找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机PID温控源程序

[复制链接]
跳转到指定楼层
楼主
ID:404701 发表于 2018-10-1 18:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
第一章 前言
温度控制系统无论是工业生产过程,还是日常生活都起着非常重要的作用,过低或过高的温度环境不仅是一种资源的浪费,同时也会对机器和工作人员的寿命产生严重影响,极有可能造成严重的经济财产损失,给生活生产带来许多不利的因素。基于AT89C51的单片机温度控制系统与传统的温度控制系统相比具有操作方便、价格便宜、精确度高和开展容易等优点,因此市场前景好。

第二章 系统设计
2.1方案论证
    方案一:整个系统采用LCD1602,该显示器原理简单,编程简单,对于我们这个系统显示效果也可以了。
方案二:整个系统采用LCD12864,该显示器是点阵的,编程相对有点难度,可以显示汉字。
综上,对于我们初学者来说,对编程还不是很熟练,我们采用方案一。
2.2系统的总设计
本设计使用单片机作为控制核心,采用整个温度传感器(DS18B20)对温度进行检测,以液晶显示屏(LCD1602)显示检测温度,通过继电器对加热降温系统进行控制;温度过高或过低,蜂鸣器报警提示;温度偏低进行热风机加热处理;温度偏高进行冷风机降温处理。系统总体控制框图如图2.1所示:
  
2.3 功能模块
    根据总系统的结构可以将其分为五个功能模块:单片机主控制模块、温度信号采集模块、温度处理模块、液晶屏温度显示模块、蜂鸣器报警模块。单片机主控制模块即整个系统的核心模块,是一个AT89C51芯片,主要通过执行其程序存储器Rom中得到程序来对其4个并行I/O口进行读写操作完成对其他模块的控制。温度信号采集模块是由一个温度信号采集器组成,主要是温度信号采集并将数据传回给单片机主控制模块。传感器采集的温度值通过传回给主控制模块AT89C51单片机进行处理,然后送入液晶显示器进行温度显示。温度处理模块是由继电器控制,热电机和冷电机分别来对温度进行升温、降温处理。液晶屏温度显示模块当然就是对温度的当前值进行显示。蜂鸣器报警模块就是对当采集的温度值大于或小于用户自定义的临界温度值进行报警提示。

整个设计总体分为以下几个部分:控制部分、显示部分、温度采集部分、按键控制部分。

控制部分由单片机AT89C51芯片在程序控制和外围简单组合电路作用下运行,和控制温度的上、下限,和LED的温度显示。控制发光的二极管的亮灭,起到提醒报警功能。

显示部分

显示电路采用1602LCD显示屏从P2口送数,P0口扫描。有两部分显示电路,第一是显示DS18B20温度传感器所检测的当前温度,第二是设定恒定的温度值。

温度采集部分由DS18B20智能温度传感器直接采集被测温度。

