基于51单片机的PID控制恒温系统protues仿真,楼主之前找了很久,没找到好用的,这个是楼主花了一点小代价找到的,现在免费分享给那些需要的伙伴吧,希望能帮助到你们一点
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include"reg51.h"
- #define uchar unsigned char
- #define uint unsigned int
- #define ulong unsigned long
- /*****************引脚定义*********************************/
- //l298n
- sbit output=P2^5;
- sbit in1=P2^3;
- sbit in2=P2^4;
- /********************************/
- //AD芯片
- sbit CLOCK=P3^1;
- sbit D_IN=P2^7;
- sbit D_OUT=P2^6;
- sbit _CS=P3^0;
- /********************************/
- //lcd液晶
- sbit lcdrs=P2^0;
- sbit lcdrw=P2^1;
- sbit lcden=P2^2;
- /********************************/
- //灯
- sbit led=P3^2;
- //蜂鸣器
- sbit speaker=P3^3;
- /*****************引脚定义*********************************/
- /*****************变量定义(申明)*********************************/
- int freq=500,pwm=0;
- uchar setflag=0,pageflag=0,ok=0;
- float pwm_temp=0;
- float KP=100,KI=10,KD=0;
- uint pul_count=0;
- float ek=0,ek1=0,ek2=0;
- float keytemp=0;
- uchar code str[16]=" welcome! ";
- uchar code str1[16]=" temperature PID";
- uchar code str2[16]="set-T now-T " ;
- uchar code str3[16]="P: I: D:" ;
- uchar code str4[16]="set-P: " ;
- uchar code str5[16]="set-I: " ;
- uchar code str6[16]="set-D: " ;
- void Init(void);
- uint adcread(uchar port);
- void delay(uint n);
- void writecom(uchar com);
- void writedata(uchar date);
- void initlcd();
- float keyscan(void);
- uchar keyscans(void);
- void lcdnumdisplay(uchar pos,double f);
- void lcdnumdisplays(uchar pos,double f);
- uint read_pul();
- void mypid(float Kp,float Ki,float Kd,uint count,uint point);
- /*****************变量定义(申明)*********************************/
- void main()
- {
- uchar i;float scantemp;
- float adnum0=0;
- float adnum1=0;
- bit init0,init1,init2,init3,init4;
- Init();
- initlcd();
- writecom(0x80);
- for(i=0;i<16;i++)writedata(str[i]); //huanyin
- writecom(0x80+0x40);
- for(i=0;i<16;i++)writedata(str1[i]); //shuming
- delay(2000);
- // output=0;
- // in1=1;in2=0;
- // while(1);
- while(1)
- {
- pwm_temp=500*(float)(adnum0)/4095;
- //pwm=pwm_temp;
- mypid(KP,KI,KD,adnum1,pwm_temp);
- scantemp=keyscan();
- if(adnum1>=pwm_temp-1.5&&adnum1<=pwm_temp+1.5)
- {
- led=0;
- speaker=1;
- }
- else{
- led=1;
- speaker=0;
- }
- if(setflag==0)
- {
- adnum0=adcread(0);
- adnum1=adcread(1)/45;
- if(init0==0)
- {
- initlcd();
- writecom(0x80);
- for(i=0;i<16;i++)
- writedata(str2[i]); //shuming
- init0=1;init1=0;init2=0;init3=0;init4=0;
- }
- lcdnumdisplays(0x80+0x40,(float)pwm_temp); //pwm_temp
- lcdnumdisplays(0x80+0x4a,(float)adnum1);
- }
- if(setflag!=0&&pageflag==0)
- {
- if(init1==0)
- {
- initlcd();
- writecom(0x80);
- for(i=0;i<16;i++)writedata(str3[i]);
- init0=0;init1=1;init2=0;init3=0;init4=0;
- }
- lcdnumdisplays(0x80+0x40,KP);
- lcdnumdisplays(0x80+0x46,KI);
- lcdnumdisplays(0x80+0x4D,KD);
- }
- if(setflag!=0&&pageflag==1)
- {
- if(init2==0)
- {
- initlcd();
- writecom(0x80);
- for(i=0;i<16;i++)writedata(str4[i]);
- init0=0;init1=0;init2=1;init3=0;init4=0;
- }
- lcdnumdisplays(0x80+0x40,scantemp);
- if(ok==1){KP=scantemp;ok=0;}
- }
- if(setflag!=0&&pageflag==2)
- {
- if(init3==0)
- {
- initlcd();
- writecom(0x80);
- for(i=0;i<16;i++)writedata(str5[i]);
- init0=0;init1=0;init2=0;init3=1;init4=0;
- }
- lcdnumdisplays(0x80+0x40,scantemp);
- if(ok==1){KI=scantemp;ok=0;}
- }
- if(setflag!=0&&pageflag==3)
- {
- if(init4==0)
- {
- initlcd();
- writecom(0x80);
- for(i=0;i<16;i++)writedata(str6[i]);
- init0=0;init1=0;init2=0;init3=0;init4=1;
- }
- lcdnumdisplays(0x80+0x40,scantemp);
- if(ok==1){KD=scantemp;ok=0;}
- }
- }
- }
- void mypid(float Kp,float Ki,float Kd,uint count,uint point)
- {
- static float Uk;
- ek=point-count;
- // if(ek>=5&&ek<=-5) //积分分离
- {Uk=Kp*(ek-ek1)+Ki*ek+Kd*(ek-2*ek1+ek2);}
- // else
- // Uk=Kp*ek;
- pwm=Uk;
- //lcdnumdisplays(0x80+0x4a,(float)pwm);
- if(pwm>freq)pwm=freq;
- if(pwm<=0){pwm=0;in1=0;in2=1;}
- if(pwm>0) {in1=1;in2=0;}
- ek2=ek1;
- ek1=ek;
- }
- uint read_pul()
- {
- uint t1,th1,th2;
- uint val;
- while(1)
- {
- th1=TH1;
- t1=TL1;
- th2=TH1;
- if(th1==th2)
- break;
- }
- val=th1*256+t1;
- return val;
- }
- void delay(uint n)
- {
- uint i,j;
- for(i=n;i>0;i--)
- for(j=1;j>0;j--);
- }
- void Init(void)//初始化函数
- {
- TMOD=0x51;
- TH0=(65536-10)/256;
- TL0=(65536-10)%256;
- EA=1;
- ET0=1;
- TR0=1;
- TH1=0;
- TL1=0;
- TR1=1;
- }
- void Timer_0(void) interrupt 1
- {
- static ulong t_count=0;
- static uint num_count=0;
- TR0=0;
- TH0=(65536-10)/256;
- TL0=(65536-10)%256;
- TR0=1;
- num_count++;
- // t_count++;
- // if(t_count==2320)
- // {
- // t_count=0;
- // TR1=0;
- // pul_count=read_pul();
- // TH1=0;
- // TL1=0;
- // TR1=1;
- // }
- if(num_count>freq)num_count=0; //1khz;
- if(num_count<pwm)output=1;
- else output=0;
-
- }
- //lcd写命令
- void writecom(uchar com)
- {
- lcdrs=0;
- P0=com;
- delay(1);
- lcden=1;
- delay(1);
- lcden=0;
- }
- //lcd写数据
- void writedata(uchar date)
- //初始化lcd
- {
- lcdrs=1;
- P0=date;
- delay(1);
- lcden=1;
- delay(1);
- lcden=0;
- }
- void initlcd()
- {
- lcdrw=0;
- writecom(0x38);delay(1);
- writecom(0x0c);delay(1);
- writecom(0x06);delay(1);
- writecom(0x01);delay(5);
- }
- //adc读
- uint adcread(uchar port)
- {
- uint ad=0,i;
-
- CLOCK=0;
- _CS=0;
- port<<=4;
- for(i=0;i<12;i++)
- {
- if(D_OUT)
- ad|=0x01;
- D_IN=(bit)(port&0x80);
- CLOCK=1;
- delay(1);
- CLOCK=0;
- delay(1);
- port<<=1;
- ad<<=1;
- }
- _CS=1;
-
- ad>>=1;
- return(ad);
- }
- //lcd显示数据1
- void lcdnumdisplays(uchar pos,float f) //(0.001-99999) 精度低 但方便数据更新
- {
- uchar i;
- writecom(pos);
- if(f>65535&&f<0.001) for(i=0;i<5;i++)writedata(0x23);//超出范围 显示#
- else if(f==0){writedata(0x30);for(i=0;i<4;i++)writedata(0x20);}
- else
- {
- if((uint)f/10000!=0)
- {
- writedata((uint)f/10000+0x30);
- writedata((uint)f%10000/1000+0x30);
- writedata((uint)f%1000/100+0x30);
- writedata((uint)f%100/10+0x30);
- writedata((uint)f%10+0x30);
- }
- else
- {
- if((uint)f/1000!=0)
- {
- writedata(0+0x30);
- writedata((uint)f/1000+0x30);
- writedata((uint)f%1000/100+0x30);
- writedata((uint)f%100/10+0x30);
- writedata((uint)f%10+0x30);
- }
- else
- {
- if((uint)f/100!=0)
- {
- writedata((uint)f/100+0x30);
- writedata((uint)f%100/10+0x30);
- writedata((uint)f%10+0x30);
- writedata(0x2e);
- writedata((uint)(f*10)%10+0x30);
- }
- else
- {
- if((uint)f/10!=0)
- {
- writedata((uint)f/10+0x30);
- writedata((uint)f%10+0x30);
- writedata(0x2e);
- writedata((uint)(f*10)%10+0x30);
- writedata((uint)(f*100)%10+0x30);
- }
- else
- {
- writedata((uint)f%10+0x30);
- writedata(0x2e);
- writedata((uint)(f*10)%10+0x30);
- writedata((uint)(f*100)%10+0x30);
- writedata((uint)(f*1000)%10+0x30);
- }
- }
- }
- }
- }
- }
- //lcd显示数据2
- void lcdnumdisplay(uchar pos,float f0) //(0.00001-99999.99999) 精度高 但数据需刷屏更新
- {
- uchar temp;
- ulong f;
- writecom(pos);
- f=(ulong)f0;
- temp=f/10000; //整数部分
- if(temp!=0)
- {
- writedata(temp+0x30);
- writedata(f%10000/1000+0x30);
- writedata(f%1000/100+0x30);
- writedata(f%100/10+0x30);
- writedata(f%10+0x30);
- }
- else
- {
- temp=f%10000/1000;
- if(temp!=0)
- {
- writedata(temp+0x30);
- writedata(f%1000/100+0x30);
- writedata(f%100/10+0x30);
- writedata(f%10+0x30);
- }
- else
- {
- temp=f%1000/100;
- if(temp!=0)
- {
- writedata(temp+0x30);
- writedata(f%100/10+0x30);
- writedata(f%10+0x30);
- }
- else
- {
- temp=f%100/10;
- if(temp!=0)
- {
- writedata(temp+0x30);
- writedata(f%10+0x30);
- }
- else
- {
- temp=f%10;
- if(temp!=0)
- {
- writedata(temp+0x30);
- }
- else writedata(0+0x30);
- }
- }
- }
- }
- if((ulong)(f0*10)%10!=0||(ulong)(f0*100)%10!=0||(ulong)(f0*1000)%10!=0||(ulong)(f0*10000)%10!=0)
- {
- writedata(0x2e);
- temp=(ulong)(f0*10000)%10;
- if(temp!=0)
- {
- writedata((ulong)(f0*10)%10+0x30);
- writedata((ulong)(f0*100)%10+0x30);
- writedata((ulong)(f0*1000)%10+0x30);
- writedata(temp+0x30);
- }
- else
- {
- temp=(ulong)(f0*1000)%10;
- if(temp!=0)
- {
- writedata((ulong)(f0*10)%10+0x30);
- writedata((ulong)(f0*100)%10+0x30);
- writedata(temp+0x30);
- }
- else
- {
- temp=(ulong)(f0*100)%10;
- if(temp!=0)
- {
- writedata((ulong)(f0*10)%10+0x30);
- writedata(temp+0x30);
- }
- else
- {
- temp=(ulong)(f0*10)%10;
- if(temp!=0)
- writedata(temp+0x30);
- }
- }
- }
- }
- }
- uchar keyscans(void)//矩阵键盘扫描
- {
- uchar i, j, temp, Buffer[4] = {0xef, 0xdf, 0xbf, 0x7f};
- for(j = 0; j < 4; j++) //循环四次
- {
- P1 = Buffer[j]; //在P1高四位分别输出一个低电平
- temp = 0x01; //计划先判断P1.0位
- for(i = 0; i < 4; i++)
- {
- if(!(P1 & temp)) //从P1低四位,截取1位
- return (i + j * 4); //返回取得的按键值
- temp <<= 1; //判断的位,左移一位
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
水温控制系统PID可调51单片机仿真.zip
(100.06 KB, 下载次数: 171)
|