六、设计心得
为时两周时间的课程设计,不但让我对计算机控制技术有了更深的理解,而且熟悉了数字PID的编程办法,在做的过程中遇到的问题很多。比如一开始选PID参数整定办法时我们是用了扩充临界比例度法,但是在调试过程始终达不到理想效果,后来发现是我们采样周期太大的问题,远大于系统纯滞后时间,但是我们改变采样周期后,显示和采样效果均不理想,为此我们决定采用凑试法整定PID参数,在调试过程中,发现效果很明显,先只采用比例环节,待达到理想效果之后保持Kp值不变,继续加入积分环节,但是问题出现了,加入积分环节不但不能消除静差,反而使系统发生了较大超调和长时间的波动,为此我们查找了相关书籍,得出的结论是在一般的PID控制中,当有较大的扰动或大幅度改变给定值是,由于此时有较大的偏差,以及系统有惯性和滞后,故在积分项的作用下,往往会产生较大的超调和长时间的波动。为此我们采用了积分分离的办法,但达到设定误差时才启用积分环节,调试之后效果非常理想。接着再加入微分环节,此环节比较顺利,安照书上办法把Td值从小变到大从而找到合适值,从而使系统在期望值改变的时候不会出现超调或者波动,能实现平缓过渡。至此我们成功设计了直流电机调速系统,对学到知识感动非常开心与满足。
七、参考文献
[1] 于海生. 计算机控制技术. 北京:机械工业出版社
[2] 郭天祥. 新概念51单片机C语言教程. 电子工业出版社 [3] 凑试法整定PID参数. 百度文库
[4] ULN2003A数据手册[DB/OL]. http://www.docin.com/p-33818289.html.
16
八、附录(源程序)
#include
//LCD//
sbit RS=P2^6; sbit RW=P2^5; sbit EN=P2^7;
sbit key=P2^0; sbit key1=P2^1; sbit key2=P2^2; sbit key3=P2^3;
//motor//
unsigned int tt0; unsigned int tt1; sbit A1=P1^2; sbit A2=P1^3;
unsigned char flag; //抽样时间 unsigned int speed=41; unsigned int a;
unsigned char receive;
unsigned int ReData,sum=0,summ=0; //pid
float Kp,Ki,Kd,Ti,Td,T; //
unsigned int set=100; int en,en1,en2,enx; double Un;
void delay(unsigned int xms) {
unsigned i, j;
for(i = xms; i >0; i--)
17
for(j = 110; j >0; j--); }
bit test_busy() { bit result; P0=0xff; RS=0; RW=1; delay(1); EN=1; delay(1); result=(bit)(P0&0x80); EN=0; return result; }
void write_command(unsigned char command) { while(test_busy()); RS=0; RW=0; P0=command; delay(1); EN=1; delay(1); EN=0; }
void write_date(unsigned char date) { while(test_busy()); RS=1; RW=0; P0=date; delay(1); EN=1; delay(1); EN=0; }
void write_string(unsigned char *s)
//写命令//写数据18
{ while (*s) {
write_date(*s); s++; } }
void lcd_initial() //LCD初始化 { RS=1; RW=1; EN=0; write_command(0x38); //设置16X2显示,5X7点阵,8位数据接口 delay(1); write_command(0x01); //显示清零,数据指针清零 delay(1); write_command(0x0c); //设置开显示,不显示光标 delay(1); write_command(0x06); //写一个字符后地址指针加1 }
void keyscan() { if(key==0) { delay(10); if(key==0) { set=set+1; if(set>=138)set=138; while(!key); receive=1; } } if(key1==0) { delay(10); if(key1==0) { set=set-1;
19
if(set<=90)set=90; while(!key1); receive=1; } } }
void keyspeed() { if(key2==0) { delay(10); if(key2==0) { speed=speed+1; while(!key2); } } if(key3==0) { delay(10); if(key3==0) { speed=speed-1; while(!key3); } } }
void init() { TMOD=0x23; SCON=0x50; PCON|=0x80; T2CON=0x02; TH0=(256-100); TL0=(256-250); TH1=243; TL1=243;
//0010_0011 定时器0:模式3 定时器1:模式2 //0101_0000 串行口方式1 10位UART 波特率可变 //SMOD=1 串行口波特率加倍 //计数器2 仅当定时器溢出时捕获和重装 //驱动电机 //定时0.00025s //256-2^1*11.0592/(384*9600) 波特率为9600 20