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;