51单片机PID调增量式光电编码器测速
- 格式:doc
- 大小:56.00 KB
- 文档页数:15
编码器输出的A向脉冲接到单片机的外部中断INT0,B向脉冲接到I/O端口P1.0。当系统工作时,首先要把INT0设置成下降沿触发,并开相应中断。当有有效脉冲触发中断时,进行中断处理程序,判别B脉冲是高电平还是低电平,若是高电平则编码器正转,加1计数;
若是低电平则编码器反转,减1计数。
基于51单片机的直流电机PID闭环调速系统原理详解与程序
(2013-08-04 01:18:15)
转载▼
标签:
51单片机
直流电机
pid
pcf8591 分类:单片机
基于51单片机的直流电机PID闭环调速系统
1.电机转速反馈:
原理:利用光电编码器作为转速的反馈元件,设电机转一周光电编码器发送N个PWM波形,利用测周法测量电机转速。
具体实现:将定时器0设置在计数模式,用来统计一定的时间T内接受到的脉冲个数M个,而定时器0置在计时模式,用来计时T时间。则如果T时间接受到M个PWM波形,而电机转一圈发出N个PWM波形,则根据测周法原理,电机的实际的转速为:real_speed=M/(N*T),单位转/秒。若将定时器1置在计数模式,则PWM波形应该由P3^3脚输入。
代码实现:
//定时器0初始化,用来定时10ms void Init_Timer0(void)
{
TMOD |= 0x01; //使用模式1,16位定时器 ,且工作在计时模式
TH0=(65536-10000)/256; //定时10ms
TL0=(65536-10000)%6;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
// 计数器1初始化,用来统计定时器1计时250ms内PWM波形个数
void Init_Timer1(void)
{
TMOD |= 0x50; //使用计数模式1,16位计数器模式
TH1=0x00; //给定初值,由0往上计数
TL1=0x00;
EA=1; //总中断打开
ET1=1; //定时器中断打开
TR1=1; //定时器开关打开
}
//定时器0的中断服务子函数,主要完成脉冲个数的读取,实际转速的计算和PID控制以及控制结
//果输出等工作
void Timer0_isr(void) interrupt 1
{
unsigned char count;
TH0=(65536-10000)/256; //重新赋值 10ms
TL0=(65536-10000)%6;
count++;
if (count==25) //如果达到250ms,则计算一次转速并进行一次控制运算
{
count=0;//清零以便于定时下一个250ms
TR1=0;//关闭定时器1,统计脉冲个数
real_speed=(256*TH1+TL1)*4/N;//250ms内脉冲个数并由此计算转速
TH1=0x00; //计数器1清零,重新开始计数
TL1=0x00;
TR1=1;
OUT=contr_PID();//进入PID控制 ,PID控制子函数代码在后面给出
write_add(0x40,OUT);//进行DA转换,将数字量转换为模拟量,后面会介绍到
}
}
2.PID控制:
PID的基本原理在这里不作具体讲解,这里主要给出PID算法的实现,通过调节结构体中比例常数(Proportion)、积分常数(Integral)、微分常数( Derivative)使得转速控制达到想要的精度。
试凑法:注意这里参数调节采用实验凑试法,试凑法也有其规律,下面做出讲解:
实验凑试法是通过闭环运行或模拟,观察系统的输出结果,然后根据各参数对系统的影响,反复凑试参数,直至出现满意的响应,从而确定PID控制参数。
实验凑试法的整定步骤为"先比例,再积分,最后微分"。
(1)整定比例控制
将比例控制作用由小变到大,观察各次响应,直至得到反应快、超调小的响应曲线。 (2)整定积分环节
若在比例控制下稳态误差不能满足要求,需加入积分控制。
先将步骤(1)中选择的比例系数减小为原来的50~80%,再将积分时间置一个较大值,观测响应曲线。然后减小积分时间,加大积分作用,并相应调整比例系数,反复试凑至得到较满意的响应,确定比例和积分的参数。
(3)整定微分环节
若经过步骤(2),PI控制只能消除稳态误差,而动态过程不能令人满意,则应加入微分控制,构成PID控制。
先置微分时间TD=0,逐渐加大TD,同时相应地改变比例系数和积分时间,反复试凑至获得满意的控制效果和PID控制参数。
代码实现
unsigned int Proportion=8;//比例常数 Proportional Const
unsigned int Integral=3;//积分常数 Integral Const
unsigned int Derivative=1;//微分常数 Derivative Const
unsigned int LastError=0;//Error[-1]
unsigned int PrevError=0;//Error[-2]
unsigned int Error=0;//Error[0]
int Out=0;//outcome
int contr_PID()
{
Error=expc_speed-real_speed;//计算偏差
//进行增量式PID计算
Out=Out+
Proportion*(Error-LastError)+
Integral*Error+
Derivative*(Error+PrevError-2*LastError);
//进行误差更新 PrevError=LastError;
LastError=Error;
//上下限幅处理
if(Out<0)
Out=0;//驱动电机的电压不可能小于零,故当输出小于零时,输出应该值为零
if(Out>255)
Out=255;//DA转换为8位,最大数值为255,故当大于255时,限制为255
return Out;
}
3.电机驱动:
原理:直流有刷电机既可以用模拟电压驱动,又可以用PWM驱动.如果用PWM驱动时,刚刚PID后的输出可以直接对应到PWM高电平持续的时间,PWM周期为T,则低电平对应为T-Out即可,这个实现比较简单。这里介绍利用DA将数字量Out转化为模拟电压驱动电机的方法。
模拟电压驱动实现:将数字量转化为模拟量的最常用方法就是使用DA转换。在一般的使用中我比较喜欢的一款芯片是PCF8591。它内部集成了4路8位AD转换和1路8位DA转换,与单片机之间使用IIC通信方式。由于IIC通信只需要SDA和SCL两根信号线,因此很省IO口,并且一个芯片AD,DA都有了,很方便。具体的PCF8591资料请参考其datasheet,这里直接给出其封装好的IIC通信代码,使用直接就可以了。这里面其他的函数不用管,因为它们最终在两个函数中被调用,即write_add()和read_add()中。前者实现DA转换,有两个参数,第一个参数是控制DA转换对应寄存器地址,取0x40,第二个是要转换的数据,即返回的OUT,使用时直接一句代码:write_add(0x40,OUT)就能将数字信号转换为模拟电压信号。后者实现AD转换,只有一个参数,就是选择AD转换的4个通道,通过宏定义可以定义出其四个通道: #define AD_IN0 0x40
#define AD_IN1 0x41
#define AD_IN2 0x42
#define AD_IN3 0x43
使用时只需要一句代码:dat=read_add(AD_IN2)就能实现将第二个通道的模拟信号转换为数字信号。
代码实现:
//PCF8591.h
#define uchar unsigned char
//延时4us
void delay(void);
//iic初始化
void init(void);
// iic开始信号
void start(void) ;
// iic停止信号
void stop(void) ;
// iic应答 相当于一个智能的延时函数
void respons(void) ;
// iic读一个字节数据
uchar read_byte(void) ;
//iic写一字节数据
void write_byte(uchar date) ;
// 控制DA转换
void write_add(uchar control,uchar date);
// 控制AD转换
uchar read_add(uchar control) ;
//PCF8591.c
#include #include
#define PCF8591 0x90 //默认为写,如果为读,则为0x91
sbit SDA=P2^0;
sbit SCL=P2^1;
//延时4us
void delay(void)
{
unsigned char i;
for(i=1;i>0;i--);
}
// iic初始化
void init()
{
SDA=1;
delay();
SCL=1;
delay();
}
// iic开始信号
void start()
{
SDA=1;