按键控制部分由三个按键控制调节,用来调节温度的恒定限值,起到预设调节作用。

  1. #include<reg51.h>
  2. #include<intrins.h>
  3. #include<math.h>
  4. #include<string.h>

  5. //PID结构体存储PID参数
  6. struct PID {
  7. unsigned int SetPoint; // 设定目标 Desired Value
  8. unsigned int Proportion; // 比例常数 Proportional Const
  9. unsigned int Integral; // 积分常数 Integral Const
  10. unsigned int Derivative; // 微分常数 Derivative Const
  11. unsigned int LastError; // Error[-1]
  12. unsigned int PrevError; // Error[-2]
  13. unsigned int SumError; // Sums of Errors
  14. };
  15. struct PID spid; // PID Control Structure

  16. unsigned int rout; // PID Response (Output)
  17. unsigned int rin; // PID Feedback (Input)

  18. sbit data1=P1^0;
  19. sbit clk=P1^1;
  20. sbit plus=P2^0;
  21. sbit subs=P2^1;
  22. sbit stop=P2^2;
  23. sbit output=P3^4;
  24. sbit DQ=P3^3;

  25. unsigned char flag,flag_1=0;
  26. unsigned char high_time,low_time,count=0;//占空比调节参数
  27. unsigned char set_temper=35;   
  28. unsigned char temper;        
  29. unsigned char i;
  30. unsigned char j=0;
  31. unsigned int s;
  32. /***********************************************************
  33. 延时子程序,延时时间以12M晶振为准,延时时间为30us×time
  34. ***********************************************************/
  35. void delay(unsigned char time)
  36.   {
  37.   unsigned char m,n;
  38.     for(n=0;n<time;n++)
  39.       for(m=0;m<2;m++){}
  40.   }
  41. /***********************************************************
  42. 写一位数据子程序
  43. ***********************************************************/
  44. void write_bit(unsigned char bitval)
  45.   {
  46.    EA=0;
  47.      DQ=0;  /*拉低DQ以开始一个写时序*/
  48.    if(bitval==1)
  49.       {
  50.        _nop_();
  51.        DQ=1;   /*如要写1,则将总线置高*/
  52.        }
  53.      delay(5);   /*延时90us供DA18B20采样*/
  54.    DQ=1;  /*释放DQ总线*/
  55.    _nop_();
  56.    _nop_();
  57.   EA=1;
  58.    }
  59. /***********************************************************
  60. 写一字节数据子程序
  61. ***********************************************************/
  62. void write_byte(unsigned char val)
  63. {
  64. unsigned char i;
  65. unsigned char temp;
  66. EA=0;
  67. TR0=0;
  68. for(i=0;i<8;i++)  /*写一字节数据,一次写一位*/
  69.      {
  70.       temp=val>>i;  /*移位操作,将本次要写的位移到最低位*/
  71.       temp=temp&1;
  72.       write_bit(temp);  /*向总线写该位*/
  73.       }
  74.   delay(7);   /*延时120us后*/
  75. // TR0=1;
  76. EA=1;
  77.   }
  78. /***********************************************************
  79. 读一位数据子程序
  80. ***********************************************************/
  81. unsigned char read_bit()
  82. {
  83. unsigned char i,value_bit;
  84. EA=0;
  85. DQ=0;   /*拉低DQ,开始读时序*/
  86. _nop_();
  87. _nop_();
  88. DQ=1;   /*释放总线*/
  89. for(i=0;i<2;i++){}
  90. value_bit=DQ;
  91. EA=1;
  92. return(value_bit);
  93.   }
  94. /***********************************************************
  95. 读一字节数据子程序
  96. ***********************************************************/
  97. unsigned char read_byte()
  98.   {
  99.   unsigned char i,value=0;
  100.   EA=0;
  101.   for(i=0;i<8;i++)
  102.      {
  103.       if(read_bit())  /*读一字节数据,一个时序中读一次,并作移位处理*/
  104.          value|=0x01<<i;
  105.       delay(4);  /*延时80us以完成此次都时序,之后再读下一数据*/
  106.       }
  107.   EA=1;
  108.   return(value);
  109.   }
  110. /***********************************************************
  111. 复位子程序
  112. ***********************************************************/
  113. unsigned char reset()
  114.   {
  115.   unsigned char presence;
  116.   EA=0;
  117.   DQ=0;   /*拉低DQ总线开始复位*/
  118.   delay(30);   /*保持低电平480us*/
  119.   DQ=1;   /*释放总线*/
  120.   delay(3);   
  121.   presence=DQ;   /*获取应答信号*/
  122.   delay(28);   /*延时以完成整个时序*/
  123.   EA=1;
  124.   return(presence);  /*返回应答信号,有芯片应答返回0,无芯片则返回1*/
  125.   }
  126. /***********************************************************
  127. 获取温度子程序
  128. ***********************************************************/
  129. void get_temper()
  130. {
  131. unsigned char i,j;
  132.   do
  133.   {
  134.    i=reset();  /*复位*/
  135. }while(i!=0);  /*1为无反馈信号*/
  136. i=0xcc;  /*发送设备定位命令*/
  137. write_byte(i);
  138. i=0x44;  /*发送开始转换命令*/
  139. write_byte(i);
  140. delay(180);  /*延时*/
  141.   do
  142.   {
  143. i=reset();  /*复位*/
  144. }while(i!=0);  
  145. i=0xcc;  /*设备定位*/
  146. write_byte(i);
  147. i=0xbe;  /*读出缓冲区内容*/
  148. write_byte(i);
  149. j=read_byte();
  150. i=read_byte();   
  151. i=(i<<4)&0x7f;
  152. s=(unsigned int)(j&0x0f);
  153. s=(s*100)/16;
  154. j=j>>4;
  155. temper=i|j;                                      /*获取的温度放在temper中*/
  156.   }
  157. /*====================================================================================================
  158. Initialize PID Structure
  159. =====================================================================================================*/
  160. void PIDInit (struct PID *pp)
  161. {
  162. memset ( pp,0,sizeof(struct PID));
  163. }
  164. /*====================================================================================================
  165. PID计算部分
  166. =====================================================================================================*/
  167. unsigned int PIDCalc( struct PID *pp,unsigned int NextPoint )
  168. {
  169. unsigned int dError,Error;
  170. Error = pp->SetPoint - NextPoint; // 偏差
  171. pp->SumError += Error; // 积分
  172. dError = pp->LastError -pp->PrevError; // 当前微分
  173. pp->PrevError = pp->LastError;
  174. pp->LastError = Error;
  175. return (pp->Proportion * Error // 比例项
  176. + pp->Integral * pp->SumEror // 积分项
  177. + pp->Derivative * dError); // 微分项
  178. }
  179. /***********************************************************
  180. 温度比较处理子程序
  181. ***********************************************************/
  182. compare_temper()
  183. {
  184. unsigned char i;
  185.     if(set_temper>temper)
  186.         {
  187.          if(set_temper-temper>1)   
  188.             {
  189.               high_time=100;
  190.               low_time=0;
  191.             }
  192.          else
  193.             {
  194.                for(i=0;i<10;i++)
  195.                  {  get_temper();
  196.                     rin = s; // Read Input
  197.                     rout = PIDCalc (&spid,rin ); // Perform PID Interation
  198.                  }
  199.                if (high_time<=100)
  200.                  high_time=(unsignedchar)(rout/800);
  201.                else
  202.                  high_time=100;
  203.                low_time= (100-high_time);
  204.             }
  205.         }
  206.      else if(set_temper<=temper)
  207.             {
  208.                if(temper-set_temper>0)
  209.                  {
  210.                    high_time=0;
  211.                    low_time=100;
  212.                  }
  213.                else
  214.                {
  215.                  for(i=0;i<10;i++)
  216.                  {  get_temper();
  217.                     rin = s; // Read Input
  218.                     rout = PIDCalc (&spid,rin ); // Perform PID Interation
  219.                  }
  220.                  if (high_time<100)
  221.                    high_time=(unsigned char)(rout/10000);
  222.                  else
  223.                    high_time=0;
  224.                  low_time= (100-high_time);
  225.                }
  226.             }
  227.     //  else
  228.     //      {}
  229.     }
  230. /*****************************************************
  231. T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期
  232. ******************************************************/
  233. void serve_T0() interrupt 1 using 1
  234.   {
  235.   if(++count<=(high_time))
  236.     output=1;
  237.   else if(count<=100)
  238.     {
  239.      output=0;
  240.      }
  241.   else
  242.      count=0;
  243.   TH0=0x2f;
  244.   TL0=0xe0;
  245.    }
  246. /*****************************************************
  247. 串行口中断服务程序,用于上位机通讯
  248. ******************************************************/
  249. void serve_sio() interrupt 4 using 2
  250.   {
  251. /*  EA=0;
  252.   RI=0;  
  253.   i=SBUF;
  254.   if(i==2)
  255.      {
  256.       while(RI==0){}  
  257.       RI=0;
  258.       set_temper=SBUF;  
  259.       SBUF=0x02;  
  260.       while(TI==0){}
  261.       TI=0;
  262.       }
  263.    else if(i==3)  
  264.       {
  265.        TI=0;
  266.       SBUF=temper;
  267.        while(TI==0){}
  268.        TI=0;
  269.        }
  270.     EA=1;   */
  271.    }
  272. void disp_1(unsigned char disp_num1[6])
  273. {
  274.     unsigned char n,a,m;
  275.     for(n=0;n<6;n++)
  276.      {
  277.     //  k=disp_num1[n];
  278.       for(a=0;a<8;a++)
  279.         {
  280.          clk=0;
  281.           m=(disp_num1[n]&1);
  282.            disp_num1[n]=disp_num1[n]>>1;
  283.          if(m==1)
  284.             data1=1;
  285.          else
  286.             data1=0;
  287.          _nop_();
  288.          clk=1;
  289.          _nop_();
  290.          }
  291.       }
  292. }
  293. /*****************************************************
  294. 显示子程序
  295. 功能:将占空比温度转化为单个字符,显示占空比和测得到的温度
  296. ******************************************************/
  297. void display()
  298. {
  299. unsigned char codenumber[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};
  300. unsigned char disp_num[6];
  301. unsigned int k,k1;
  302. k=high_time;
  303. k=k%1000;
  304. k1=k/100;
  305. if(k1==0)
  306.    disp_num[0]=0;
  307. else
  308.    disp_num[0]=0x60;
  309. k=k%100;
  310. disp_num[1]=number[k/10];
  311. disp_num[2]=number[k%10];
  312. k=temper;
  313. k=k%100;
  314. disp_num[3]=number[k/10];
  315. disp_num[4]=number[k%10]+1;
  316. disp_num[5]=number[s/10];
  317. disp_1(disp_num);
  318. }
  319. /***********************************************************
  320. 主程序
  321. ***********************************************************/
  322. main()
  323. {
  324. unsigned char z;
  325. unsigned char a,b,flag_2=1,count1=0;
  326. unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};;
  327. TMOD=0x21;   
  328. TH0=0x2f;   
  329. TL0=0x40;
  330. SCON=0x50;   
  331. PCON=0x00;            
  332. TH1=0xfd;   
  333. TL1=0xfd;
  334. PS=1;           
  335. EA=1;   
  336. EX1=0;   
  337. ET0=1;   
  338. ES=1;   
  339. TR0=1;  
  340. TR1=1;
  341. high_time=50;                 
  342. low_time=50;
  343. PIDInit ( &spid ); // Initialize Structure
  344. spid.Proportion = 10; // Set PID Coefficients
  345. spid.Integral = 8;
  346. spid.Derivative =6;
  347. spid.SetPoint = 100; // Set PID Setpoint
  348. while(1)
  349.       {
  350.           if(plus==0)
  351.             {
  352.               EA=0;
  353.               for(a=0;a<5;a++)
  354.                 for(b=0;b<102;b++){}  
  355.                 if(plus==0)
  356.                   {
  357.                   set_temper++;
  358.                   flag=0;
  359.                   }
  360.               }
  361.            else if(subs==0)
  362.               {
  363.                for(a=0;a<5;a++)
  364.                   for(b=0;a<102;b++){}  
  365.                   if(subs==0)
  366.                   {
  367.                     set_temper--;
  368.                     flag=0;
  369.                    }
  370.                }
  371.            else if(stop==0)
  372.                {
  373.                 for(a=0;a<5;a++)
  374.                    for(b=0;b<102;b++){}  
  375.                   if(stop==0)
  376.                    {
  377.                    flag=0;         
  378.                    break;
  379.                    }
  380.             EA=1;
  381.             }
  382.      get_temper();
  383.      b=temper;
  384.      if(flag_2==1)
  385.         a=b;
  386.      if((abs(a-b))>5)
  387.        temper=a;
  388.      else
  389.        temper=b;
  390.      a=temper;
  391.      flag_2=0;
  392.      if(++count1>30)
  393.         {
  394.          display();
  395.          count1=0;
  396.          }
  397.      compare_temper();   
  398.       }
  399.    TR0=0;
  400.    z=1;
  401. while(1)
  402.      {
  403.       EA=0;
  404.       if(stop==0)
  405.        {
  406.         for(a=0;a<5;a++)
  407.           for(b=0;b<102;b++){}
  408.         if(stop==0)
  409.           disp_1(phil);
  410.        //        break;
  411.           }
  412.      EA=1;
  413.         }
  414. }
复制代码


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

使用道具 举报

沙发
ID:1 发表于 2018-10-1 22:46 | 只看该作者
能补一下word吗?
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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