/*=========================================================================== CopyLeft(CL) FORVERE Wjj All rights NOT reserved 版权所无,翻版不究,但请保留此处信息 http://blog.sina.com.cn/u/2150397142 any problem or suggestion mail to: 15258297408@163.com **************************************************************************************************************************/ *文件名:PID_control *文件说明:PID温控源代码,采用PID算法处理的温控模拟系统 ,ADC0809采集数据,IN4148为温度传感器 *版本: The final version *芯片: STC89C52RC *晶振: (外)内部12MHz晶振 *作者: Wang Jian Jun *日期: 2010年5月27日 *编译环境: keil3+proteus7 *结果: 实物测试通过,温度维持在33℃-35℃ *说明: 采用PID算法处理的温控模拟系统 ,ADC0809采集数据,IN4148为温度传感器,LCD显示 =============================================================================*/ #include<reg51.h> //加载C51核心库文件 #include<intrins.h> //加载应用型库文件 #include"config.h" //加载用户自配置可文件,此处未给出 #define N0 40536 #define nop() _nop_() #define uchar unsigned char #define uint unsigned int //以上宏定义,方便写代码 /*程序中变量 数组定义*/ uchar idata table[]={"Real-time Temp:"}; //第一行显示"Real-time Temp:" uchar idata table1[5]; uchar data1; uchar kp; uchar ki; uchar kd; //以上为PID算法的比例,积分,微分系数 uint t,hightime,count; //占空比调节参数 uint rltemp,settemp=350; int e1,e2,e3,duk,uk; /*引脚定义*/ sbit EOC=P2^6; sbit OE=P2^5; sbit START=P2^7; sbit lcden=P3^2; sbit lcdrw=P3^1; sbit lcdrs=P3^0; sbit pwm=P3^3; /****************************** 延时子程序 *******************************/ void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=29;y>0;y--); } /****************************** LCD忙检测 *******************************/ bit lcd_busy() { bit result; lcdrw = 1; lcdrs = 0; lcden = 1; nop();nop();nop();nop(); result = (bit)(P0&0x80); lcden = 0; return(result); } /****************************** LCD写命令子程序 *******************************/ void write_com(uchar com) { while(lcd_busy());//忙等待 lcdrs = 0; lcdrw = 0; P1 = com; delay(5); lcden = 1; delay(5); lcden = 0; } /****************************** LCD写数据子程序 *******************************/ void write_data(uchar date) { while(lcd_busy()); //忙等待 lcdrs = 1; lcdrw = 0; P1=date; delay(5); lcden = 1; delay(5); lcden = 0; } /****************************** LCD初始化 *******************************/ void lcd_init() { lcden = 0; write_com(0x38); delay(5); write_com(0x0f); delay(5); write_com(0x06); delay(5); write_com(0x01); delay(5); write_com(0x80); delay(5); write_com(0x01); } /****************************** 定时器初始化 *******************************/ void time_init() { EA = 1; ET0 = 1; ET1 = 1; TR0 = 1; TR1 = 1; TMOD = 0x11; TH0 = N0/256; TL0 = N0%256; TH1 = 0X3C; TL1 = 0XB0; } /****************************** PID算法系数设置 *******************************/ void Pid_init() { hightime= 0; e1 = 0; e2 = 0; e3 = 0; kp = 10; ki = 5; kd = 5; } /****************************** 温度比较 PID算法 *******************************/ void pid_ys() { if(rltemp<settemp) // 如果实际温度小于设定值 { if(settemp-rltemp>20) // 如果相差2度 { hightime=100; //全速加热 } else //否则运行PID算法进行平滑加热 { e1 = settemp-rltemp; duk=(kp*(e1-e2)+ki*e1+kd*(e1-e2*2+e3))/10; uk = uk+duk; if(uk>100) uk = 100; else if(uk<-100) uk = -100; if(uk<0) { hightime=-uk; } else { hightime=uk; } e3 = e2; e2 = e1; } } if(rltemp>=settemp) // 如果实际温度大于设定值 { if(rltemp-settemp>0) //只要实际温度与设定值有偏差 { hightime=0; //停止加热 } else //其他情况运行PID算法,但参数与前面的刚好相反 { e1 = rltemp-settemp; duk=(kp*(e1-e2)+ki*e1+kd*(e1-e2*2+e3))/10; uk = uk+duk; if(uk>100) uk = 100; else if(uk<-100) uk = -100; if(uk<0) { hightime=100-(-uk); } else { hightime=100-uk; } e3 = e2; e2 = e1; } } } /****************************** 主函数 *******************************/ void main() { uint i; time_init();//定时器初始化 Pid_init(); // PID初始化 lcd_init(); // LCD初始化 table1[5]=0x43; table1[4]=0xdf; table1[2]=0x2e; //小数点 摄氏度符号ASCII码 for(i=0;i<15;i++) //带循环第一行显示"Real-time Temp:" { write_data(table[i]); delay(20); } while(1) { t=data1*196/100; table1[3]=(t%100)%10+0x30; table1[1]=(t%100)/10+0x30; table1[0]=t/100+0x30; //以上温度数据转化 rltemp = t; //给PID算法装载实际值 write_com(0x80+0x45);//写LCD第二行的初地址 for(i=0;i<6;i++) //该循环显示温度值 { write_data(table1[i]); delay(20); } pid_ys();//运行温度比较 PID算法 } } /****************************** 温度采集转换的定时中断 0.5s刷新一次数据 *******************************/ void timer0() interrupt 1 { uint j; j++; if(j==20) { OE = 0; START = 0; _nop_(); START = 1; _nop_(); START = 0; while(EOC==0); OE = 1; _nop_(); data1 = P0; _nop_(); OE = 0; j = 0; } TH0=N0/256; TL0=N0%256; } /****************************** PWM波输出的定时中断 *******************************/ void timer1() interrupt 3 { if(++count<=(hightime)) pwm=0; else if(count<=100) { pwm=1; } else count=0; TH1=0x3c; TL1=0xb0; } /*==============================end of file=======================================*/