51单片机PID控制直流电机实验报告
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
} }
(3)、按键扫描: #include <reg51.h> sbit jiashi=P1^3; sbit jianshi=P1^4; sbit jia=P1^5; sbit jian=P1^6; sbit enter=P1^7; extern int num_key[5]; void keyscan() { if(jiashi==0) { while(!jiashi); num_key[0]++; } if(jianshi==0) { while(!jianshi); num_key[1]++; } if(jia==0) { while(!jia); num_key[2]++; } if(jian==0) { while(!jian); num_key[3]++; } if(enter==0) {
//存储当前误差以便后面计算 sptr->PrevError = sptr->LastError; sptr->LastError = iError; //返回增量值 return(iIncpid); }
(7)、main 函数: #include <reg51.h> #include <intrins.h> #include <key.h> #include <delay.h> #include <display.h> #include <PWM.h> #include <PID.h> sbit P10=P1^2; //确定电机转向 int num_key[5]; int PWM,PWM1,count,count1,dir,sudu_lilun,start,count20ms_flag; double dis_count; int PWM_PID; void init(); void main() { init(); while(1) { PWM_duty(); if(P10==1) dir=0; else dir=1; keyscan(); sudu_lilun=num_key[0]*10-num_key[1]*10+num_key[2]-num_key[3]; display_lilun(sudu_lilun); if(num_key[4]==1) start=1; display(dis_count,dir); if(start>=1&&count20ms_flag==1) { count20ms_flag=0; IncPIDInit(); PWM_PID=IncPIDCalc(dis_count);
iError = sptr->SetPoint - NextPoint; //计算增加量
iIncpid = sptr->Proportion * iError //E[k]项
- sptr->Integral * sptr->LastError //E[k-1]项
+ sptr->Derivative * sptr->PrevError; //E[k-2]项
#include <delay.h> void delayms(unsigned char x) {
unsigned char i ; while(x--)
for(i = 0 ; i < 120 ; i++) ; } (2)、数码管显示: #include <reg51.h> #include <display.h> #include <delay.h> void display_lilun(double num) {
long int i;
TRห้องสมุดไป่ตู้=0 ;
dir=0;
TL0=0x00;
TH0=0xd8; //10ms
TL0=0xf0;
TH1=PWM ;
TR1=1 ;
PWM_OUT1=0 ;
//启动输出
PWM_OUT2=0;
if(i++==492)
{
count20ms_flag=1;
i=0;
dis_count=(double)(count+count1)/2;
}
}
while(S3==0);
do
{
if(PWM>=0x02)
{
PWM-- ;
delayms(10);
}
}
while(S2==0);
}
(5)、中断服务程序: #include <reg51.h> extern int PWM,count,count1,dir,count20ms_flag; extern double dis_count; sbit PWM_OUT1=P1^1; sbit PWM_OUT2=P1^0; void timer0() interrupt 1 {
百位加小数点
P0 = 0; P2 =0xfd; P0 = table[n % 100 / 10]+128; delayms(2);//
十位
P0 = 0; P2 =0xfe; P0 = table[n % 10];
delayms(2);//个位
P0 = 0; if(dir==1)
//关闭显示器
{ P0=0;P2=0xef;P0=0x40;delayms(2);
{
EX0=0;
count++;
EX0=1;
}
void EIRQ1(void) interrupt 2
{
EX1=0;
count1++;
EX1=1;
}
(6)、PID 控制:
#include <PID.h>
#include <PWM.h>
int P,I,D;
extern int sudu_lilun;
typedef struct PID //定义结构体
3、直流电机。在 protues 中选择 motor-encoder 直流电机,引脚图如下: 上方左右的两个引脚在点击运转时输出频
率相同的方波,但是在相位上相差 90 ,而且 在正转和反转是相反,因此可以根据这两个引 脚的输出情况判断点击的转向。上方中间的引 脚每当电机转一圈就输出一个正脉冲,可以据 此册数点击的转速。左右两个引脚是电机的电 压输入端。 4、74HC74。当 D 触发器的 D 和 CLK 输入端分别接电机上方的左右两个输出端口 时可以根据 D 触发器的输出情况判断点击的转速。 5、八位数码管。用以显示。
extern double dis_count;
sbit S2 =P3^6 ;
//PWM 值减少键
sbit S3 =P3^7 ;
//PWM 值增加键
void PWM_duty()
{
if(start>=1)
PWM=sudu_lilun;
do
{
if(PWM!=0xff)
{
PWM++ ;
delayms(10);
char code table[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, //0~7 对应数码 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; //8~F 对应数码 long int n=num; P0 = 0; P2 =0x7f; P0 = table[n % 1000/100]; delayms(2);//百位 加小数点 P0 = 0; P2 =0xbf; P0 = table[n % 100 / 10]; delayms(2);//十位
static PID *sptr = &sPID;
void IncPIDInit()
{
sptr->SumError = 0;
sptr->LastError =0; //Error[-1]
sptr->PrevError =0; //Error[-2]
sptr->Proportion =0.5; //比例系数
P0 = 0; P2 =0xdf; P0 = table[n % 10];
delayms(2);//个位
P0 = 0; }
//关闭显示器
void display(double num,int dir)
{
char code table[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, //0~7 对应数码
二、系统硬件设计连接
1、系统的器件连接图如下:
2、单片机与数码管通过 P0 口和 P2 口相连,其中 P2 口选择点亮哪一个数码管, P0 口则控制被点亮的数码管显示的数据。
3、单片通过 P1^0 和 P1^1 和 L298 的第一对输入端 IN1 和 IN2 相连,然后又 L298 的第一对输出端 OUT1 和 OUT2 与直流电机相连,已达到控制直流电机的目的。 4、从 P1^4 到 P1^7 分别接一个 Button 按钮来实现 PID 控制,P3^6 和 P3^7 分别 接 Button 按钮实现对电机的加速与减速控制。 5、双刀双掷开关 SW1 课实现点击的正转与反转,单刀双掷开关 SW2 可实现点击 的开启与停止。
sptr->Integral =0.3; //积分系数
sptr->Derivative = 0.3; //微分系数
sptr->SetPoint =sudu_lilun;
}
int IncPIDCalc(int NextPoint)
{
register int iError, iIncpid; //当前的误差值
(2)、AT89C51 引脚图如下:
2、电机驱动芯片 (1)、电机驱动芯片选择 L298。其主要功能是作为单片机与直流电机中间的
过度链接,单片机输出的信号通过 L298 加载到直流电机上驱动直流电机运行。 其引脚图如下:
(2)、主要工作原理: 1、15 脚分别是两个 H 桥的电流反馈脚,不用时可以直接接地; 2、3 为一对输出端口,13、14 为一对输出端口; 4 为驱动电压输入,最小值必须比输入的低电平高 2; 5、7 一对输入端口,10、12 一对输入端口,TTL 电平兼容 6、11 使能端,低电平禁止输出; 8、9 分别为接地和逻辑电源
count=0;
count1=0;
}
}
void timer1() interrupt 3
{
TR1=0 ;
if(dir==0)
{
PWM_OUT1=1 ; //结束输出
PWM_OUT2=0;
}
else
{
PWM_OUT1=0;
PWM_OUT2=1;
}
}
void EIRQ0(void) interrupt 0
//对各个按钮进行位定义 //定义全局变量
while(!enter);
num_key[4]++;
}
}
(4)、PWM 波输出:
#include <reg51.h>
#include <delay.h>
#include <PWM.h>
extern int PWM ;
//赋初值
extern int start,sudu_lilun;
{
int SetPoint;
//目标
long SumError;
//误差
double Proportion; //比例系数
double Integral; //积分系数
double Derivative; //微分系数
int LastError;
int PrevError;
}PID;
static PID sPID;
三、 系统程序设计及功能实现
1、程序流程图:
开始
输入一个值,点击 Enter 按 钮,通过 PID 算法,改变 PWM 波输出让电机运行
通过按钮加减 改变当前值, Enter 键确定
循环
判断新的输入值与当前值的 差值,将差值加到原值上, 通过 PID 算法改变 PWM 波
输出控制电机运行
2、各部分实现程序: (1)、普通延时:
0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; //8~F 对应数码
long int n=num*10;
P0 = 0; P2 =0xf7; P0 = table[n / 1000]; delayms(2); //百位加
小数点
P0 = 0; P2 =0xfb; P0 = table[n % 1000/100]; delayms(2); //
基于 51 单片机的 直流电机 PID 控制
一、 试验器件选择
1、控制芯片的作用主要是与 L289 相连接驱动直流电机,以及与八位数码管相连 显示。 (1)、AT89C51 是一种带 4K 自己 FLASH 存储器的低压、高性能 CMOS8 为微处
理器。单片机的可擦除只读存储器可以反复擦除 1000 次。该器件采用 ATMEL 高 密度非易失真存储制造技术制造,与工业标准的 MCS-51 指令集和输出关键相兼 容。由于将多功能 8 位 CPU 和闪存组合在单个芯片中,ATMEL 的 AT89C51 是一种 高效微控制器。AT89C51 单片机为很多嵌入式控制系统提供了一种灵活性奥高且 廉价的方案。
(3)、按键扫描: #include <reg51.h> sbit jiashi=P1^3; sbit jianshi=P1^4; sbit jia=P1^5; sbit jian=P1^6; sbit enter=P1^7; extern int num_key[5]; void keyscan() { if(jiashi==0) { while(!jiashi); num_key[0]++; } if(jianshi==0) { while(!jianshi); num_key[1]++; } if(jia==0) { while(!jia); num_key[2]++; } if(jian==0) { while(!jian); num_key[3]++; } if(enter==0) {
//存储当前误差以便后面计算 sptr->PrevError = sptr->LastError; sptr->LastError = iError; //返回增量值 return(iIncpid); }
(7)、main 函数: #include <reg51.h> #include <intrins.h> #include <key.h> #include <delay.h> #include <display.h> #include <PWM.h> #include <PID.h> sbit P10=P1^2; //确定电机转向 int num_key[5]; int PWM,PWM1,count,count1,dir,sudu_lilun,start,count20ms_flag; double dis_count; int PWM_PID; void init(); void main() { init(); while(1) { PWM_duty(); if(P10==1) dir=0; else dir=1; keyscan(); sudu_lilun=num_key[0]*10-num_key[1]*10+num_key[2]-num_key[3]; display_lilun(sudu_lilun); if(num_key[4]==1) start=1; display(dis_count,dir); if(start>=1&&count20ms_flag==1) { count20ms_flag=0; IncPIDInit(); PWM_PID=IncPIDCalc(dis_count);
iError = sptr->SetPoint - NextPoint; //计算增加量
iIncpid = sptr->Proportion * iError //E[k]项
- sptr->Integral * sptr->LastError //E[k-1]项
+ sptr->Derivative * sptr->PrevError; //E[k-2]项
#include <delay.h> void delayms(unsigned char x) {
unsigned char i ; while(x--)
for(i = 0 ; i < 120 ; i++) ; } (2)、数码管显示: #include <reg51.h> #include <display.h> #include <delay.h> void display_lilun(double num) {
long int i;
TRห้องสมุดไป่ตู้=0 ;
dir=0;
TL0=0x00;
TH0=0xd8; //10ms
TL0=0xf0;
TH1=PWM ;
TR1=1 ;
PWM_OUT1=0 ;
//启动输出
PWM_OUT2=0;
if(i++==492)
{
count20ms_flag=1;
i=0;
dis_count=(double)(count+count1)/2;
}
}
while(S3==0);
do
{
if(PWM>=0x02)
{
PWM-- ;
delayms(10);
}
}
while(S2==0);
}
(5)、中断服务程序: #include <reg51.h> extern int PWM,count,count1,dir,count20ms_flag; extern double dis_count; sbit PWM_OUT1=P1^1; sbit PWM_OUT2=P1^0; void timer0() interrupt 1 {
百位加小数点
P0 = 0; P2 =0xfd; P0 = table[n % 100 / 10]+128; delayms(2);//
十位
P0 = 0; P2 =0xfe; P0 = table[n % 10];
delayms(2);//个位
P0 = 0; if(dir==1)
//关闭显示器
{ P0=0;P2=0xef;P0=0x40;delayms(2);
{
EX0=0;
count++;
EX0=1;
}
void EIRQ1(void) interrupt 2
{
EX1=0;
count1++;
EX1=1;
}
(6)、PID 控制:
#include <PID.h>
#include <PWM.h>
int P,I,D;
extern int sudu_lilun;
typedef struct PID //定义结构体
3、直流电机。在 protues 中选择 motor-encoder 直流电机,引脚图如下: 上方左右的两个引脚在点击运转时输出频
率相同的方波,但是在相位上相差 90 ,而且 在正转和反转是相反,因此可以根据这两个引 脚的输出情况判断点击的转向。上方中间的引 脚每当电机转一圈就输出一个正脉冲,可以据 此册数点击的转速。左右两个引脚是电机的电 压输入端。 4、74HC74。当 D 触发器的 D 和 CLK 输入端分别接电机上方的左右两个输出端口 时可以根据 D 触发器的输出情况判断点击的转速。 5、八位数码管。用以显示。
extern double dis_count;
sbit S2 =P3^6 ;
//PWM 值减少键
sbit S3 =P3^7 ;
//PWM 值增加键
void PWM_duty()
{
if(start>=1)
PWM=sudu_lilun;
do
{
if(PWM!=0xff)
{
PWM++ ;
delayms(10);
char code table[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, //0~7 对应数码 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; //8~F 对应数码 long int n=num; P0 = 0; P2 =0x7f; P0 = table[n % 1000/100]; delayms(2);//百位 加小数点 P0 = 0; P2 =0xbf; P0 = table[n % 100 / 10]; delayms(2);//十位
static PID *sptr = &sPID;
void IncPIDInit()
{
sptr->SumError = 0;
sptr->LastError =0; //Error[-1]
sptr->PrevError =0; //Error[-2]
sptr->Proportion =0.5; //比例系数
P0 = 0; P2 =0xdf; P0 = table[n % 10];
delayms(2);//个位
P0 = 0; }
//关闭显示器
void display(double num,int dir)
{
char code table[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, //0~7 对应数码
二、系统硬件设计连接
1、系统的器件连接图如下:
2、单片机与数码管通过 P0 口和 P2 口相连,其中 P2 口选择点亮哪一个数码管, P0 口则控制被点亮的数码管显示的数据。
3、单片通过 P1^0 和 P1^1 和 L298 的第一对输入端 IN1 和 IN2 相连,然后又 L298 的第一对输出端 OUT1 和 OUT2 与直流电机相连,已达到控制直流电机的目的。 4、从 P1^4 到 P1^7 分别接一个 Button 按钮来实现 PID 控制,P3^6 和 P3^7 分别 接 Button 按钮实现对电机的加速与减速控制。 5、双刀双掷开关 SW1 课实现点击的正转与反转,单刀双掷开关 SW2 可实现点击 的开启与停止。
sptr->Integral =0.3; //积分系数
sptr->Derivative = 0.3; //微分系数
sptr->SetPoint =sudu_lilun;
}
int IncPIDCalc(int NextPoint)
{
register int iError, iIncpid; //当前的误差值
(2)、AT89C51 引脚图如下:
2、电机驱动芯片 (1)、电机驱动芯片选择 L298。其主要功能是作为单片机与直流电机中间的
过度链接,单片机输出的信号通过 L298 加载到直流电机上驱动直流电机运行。 其引脚图如下:
(2)、主要工作原理: 1、15 脚分别是两个 H 桥的电流反馈脚,不用时可以直接接地; 2、3 为一对输出端口,13、14 为一对输出端口; 4 为驱动电压输入,最小值必须比输入的低电平高 2; 5、7 一对输入端口,10、12 一对输入端口,TTL 电平兼容 6、11 使能端,低电平禁止输出; 8、9 分别为接地和逻辑电源
count=0;
count1=0;
}
}
void timer1() interrupt 3
{
TR1=0 ;
if(dir==0)
{
PWM_OUT1=1 ; //结束输出
PWM_OUT2=0;
}
else
{
PWM_OUT1=0;
PWM_OUT2=1;
}
}
void EIRQ0(void) interrupt 0
//对各个按钮进行位定义 //定义全局变量
while(!enter);
num_key[4]++;
}
}
(4)、PWM 波输出:
#include <reg51.h>
#include <delay.h>
#include <PWM.h>
extern int PWM ;
//赋初值
extern int start,sudu_lilun;
{
int SetPoint;
//目标
long SumError;
//误差
double Proportion; //比例系数
double Integral; //积分系数
double Derivative; //微分系数
int LastError;
int PrevError;
}PID;
static PID sPID;
三、 系统程序设计及功能实现
1、程序流程图:
开始
输入一个值,点击 Enter 按 钮,通过 PID 算法,改变 PWM 波输出让电机运行
通过按钮加减 改变当前值, Enter 键确定
循环
判断新的输入值与当前值的 差值,将差值加到原值上, 通过 PID 算法改变 PWM 波
输出控制电机运行
2、各部分实现程序: (1)、普通延时:
0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; //8~F 对应数码
long int n=num*10;
P0 = 0; P2 =0xf7; P0 = table[n / 1000]; delayms(2); //百位加
小数点
P0 = 0; P2 =0xfb; P0 = table[n % 1000/100]; delayms(2); //
基于 51 单片机的 直流电机 PID 控制
一、 试验器件选择
1、控制芯片的作用主要是与 L289 相连接驱动直流电机,以及与八位数码管相连 显示。 (1)、AT89C51 是一种带 4K 自己 FLASH 存储器的低压、高性能 CMOS8 为微处
理器。单片机的可擦除只读存储器可以反复擦除 1000 次。该器件采用 ATMEL 高 密度非易失真存储制造技术制造,与工业标准的 MCS-51 指令集和输出关键相兼 容。由于将多功能 8 位 CPU 和闪存组合在单个芯片中,ATMEL 的 AT89C51 是一种 高效微控制器。AT89C51 单片机为很多嵌入式控制系统提供了一种灵活性奥高且 廉价的方案。