单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 147|回复: 1
打印 上一主题 下一主题
收起左侧

改良基于51单片机pid算法水温控制系统程序+Proteus仿真

[复制链接]
跳转到指定楼层
楼主
实现了升温,降温控制,用了pid算法


单片机源程序如下:
  1. #include <REG51.H>
  2. #define Kp 18        //比例系数 18
  3. #define Ki 13 //积分系数  13
  4. #define Kd 0.8        //微分系数 0.3

  5. unsigned char m,n,p;                          //温度的十位 个位 小数
  6. unsigned char test_temp;                //温度检定标志
  7. unsigned char key_set_flag;                //按键设定进入标志
  8. unsigned char flag=1;                        //按键保持标志
  9. unsigned char Change_step=1;        //温度设置步进
  10. unsigned char T0_H = 0,T0_L = 0,T1_H=0,T1_L=0,T0h=0,T0l=0;
  11. unsigned char t0=0,t1=0;

  12. int Real_temp;                //实际温度值
  13. int Set_temp;                //设置温度
  14. int Disp_temp;                //显示温度
  15. int last_error;                //上次误差
  16. float I_term;                //前面温差和
  17. bit        key_hold;
  18. int PID_MAX;
  19. unsigned int out,PWMT,counter,kk,outp;
  20. int time;        //脉冲触发时刻

  21. sbit DQ=P1^0;        //定义DS18b20的管脚        1.0
  22. sbit L1=P2^0;        //定义控制数码管的管脚
  23. sbit L2=P2^2;
  24. sbit L3=P2^4;
  25. sbit L4=P2^6;
  26. sbit k1=P3^3;
  27. sbit k2=P3^4;
  28. sbit k3=P3^5;
  29. sbit PWM=P2^7;        //PWM控制脚
  30. //sbit jia=P2^5;

  31. unsigned char table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x7F,0xbF,0xC6};//0-9数字,后面为". - C"

  32. /*****延时子程序*****/
  33. void delay(unsigned int t)
  34. {
  35.         for(;t>0;t--);
  36. }
  37. void delay_50us(unsigned int t)
  38. {
  39.         unsigned char j;
  40.         for(;t>0;t--)
  41.                 for(j=19;j>0;j--);
  42. }

  43. /*****初始化DS18B20*****/
  44. unsigned char Init_DS18B20(void)
  45. {
  46.   unsigned char x=0;
  47.   DQ = 1;      //DQ复位
  48.   delay(8);    //稍做延时
  49.   DQ = 0;      //单片机将DQ拉低
  50.   delay(80);   //精确延时,大于480us
  51.   DQ = 1;      //拉高总线
  52.   delay(8);
  53.   x = DQ;      //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
  54.   delay(4);
  55.   return x;
  56. }

  57. /*****读一个字节*****/
  58. unsigned char ReadOneChar(void)
  59. {
  60.   unsigned char i=0;
  61.   unsigned char dat = 0;
  62.   for (i=8;i>0;i--)
  63.   {
  64.     DQ = 0;     // 给脉冲信号
  65.     dat>>=1;
  66.     DQ = 1;     // 给脉冲信号
  67.     if(DQ)
  68.             dat|=0x80;
  69.         delay(4);
  70.   }
  71.   return(dat);
  72. }

  73. /*****写一个字节*****/
  74. void WriteOneChar(unsigned char dat)
  75. {
  76.   unsigned char i=0;
  77.   for (i=8; i>0; i--)
  78.   {
  79.     DQ = 0;
  80.     DQ = dat&0x01;
  81.         delay(4);
  82.     DQ = 1;
  83.     dat>>=1;
  84.   }
  85.   delay(4);
  86. }

  87. /*****读取温度*****/
  88. int ReadTemperature(void)
  89. {
  90.           unsigned char a=0;
  91.           unsigned char b=0;
  92.           unsigned int t=0;
  93.           t=Init_DS18B20();
  94.           if(t) return Real_temp;
  95.           WriteOneChar(0xCC);  //跳过读序号列号的操作
  96.           WriteOneChar(0x44);  //启动温度转换
  97.           t=Init_DS18B20();
  98.           if(t) return Real_temp;
  99.           WriteOneChar(0xCC);  //跳过读序号列号的操作
  100.           WriteOneChar(0xBE);  //读取温度寄存器
  101.           a=ReadOneChar();     //读低8位
  102.           b=ReadOneChar();     //读高8位
  103.           t=b;
  104.           t<<=8;
  105.           t=t|a;
  106.           if(t<=0||t>0x900)
  107.         return Real_temp;
  108.         t=t*0.625+0.5;
  109.           return(t);
  110. }


  111. void display(signed int dd)//数码管扫描函数
  112. {
  113.     int tt=0;   

  114.     tt= dd; //放大10倍输出并四舍五入
  115.         m=tt/100;                //分离出十位
  116.         n=(tt%100)/10;        //分离出个位
  117.         p=tt%10;                //分离出小数位
  118.                                                                                           //m
  119.         P0=table[12];
  120.         L1=0;                        //暂未1,如用三极管驱动要改为0                 L1
  121.         delay(300);
  122.         L1=1;                        //后关闭显示

  123.         P0=table[n];                           //n
  124.         L3=0;                                                                                //L2
  125.         delay(300);
  126.         L3=1;
  127.         P0=table[10];                          //10
  128.         L3=0;                                                                                  //L2
  129.         delay(300);
  130.         L3=1;

  131.         P0=table[p];        //小数部分p
  132.         L2=0;                                                                                        //L3
  133.         delay(300);
  134.         L2=1;

  135.         P0=table[m];                         //12
  136.         L4=0;
  137.         delay(300);
  138.         L4=1;
  139. }

  140. void key_set(void)
  141. {
  142.         if(k1==0)
  143.         {
  144.                 delay(10);
  145.                 while(!k1);
  146.                 key_hold=~key_hold;
  147.         }
  148.         if(key_hold==0)
  149.         {
  150.             if(k2==0)
  151.                 {
  152.                         delay(10);
  153.                     while(!k2);
  154.                         Set_temp=Set_temp+1;
  155.                         if(Set_temp>99)
  156.                         Set_temp=99;
  157.                 }
  158.         }
  159.         if(key_hold==0)
  160.         {
  161.             if(k3==0)
  162.                 {
  163.                         delay(10);
  164.                         while(!k3);
  165.                         Set_temp=Set_temp-1;
  166.                         if(Set_temp<1)
  167.                         Set_temp=1;
  168.                 }
  169.         }
  170. }

  171. int PID(int Set_value,int Real_value) //标准PID温度控制算法
  172. {
  173.         float uk ,uk1 ,duk;
  174.         int pid_out,e ,e1 ,e2;
  175.         e=Set_value-Real_value;//误差量
  176.         duk=Kp*(e-e1)+Ki*e+Kd*(e-2*e1+e2);  //+Kd*(e-2e1+e2)
  177.         uk=uk1+duk;
  178.         pid_out=(int)uk;
  179.         uk1=uk;
  180.         e2=e1;
  181.         e1=e;
  182.         if(pid_out>1000) //1000
  183.         {
  184.                 pid_out=990;//        990
  185.         }
  186.         else if(pid_out<10)         //10
  187.         {
  188.                 pid_out=10;                //10
  189.         }
  190.         outp=pid_out;

  191.         return(pid_out);
  192.                
  193. }


  194. void T0_int(void) interrupt 1
  195. {
  196.         T0_H = (65535-2000)/256;                                //PWM=1高位初值计算
  197.         T0_L = (65535-2000)%256;                                          //PWM=1低位初值计算

  198.         TH0 = T0_H;                                 //通的初值高位
  199.         TL0= T0_L;                                 //通的初值低位


  200.         kk++;
  201.         if(kk>1000)
  202.         kk=0;
  203.         if(kk>outp)
  204.         {PWM=1;
  205.         // jia=1;
  206.           }
  207.         else {PWM=0;
  208.              //jia=0;
  209.         }
  210.        
  211.          
  212. }
  213.                  
  214. void main()
  215. {       
  216.         PWMT=128;                        //128级步进PWM控制               
  217.         PID_MAX=PWMT;
  218.         counter=0;
  219.         out=0;
  220.         PWM=1;
  221.    // jia=1;

  222.         I_term=0;
  223.         last_error=0;
  224.         Set_temp=40;                //初始设定温度为41度
  225.         Real_temp=Set_temp*10;
  226.         key_hold=1;
  227.           Init_DS18B20();
  228.           WriteOneChar(0xCC);        //跳过读序号列号的操作
  229.           WriteOneChar(0x44); //启动温度转换
  230.         delay_50us(15000);        //等待温度测量         15000
  231.         TMOD=0x01;                        //定时器0模式1               
  232.         TR0=1;                                                                  
  233.         ET0=1;
  234.         IT0=1;
  235.         EX0=1;
  236.         EA=1;
  237.        
  238.         while(1)
  239.         {
  240.                 counter++;
  241.                 if(counter>40)        //if(counter>40)
  242.                 {
  243.                         test_temp=1;        //进行一次温度检定
  244.                         counter=0;                               
  245.                 }
  246.                 if(test_temp)         //温度检定标志置位,进入温度PID调节
  247.                 {
  248.                         Real_temp=ReadTemperature(); //采集当前实际温度
  249.                         if(Real_temp>Set_temp*10)
  250.                         PWM=1;
  251.                         else                       
  252.                         PID(Set_temp*10,Real_temp); //PID程序
  253.                         test_temp=0;                                 //检定完成,清温度检定标志
  254.                 }       
  255.                 if(key_hold)
  256.                 Disp_temp=Real_temp;
  257.                 else Disp_temp=Set_temp;
  258.                 display(Disp_temp);       
  259.                 key_set();        //按键温度设置
  260.         }
  261. }
复制代码

所有资料51hei提供下载:
水温控制系统1.zip (338.66 KB, 下载次数: 15)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 转播转播 分享分享 分享淘帖 顶 踩
回复

使用道具 举报

沙发
qpzmg 发表于 2019-6-24 10:04 | 只看该作者
感谢分享,学习一下。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51Hei单片机16群 联系QQ:125739409;技术交流QQ群7344883

Powered by 单片机教程网

快速回复 返回顶部 返回列表