找回密码
 立即注册

QQ登录

只需一步,快速开始

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

非原创 单片机热风器控制 自整定PID程序+PCB文件原理图

  [复制链接]
跳转到指定楼层
楼主
很早以前淘来的 热风器 自整定 PID 参考程序,现发布出来给大伙分享,内容仅供学习参考,包含PCB图;
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)


单片机源程序如下:
  1. #include<intrins.h>
  2. #include<stdlib.h>//包含 rand() 这样的随机函数

  3. #include "STC12C5A60S2.h"
  4. #include "zcy.h"
  5. #include "s_12864.h"



  6. ////////////////////////////////////////////////////////
  7. //全局变量

  8. volatile long time0_temp1 = 0;
  9. volatile long time0_temp2 = 0;

  10. volatile long global_sec = 0;

  11. int key_counter = 0 ;
  12. int led_flash_mode_index = 2 ;//led闪灯模式 1--8 从1开始 最多8种模式   ssssssssss

  13. volatile int time0_10ms_flag = 0;
  14. int time0_10ms_counter = 0;
  15. int led_active_flag = 0;

  16. typedef void (*led_fun_str)(void);//定义一个函数指针的数据类型
  17. //之后用该数据类型定义一个数组
  18. led_fun_str led_fun_bufffer[29+29];

  19. void (*led_flash_fun_str)(void);

  20. int led_index = 1;

  21. int k_off = 0;
  22. int k_on  = 0;

  23. uchar temp_random = 0;
  24. uchar now_temp_random = 0;
  25. uchar last_temp_random = 0;
  26. uchar temp_diff        = 0;

  27. uchar temp_buffer_random[29];

  28. int k_extern = 0;
  29. int loop_temp = 0;

  30. uchar temp_buffer_16_16_comm[32];//必须设计成全局变量才不会显示错乱
  31. uchar temp_buffer_8_16_comm[16];//必须设计成全局变量才不会显示错乱

  32. int refer_fun_flag = 0;
  33. int key_perss_counter  = 0;
  34. int key_once_active_flag = 0;//key动作一次
  35. int key_value = 0 ;

  36. float now_temp              = 0.0;
  37. long dis_now_temp           = 0;
  38. float wenkong_now_temp      = 0.0;//用于温度控制的当前温度

  39. volatile int global_sec_flag = 0;
  40. int temp_zero_below_flag = 1 ;//1说明是0及正温度  0说明是负温度

  41. char temp_dis_num_buffer[10];//必须定义成全局变量 否则出错 原因不详
  42. char *temp_str;

  43. uint them = 0;
  44. int  ds_18b20_reset_ok_flag = 0;

  45. //pid
  46. float           SV_value           = 50.0; //设定温度值
  47. float           PV_value           = 0.0;  //用于参与计算的当前温度值
  48. volatile float  P_value            = 0.0;  //比例带 比如56.3代表56.3%  0.0--200.0
  49. int             I_value            = 0;  //积分时间  秒  0-3600
  50. int             D_value            = 0;   //微分时间  秒  0-900

  51. int comm_dis_once_flag    = 1; //初始为1
  52. volatile int special_dis_once_flag = 1; //初始为1
  53. int pid_tune_flag         = 0;//初始为0 即pid阶段 采用默认的值    1 为自整定过程

  54. int three_dot_dis_flag    = 0;

  55. float  Proportion  = 0.0;           //  比例常数 Proportional Const
  56. float  Integral    = 0.0;           //  积分常数 Integral Const        
  57. float  Derivative  = 0.0;           //  微分常数 Derivative Const
  58. float  LastError   = 0.0;           //  Error[-1]
  59. float  PrevError   = 0.0;           //  Error[-2]
  60. float  SumError    = 0.0;           //  Sums of Errors
  61. float  dError      = 0.0;
  62. float  Error       = 0.0;

  63. int   pid_result = 0;
  64. float T_Hight = 0.0;
  65. float T_LOW   = 100.0; //温度
  66. long TIME_Hight = 0;
  67. long TIME_LOW   = 0;        //具体的秒
  68. int pid_con_10ms_flag = 0;
  69. int pid_con_counter        = 0;

  70. float  KC = 1.0;  //临界比例系数  初始默认的值
  71. int    TC = 40;   //振荡周期      初始默认的值

  72. int temp_pid  =  0;//设定成全局变量  

  73. volatile int get_now_temp_flag   = 0;
  74. volatile int enable_pid_sec_flag = 0;
  75. volatile int pid_self_sec_flag   = 0;

  76. //uint pid_self_calc_buffer[200] _at_ 0xF000;        //0xffff 对应flash的最顶端

  77. int zero_across_counter = 0;
  78. int pid_self_first_status_flag = 0;

  79. long pid_self_time_sec = 0;

  80. float max_temp  = 0.0 ;  //初始温度等于0
  81. float min_temp  = 100.0 ;//初始温度等于100
  82. float sum_temp  = 0.0 ;  //初始温度等于0
  83. float aver_temp        = 0.0 ;

  84. int cool_ack_counter    = 0;
  85. int hot_ack_counter     = 0;
  86. int once_add_1_flag     = 0;

  87. float pid_self_calc_buffer[4];
  88. int k_pid_self_counter = 0;

  89. int enable_calc_min_max_flag = 0;
  90. int k_max_min = 0;
  91. int dis_tune_once_flag = 1;

  92. int k_cut_off_flag = 0;//断k偶标志
  93. long k_reou_value = 0;

  94. int soft_dis_flag = 1;
  95. int soft_counter  = 0;
  96. int soft_end_counter = 0;

  97. int pwm_con_time_flag = 0;

  98. //qqqqqqqqqqqqqq
  99. ////////////////////////////////////////////////////////
  100. //函数定义
  101. void SendByte(uchar Dbyte); //发送字节数据
  102. void write_cmd(uchar Cbyte);//写指令
  103. void write_data(uchar Dbyte);//写数据
  104. void PUTchar8x8(int row,int col,int count,uchar *put);
  105. void PUTchar8x16(int row,int col,int count,uchar *put);
  106. void PUTchar16x16(int row,int col,int count,uchar *put);//32个字节表示1个汉字
  107. void PUTchar24x24(int row,int col,int count,uchar *put);
  108. void PUTBMP(void);//图片
  109. void PUTREVERSEBMP(void);//图片反显
  110. void LcmClear(void);//清屏
  111. void LcmSet(void);//显示所有  即满屏都是黑色的
  112. void LcmInit(void);//初始化
  113. void ohengxian(void);//O横线程序
  114. void jihengxian(void);//奇横线程序
  115. void oshuxian(void);//O竖线程序
  116. void jishuxian(void);//奇竖线程序
  117. void dianxian(void);//点显示程序 满屏都是点
  118. void zifu8x16xian(void);//可以显示数字及英文
  119. void zifu16x16xian(void);//可以显示特定的汉字
  120. void lcd_dis_position_16_16(int line,int column,uchar zifu_16_16[2]);// 1行 1列 具体的字符
  121. void lcd_dis_position_8_16(int line,int column,uchar zifu_8_16);// 1行 1列 具体的字符
  122. void lcd_s_12864_dis_8_16_str(int dis_line,int start_position,char *dis_str);//显示一行的8*16的字符
  123. void ds_18b20_DelayXus(int n);
  124. void ds_18b20_init(void);//DS18B20的初始化
  125. uchar ds_18b20_read_date(void);  //读一个字节
  126. void ds_18b20_write_date(uchar date);//写一个字节
  127. float read_18b20_temp(void);//读出18b20的温度值 实际温度值返回 同时改变temp_zero_below_flag的值 如果是0 说明是0度以下
  128. void key_pro(void);
  129. void display_pro(void);
  130. void pid_pro(void);
  131. void dis_4_line_as_null(void);
  132. void dis_pid_self_value(void);
  133. float read_max6675_temper(void);// 利用max6675读k探头的温度 返回最终温度的1倍
  134. void PWM_clock(uchar clock);
  135. void PWM_start(uchar module,uchar mode);
  136. void set_pwm_value(uchar value);//0--255之间         value越大,占空比越高 输出电压也越大 40-->0.8v 237-->4.6v



  137. //hhhhhhhhhhhhhhhhhhhhhhhhhhh
  138. ////////////////////////////////////////////////////////
  139. //中断函数ttttttttttttttttttttttttttttt
  140. void tm0_isr(void) interrupt 1 using 1  //1ms
  141. {

  142. TL0 = 0x20;                //设置定时初值
  143. TH0 = 0xD1;                //设置定时初值
  144.         
  145. time0_temp1++;
  146. if(time0_temp1 % 2 == 0 )//2ms
  147.         {
  148.         
  149.         pid_con_10ms_flag = 1;
  150.         
  151.         }
  152. if(time0_temp1 >= 10 )//10ms
  153.         {
  154.         time0_temp1 = 0;
  155.         time0_10ms_flag = 1;
  156.         
  157.         }

  158. time0_temp2++;

  159. if(time0_temp2 % 200  == 0)//200ms
  160.         {
  161.         get_now_temp_flag   = 1;
  162.         }

  163. if(time0_temp2 % 200  == 0)//200ms
  164.         {
  165.         //get_now_temp_flag   = 1;
  166.         
  167.         pid_self_sec_flag   = 1;
  168.         
  169.         pwm_con_time_flag   = 1;
  170.         enable_pid_sec_flag = 1;
  171.         special_dis_once_flag = 1;
  172.         
  173.         }

  174. if(time0_temp2 >= 1000 )//1s         如果要想1000对应1s 那么中间不能有关中断的行为发生
  175.         {
  176.         time0_temp2 = 0;
  177.         global_sec++;
  178.         global_sec_flag = 1;
  179.         
  180.         three_dot_dis_flag  ^= 1;
  181.    
  182.         soft_dis_flag = 1;//软启动
  183.         
  184.         //ssr_con_1;delay_ms(10);ssr_con_0;//test
  185.         
  186.         }

  187. }


  188. void PCA_Intrrpt(void) interrupt 7 //pwm 的中断
  189. {
  190. if(CCF0) CCF0=0;
  191. if(CCF1) CCF1=0;   //软件清零
  192. if(CF)   CF=0;     //软件清零
  193. }



  194. ////////////////////////////////////////////////////////
  195. //函数

  196. void Timer0Init(void)                //1毫秒@12.000MHz  定时器0
  197. {
  198.         AUXR |= 0x80;        //定时器时钟1T模式
  199.         TMOD &= 0xF0;        //设置定时器模式
  200.         TMOD |= 0x01;        //设置定时器模式
  201.         TL0 = 0x20;                //设置定时初值
  202.         TH0 = 0xD1;                //设置定时初值
  203.         TF0 = 0;                //清除TF0标志
  204.         TR0 = 1;                //定时器0开始计时
  205.         ET0 = 1;        //enable timer0 interrupt   
  206. }


  207. void io_init(void)
  208. {

  209. P3M0 = 0x00 ;   //  0000  0000  
  210. P2M0 = 0xf0 ;   //  1111  0000  低四位为按键
  211. P1M0 = 0xff ;   //  1111  1111  强推挽输出          lcd 及 ssr驱动
  212. P0M0 = 0x00 ;   //  0000  0000  强推挽输出

  213. key_1_in;
  214. key_2_in;
  215. key_3_in;
  216. key_4_in;

  217. ssr_con_out;

  218. lcd_s_12864_cs_out;
  219. lcd_s_12864_reset_out;
  220. lcd_s_12864_rs_out;
  221. lcd_s_12864_sda_out;
  222. lcd_s_12864_sck_out;
  223. lcd_s_12864_light_out;

  224. lcd_s_12864_cs_0;
  225. lcd_s_12864_reset_0;
  226. lcd_s_12864_rs_0;
  227. lcd_s_12864_sda_0;
  228. lcd_s_12864_sck_0;
  229. lcd_s_12864_light_0;

  230. max6675_so_in;
  231. max6675_sck_out;
  232. max6675_cs1_out;
  233. cs1_1;

  234. pwm_con_out;
  235. pwm_con_0;

  236. }



  237. void power_on_event(void)//eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
  238. {
  239. int k;
  240. for( k = 0; k < 2; k++ )//闪灯2次
  241.         {
  242.         lcd_s_12864_light_0;
  243.         delay_ms(200);
  244.         lcd_s_12864_light_1;
  245.         delay_ms(200);
  246.         }

  247. //引用一下基本的函数 否则老是出现警告错误
  248. if( refer_fun_flag == 1 )//让refer_fun_flag永远为0 意思就是永远不实际引用这些函数
  249.         {
  250. //        PUTchar8x8(1,1,5,zifu8x8);
  251. //        PUTchar24x24(1,1,2,zifu24x24);
  252. //        PUTBMP();//图片
  253. //        PUTREVERSEBMP();//图片反显
  254. //        LcmClear();//清屏
  255. //        LcmSet();//显示所有  即满屏都是黑色的
  256. //        LcmInit();//初始化
  257. //        ohengxian();//O横线程序
  258. //        jihengxian();//奇横线程序
  259. //        oshuxian();//O竖线程序
  260. //        jishuxian();//奇竖线程序
  261. //        dianxian();//点显示程序 满屏都是点
  262. //        zifu8x16xian();//可以显示数字及英文
  263. //        zifu16x16xian();//可以显示特定的汉字
  264. //        lcd_dis_position_16_16(1,1,"郑");
  265. //        lcd_dis_position_8_16(1,1,'8');

  266.         }                                                               

  267. }


  268. //s_12864    lllllllllllllllllllllllllllllll
  269. void SendByte(uchar Dbyte) //发送字节数据
  270. {
  271. uchar i,TEMP;
  272. TEMP = Dbyte;
  273. for(i=0;i<8;i++)
  274.     {
  275.     lcd_s_12864_sck_0;
  276.     _nop_();        
  277.         _nop_();
  278.     if( TEMP & 0x80 )
  279.         {
  280.         lcd_s_12864_sda_1;
  281.         }
  282.     else
  283.         {
  284.         lcd_s_12864_sda_0;
  285.         }
  286.     lcd_s_12864_sck_1;
  287.     _nop_();        
  288.     _nop_();     
  289.     TEMP = TEMP<<1;
  290.     }
  291. }


  292. void write_cmd(uchar Cbyte )//写指令
  293. {
  294. lcd_s_12864_cs_0;
  295. lcd_s_12864_rs_0;
  296. SendByte(Cbyte);
  297. }


  298. void write_data(uchar Dbyte )//写数据
  299. {
  300. lcd_s_12864_cs_0;
  301. lcd_s_12864_rs_1;
  302. SendByte(Dbyte);
  303. }


  304. void PUTchar8x8(int row,int col,int count,uchar *put)
  305. {               
  306. uint X=0;
  307. int  j,i;
  308. write_cmd(0xb0+row);
  309. write_cmd(0x10+(8*col/16));               
  310. write_cmd(0x00+(8*col%16));
  311. for(j=0;j<count;j++)
  312.     {
  313.     for(i=0;i<8;i++)
  314.         {
  315.         write_data(put[X++]);
  316.         }
  317.     }        
  318. }


  319. void PUTchar8x16(int row,int col,int count,uchar *put)//row 0--3代表1--4行 col 0--15 代表1--16个起始位置  count 1--16 代表写入了几个字符  *put代表字符数组 16个字节代表一个8*16的字符
  320. {               
  321. uint X=0;
  322. int j,i;
  323. write_cmd(0xb0+row);
  324. write_cmd(0x10+(8*col/16));               
  325. write_cmd(0x00+(8*col%16));
  326. for(j=0;j<count;j++)
  327.     {
  328.     for(i=0;i<8;i++)
  329.         {
  330.         write_data(put[X++]);
  331.         }
  332.     write_cmd(0xb1+row);        
  333.     write_cmd(0x10+(8*col/16));               
  334.     write_cmd(0x00+(8*col%16));
  335.     for(i=0;i<8;i++)
  336.         {
  337.         write_data(put[X++]);
  338.         }
  339.     write_cmd(0xb0+row);
  340.     col=col+1;
  341.     }
  342. }


  343. void PUTchar16x16(int row,int col,int count,uchar *put)//32个字节表示1个汉字
  344. {               
  345. uint X=0;
  346. int j,i;
  347. write_cmd(0xb0+row);
  348. write_cmd(0x10+(8*col/16));               
  349. write_cmd(0x00+(8*col%16));
  350. for(j=0;j<count;j++)
  351.     {
  352.     for(i=0;i<16;i++)
  353.         {
  354.         write_data(put[X++]);
  355.         }
  356.     write_cmd(0xb1+row);        
  357.     write_cmd(0x10+(8*col/16));               
  358.     write_cmd(0x00+(8*col%16));
  359.     for(i=0;i<16;i++)
  360.         {
  361.         write_data(put[X++]);
  362.         }
  363.     write_cmd(0xb0+row);         
  364.     col=col+2;
  365.     }
  366. }


  367. void PUTchar24x24(int row,int col,int count,uchar *put)
  368. {               
  369. uint X=0;
  370. int j,i;
  371. write_cmd(0xb0+row);           //纵坐标
  372. write_cmd(0x10+(8*col/16));                 //横坐标
  373. write_cmd(0x00+(8*col%16));
  374. for(j=0;j<count;j++)
  375.     {
  376.     for(i=0;i<24;i++)
  377.         {
  378.         write_data(put[X++]);
  379.         }
  380.     write_cmd(0xb1+row);        
  381.     write_cmd(0x10+(8*col/16));               
  382.     write_cmd(0x00+(8*col%16));
  383.     for(i=0;i<24;i++)
  384.         {
  385.         write_data(put[X++]);
  386.         }
  387.     write_cmd(0xb2+row);        
  388.     write_cmd(0x10+(8*col/16));               
  389.     write_cmd(0x00+(8*col%16));
  390.     for(i=0;i<24;i++)
  391.         {
  392.         write_data(put[X++]);
  393.         }
  394.     write_cmd(0xb0+row);
  395.     col=col+3;
  396.     }
  397. }


  398. void PUTBMP(void)//图片
  399. {               
  400. uint X=0;
  401. int j,i;
  402. for(j=0;j<8;j++)
  403.     {
  404.     write_cmd(0xb0+j);
  405.     write_cmd(0x10);               
  406.     write_cmd(0x00);
  407.     for(i=0;i<128;i++)
  408.         {
  409.         write_data(bmp1[X++]);//bmp1为具体的图片数组
  410.         }
  411.     }        
  412. }


  413. void PUTREVERSEBMP(void)//图片反显
  414. {        
  415. uint X=0;
  416. int j,i;
  417. for(j=0;j<8;j++)
  418.     {
  419.     write_cmd(0xb0+j);
  420.     write_cmd(0x10);               
  421.     write_cmd(0x00);
  422.     for(i=0;i<128;i++)
  423.         {
  424.         write_data(~bmp1[X++]);
  425.         }
  426.     }        
  427. }


  428. void LcmClear(void)//清屏
  429. {         
  430. int x,y;
  431. for(y=0;y<8;y++)
  432.     {   
  433.     write_cmd(0xb0+y);
  434.     write_cmd(0x10);               
  435.     write_cmd(0x00);
  436.     for(x=0;x<132;x++)
  437.         {
  438.         write_data(0);
  439.         }
  440.     }        
  441. }


  442. void LcmSet(void)//显示所有  即满屏都是黑色的
  443. {         
  444. int x,y;
  445. for(y=0;y<8;y++)
  446.     {   
  447.     write_cmd(0xb0+y);
  448.     write_cmd(0x10);               
  449.     write_cmd(0x00);
  450.     for(x=0;x<132;x++)
  451.         {
  452.         write_data(0xff);
  453.         }
  454.     }        
  455. }


  456. void LcmInit(void)//初始化
  457. {        
  458. lcd_s_12864_cs_0;
  459. lcd_s_12864_reset_0;
  460. delay_ms(100);
  461. lcd_s_12864_reset_1;
  462. delay_ms(100);
  463. write_cmd(0xe2);//system reset
  464. delay_ms(10);
  465. write_cmd(0x24);//SET VLCD RESISTOR RATIO  0x20--0x27  可以调节对比对 之有 0x23 0x24 这2个值可以选择 0x24的对比度强  粗调
  466. write_cmd(0xa2);//BR=1/9
  467. write_cmd(0xa0);//set seg direction
  468. write_cmd(0xc8);//set com direction
  469. write_cmd(0x2f);//set power control
  470. write_cmd(0x40);//set scroll line
  471. write_cmd(0x81);//SET ELECTRONIC VOLUME
  472. write_cmd(0x1c);//set pm: 通过改变这里的数值来改变电压 //也可以调节对比度 从0x00 -- 0x3f 值越大对比度越大 细调

  473. //write_cmd(0xa6);//set inverse display           a6 off, a7 on  打开跟不打开没有任何影响
  474. //write_cmd(0xa4);//set all pixel on                      打开跟不打开没有任何影响
  475. write_cmd(0xaf);//set display enable
  476. LcmClear();     //先清屏
  477. }


  478. void ohengxian(void)//O横线程序
  479. {
  480. int x,y;
  481. for(y=0;y<8;y++)
  482.     {   
  483.     write_cmd(0xb0+y);
  484.     write_cmd(0x10);               
  485.     write_cmd(0x00);
  486.     for(x=0;x<128;x++)
  487.         {
  488.         write_data(0x55);
  489.         }
  490.     }         
  491. }


  492. void jihengxian(void)//奇横线程序
  493. {
  494. int x,y;
  495. for(y=0;y<8;y++)
  496.     {
  497.     write_cmd(0xb0+y);
  498.     write_cmd(0x10);               
  499.     write_cmd(0x00);
  500.     for(x=0;x<128;x++)
  501.         {
  502.         write_data(0xAA);
  503.         }
  504.     }         
  505. }


  506. void oshuxian(void)//O竖线程序
  507. {
  508. int x,y;
  509. for(y=0;y<8;y++)
  510.     {   
  511.     write_cmd(0xb0+y);
  512.     write_cmd(0x10);               
  513.     write_cmd(0x00);
  514.     for(x=0;x<128;x++)
  515.         {
  516.         if(x%2==0)
  517.             {
  518.             write_data(0xFF);
  519.             }
  520.         else
  521.             {
  522.             write_data(0);
  523.             }   
  524.         }
  525.     }         
  526. }


  527. void jishuxian(void)//奇竖线程序
  528. {
  529. int x,y;
  530. for(y=0;y<8;y++)
  531.     {   
  532.     write_cmd(0xb0+y);
  533.     write_cmd(0x10);               
  534.     write_cmd(0x00);
  535.     for(x=0;x<128;x++)
  536.         {
  537.         if(x%2==0)
  538.             {
  539.             write_data(0);
  540.             }
  541.         else
  542.             {
  543.             write_data(0xFF);
  544.             }
  545.         }
  546.     }         
  547. }


  548. void dianxian(void)//点显示程序 满屏都是点
  549. {
  550. int x,y;
  551. for(y=0;y<8;y++)
  552.     {   
  553.     write_cmd(0xb0+y);
  554.     write_cmd(0x10);               
  555.     write_cmd(0x00);
  556.     for(x=0;x<128;x++)
  557.         {
  558.         if(x%2==0)
  559.             {
  560.             write_data(0xAA);
  561.             }
  562.         else
  563.             {
  564.             write_data(0x55);
  565.             }
  566.         }
  567.     }         
  568. }


  569. void zifu8x16xian(void)//可以显示数字及英文
  570. {
  571. int k;
  572. for(k=0;k<4;k++)//代表显示4行
  573.     {
  574.     PUTchar8x16(2*k,0,16,zifu8x16);
  575.     }
  576. }


  577. void zifu16x16xian(void)//可以显示特定的汉字
  578. {
  579. int k;
  580. for(k=0;k<4;k++)
  581.     {
  582.     PUTchar16x16(2*k,0,16,zifu16x16);
  583.     }
  584. }


  585. //zzzzzzzzzzzzzzzzzzz
  586. void lcd_dis_position_16_16(int line,int column,uchar zifu_16_16[2])// 1行 1列 具体的字符
  587. {               
  588. uint X=0;
  589. int i;
  590. /////////////////////////////////////
  591. if     ( zifu_16_16 == "郑" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_001[i];}}
  592. else if( zifu_16_16 == "州" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_002[i];}}
  593. else if( zifu_16_16 == "迎" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_003[i];}}
  594. else if( zifu_16_16 == "之" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_004[i];}}
  595. else if( zifu_16_16 == "胜" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_005[i];}}
  596. else if( zifu_16_16 == "电" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_006[i];}}
  597. else if( zifu_16_16 == "子" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_007[i];}}
  598. else if( zifu_16_16 == "公" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_008[i];}}
  599. else if( zifu_16_16 == "司" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_009[i];}}

  600. else if( zifu_16_16 == "当" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_010[i];}}
  601. else if( zifu_16_16 == "前" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_011[i];}}
  602. else if( zifu_16_16 == "温" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_012[i];}}
  603. else if( zifu_16_16 == "度" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_013[i];}}

  604. else if( zifu_16_16 == "设" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_014[i];}}
  605. else if( zifu_16_16 == "定" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_015[i];}}

  606. else if( zifu_16_16 == "比" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_016[i];}}
  607. else if( zifu_16_16 == "例" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_017[i];}}
  608. else if( zifu_16_16 == "积" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_018[i];}}
  609. else if( zifu_16_16 == "分" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_019[i];}}
  610. else if( zifu_16_16 == "微" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_020[i];}}

  611. else if( zifu_16_16 == "自" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_021[i];}}
  612. else if( zifu_16_16 == "整" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_022[i];}}
  613. else if( zifu_16_16 == "定" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_023[i];}}
  614. else if( zifu_16_16 == "中" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_024[i];}}

  615. else if( zifu_16_16 == "软" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_025[i];}}
  616. else if( zifu_16_16 == "启" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_026[i];}}
  617. else if( zifu_16_16 == "动" ){for(i = 0; i < 32; ++i){temp_buffer_16_16_comm[i] = hanzi_16_16_027[i];}}

  618. /////////////////////////////////////
  619. write_cmd(0xb0+((line-1)*2));//第1行
  620. write_cmd(0x10+(8*(2*(column-1))/16));
  621. write_cmd(0x00+(8*(2*(column-1))%16));//起始位置
  622. for(i=0;i<16;i++)
  623.     {   
  624.     write_data(temp_buffer_16_16_comm[X++]);
  625.     }
  626. write_cmd(0xb1+((line-1)*2));        
  627. write_cmd(0x10+(8*(2*(column-1))/16));        
  628. write_cmd(0x00+(8*(2*(column-1))%16));
  629. for(i=0;i<16;i++)
  630.     {
  631.     write_data(temp_buffer_16_16_comm[X++]);
  632.     }
  633. write_cmd(0xb0+((line-1)*2));
  634. }


  635. void lcd_dis_position_8_16(int line,int column,uchar zifu_8_16)// 1行 1列 具体的字符
  636. {               
  637. uint X=0;
  638. int i;
  639. /////////////////////////////////////
  640. if     ( zifu_8_16 == '0' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_001[i];}}
  641. else if( zifu_8_16 == '1' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_002[i];}}
  642. else if( zifu_8_16 == '2' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_003[i];}}
  643. else if( zifu_8_16 == '3' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_004[i];}}
  644. else if( zifu_8_16 == '4' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_005[i];}}
  645. else if( zifu_8_16 == '5' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_006[i];}}
  646. else if( zifu_8_16 == '6' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_007[i];}}
  647. else if( zifu_8_16 == '7' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_008[i];}}
  648. else if( zifu_8_16 == '8' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_009[i];}}
  649. else if( zifu_8_16 == '9' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_010[i];}}
  650. else if( zifu_8_16 == ':' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_011[i];}}
  651. else if( zifu_8_16 == '-' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_012[i];}}
  652. else if( zifu_8_16 == '.' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_013[i];}}
  653. else if( zifu_8_16 == '+' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_014[i];}}

  654. else if( zifu_8_16 == '%' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_015[i];}}
  655. else if( zifu_8_16 == 'S' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_016[i];}}
  656. else if( zifu_8_16 == 'C' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_017[i];}}

  657. else if( zifu_8_16 == 'P' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_018[i];}}
  658. else if( zifu_8_16 == 'I' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_019[i];}}
  659. else if( zifu_8_16 == 'D' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_020[i];}}

  660. else if( zifu_8_16 == ' ' ){for(i = 0; i < 16; ++i){temp_buffer_8_16_comm[i] = zifu_8_16_021[i];}}

  661. /////////////////////////////////////
  662. write_cmd(0xb0+((line-1)*2));//第1行
  663. write_cmd(0x10+(8*(1*(column-1))/16));
  664. write_cmd(0x00+(8*(1*(column-1))%16));//起始位置
  665. for(i=0;i<8;i++)
  666.     {   
  667.     write_data(temp_buffer_8_16_comm[X++]);
  668.     }
  669. write_cmd(0xb1+((line-1)*2));        
  670. write_cmd(0x10+(8*(1*(column-1))/16));        
  671. write_cmd(0x00+(8*(1*(column-1))%16));
  672. for(i=0;i<8;i++)
  673.     {
  674.     write_data(temp_buffer_8_16_comm[X++]);
  675.     }
  676. write_cmd(0xb0+((line-1)*2));
  677. }


  678. char *convert_num_to_str(long num)//将数字转成字符串 最大显示21亿 第1位为0的话,则显示0
  679. {

  680. temp_dis_num_buffer[0] = ((num/1000000000)%10) + '0';
  681. temp_dis_num_buffer[1] = ((num/100000000)%10) + '0';
  682. temp_dis_num_buffer[2] = ((num/10000000)%10) + '0';
  683. temp_dis_num_buffer[3] = ((num/1000000)%10) + '0';
  684. temp_dis_num_buffer[4] = ((num/100000)%10) + '0';
  685. temp_dis_num_buffer[5] = ((num/10000)%10) + '0';
  686. temp_dis_num_buffer[6] = ((num/1000)%10) + '0';
  687. temp_dis_num_buffer[7] = ((num/100)%10) + '0';
  688. temp_dis_num_buffer[8] = ((num/10)%10) + '0';
  689. temp_dis_num_buffer[9] = ((num/1)%10) + '0';

  690. temp_str = temp_dis_num_buffer;

  691. return temp_str;
  692. }


  693. void lcd_s_12864_dis_8_16_str(int dis_line,int start_position,char *dis_str)//显示一行的8*16的字符
  694. {
  695. int temp_1=0;
  696. int i;
  697. char *temp_str;
  698. temp_str = dis_str;
  699. while(1)//求出长度
  700.     {
  701.     temp_1++;
  702.     if( *temp_str++ == '\0'  )
  703.         {
  704.         break;
  705.         }
  706.     }
  707. for(i = 0; i < (temp_1 - 1) ; ++i)
  708.     {
  709.     lcd_dis_position_8_16(dis_line,start_position + i , *dis_str++);
  710.     }
  711. }


  712. void dis_long_number(int dis_line,long dis_num)
  713. {

  714. lcd_dis_position_8_16(dis_line,0,((dis_num/1000000000)%10) + '0');
  715. lcd_dis_position_8_16(dis_line,1,((dis_num/100000000)%10) + '0');
  716. lcd_dis_position_8_16(dis_line,2,((dis_num/10000000)%10) + '0');
  717. lcd_dis_position_8_16(dis_line,3,((dis_num/1000000)%10) + '0');
  718. lcd_dis_position_8_16(dis_line,4,((dis_num/100000)%10) + '0');
  719. lcd_dis_position_8_16(dis_line,5,((dis_num/10000)%10) + '0');
  720. lcd_dis_position_8_16(dis_line,6,((dis_num/1000)%10) + '0');
  721. lcd_dis_position_8_16(dis_line,7,((dis_num/100)%10) + '0');
  722. lcd_dis_position_8_16(dis_line,8,((dis_num/10)%10) + '0');
  723. lcd_dis_position_8_16(dis_line,9,((dis_num/1)%10) + '0');

  724. }


  725. //key
  726. int key_scan(void)
  727. {
  728. int key_temp = 0;
  729. if(!(key_1_status))
  730.     {
  731.     delay_ms(10);
  732.     if(!(key_1_status))
  733.         {
  734.         key_perss_counter++;
  735.         if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
  736.             {
  737.             //lcd_s_12864_light_0;
  738.             //delay_ms(20);
  739.             //lcd_s_12864_light_1;//报警            
  740.             //delay_ms(20);
  741.             key_temp = 11;//长按
  742.             }
  743.         else if( key_perss_counter >= key_perss_long_long_max_num )
  744.             {
  745.             lcd_s_12864_light_0;
  746.             delay_ms(50);
  747.             lcd_s_12864_light_1;//报警            
  748.             delay_ms(50);
  749.             key_temp = 111;//超长按
  750.             }
  751.         else
  752.             {
  753.             if( key_once_active_flag == 1 )
  754.                 {
  755.                 key_once_active_flag = 0;
  756.                 //lcd_s_12864_light_0;
  757.                 //delay_ms(10);
  758.                 //lcd_s_12864_light_1;//报警
  759.                 key_temp = 1;//短按
  760.                 }               
  761.             }
  762.         }
  763.     }
  764. else if(!(key_2_status))
  765.     {
  766.     delay_ms(10);
  767.     if(!(key_2_status))
  768.         {
  769.         key_perss_counter++;
  770.         if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
  771.             {
  772.             //lcd_s_12864_light_0;
  773.             //delay_ms(20);
  774.             //lcd_s_12864_light_1;
  775.             //delay_ms(20);
  776.             key_temp = 22;//长按
  777.             }
  778.         else if( key_perss_counter >= key_perss_long_long_max_num )
  779.             {
  780.             lcd_s_12864_light_0;
  781.             delay_ms(50);
  782.             lcd_s_12864_light_1;
  783.             delay_ms(50);
  784.             key_temp = 222;//超长按
  785.             }
  786.         else
  787.             {
  788.             if( key_once_active_flag == 1 )
  789.                 {
  790.                 key_once_active_flag = 0;
  791.                 //lcd_s_12864_light_0;
  792.                 //delay_ms(10);
  793.                 //lcd_s_12864_light_1;
  794.                 key_temp = 2;//短按
  795.                 }               
  796.             }
  797.         }
  798.     }
  799. else if(!(key_3_status))
  800.     {
  801.     delay_ms(10);
  802.     if(!(key_3_status))
  803.         {
  804.         key_perss_counter++;
  805.         if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
  806.             {
  807.             //lcd_s_12864_light_0;
  808.             //delay_ms(20);
  809.             //lcd_s_12864_light_1;
  810.             //delay_ms(20);
  811.             //key_temp = 33;//长按
  812.             key_temp = 3;            
  813.                         }
  814.         else if( key_perss_counter >= key_perss_long_long_max_num )
  815.             {
  816.             lcd_s_12864_light_0;
  817.             delay_ms(50);
  818.             lcd_s_12864_light_1;
  819.             delay_ms(50);
  820.             key_temp = 333;//超长按
  821.             //key_temp = 3;            
  822.                         }
  823.         else
  824.             {
  825.             if( key_once_active_flag == 1 )
  826.                 {
  827.                 key_once_active_flag = 0;
  828.                 //lcd_s_12864_light_0;
  829.                 //delay_ms(10);
  830.                 //lcd_s_12864_light_1;
  831.                 key_temp = 3;//短按
  832.                 }               
  833.             }
  834.         }
  835.     }
  836. else if(!(key_4_status))
  837.     {
  838.     delay_ms(10);
  839.     if(!(key_4_status))
  840.         {
  841.         key_perss_counter++;
  842.         if(( key_perss_counter > key_perss_long_max_num ) && ( key_perss_counter < key_perss_long_long_max_num ))
  843.             {
  844.             //lcd_s_12864_light_0;
  845.             //delay_ms(20);
  846.             //lcd_s_12864_light_1;
  847.             //delay_ms(20);
  848.             //key_temp = 44;//长按
  849.             key_temp = 4;            
  850.                         }
  851.         else if( key_perss_counter >= key_perss_long_long_max_num )
  852.             {
  853.             lcd_s_12864_light_0;
  854.             delay_ms(50);
  855.             lcd_s_12864_light_1;
  856.             delay_ms(50);
  857.             key_temp = 444;//超长按
  858.             //key_temp = 4;
  859.                         }
  860.         else
  861.             {
  862.             if( key_once_active_flag == 1 )
  863.                 {
  864.                 key_once_active_flag = 0;
  865.                 //lcd_s_12864_light_0;
  866.                 //delay_ms(10);
  867.                 //lcd_s_12864_light_1;
  868.                 key_temp = 4;//短按
  869.                 }               
  870.             }
  871.         }
  872.     }
  873. else//没有任何key按动的时候
  874.     {
  875.     key_once_active_flag = 1;//允许再按时1次动作
  876.     key_perss_counter    = 0;
  877.     }
  878. return key_temp;
  879. }


  880. //DS18B20
  881. void ds_18b20_DelayXus(int n)
  882. {
  883. while (n--)
  884.         {
  885.         _nop_();
  886.         //_nop_();
  887.         }
  888. }


  889. void ds_18b20_init(void)//DS18B20的初始化
  890. {  
  891. EA = 0;//关中断
  892. DQ=1;
  893. ds_18b20_DelayXus(1);//1US
  894. DQ=0;
  895. ds_18b20_DelayXus(600);//600US
  896. DQ=1;
  897. ds_18b20_DelayXus(100);         //100US
  898. if(DQ==0)
  899.         {
  900.         ds_18b20_reset_ok_flag = 1;
  901.         ds_18b20_DelayXus(200);
  902.         DQ=1;
  903.         }
  904. if(DQ==1)//说明复位成功
  905.         {
  906.         ds_18b20_reset_ok_flag = 0;
  907.         ds_18b20_DelayXus(200);
  908.         DQ=1;
  909.         }
  910. EA = 1;//开中断
  911. }


  912. uchar ds_18b20_read_date(void)  //读一个字节
  913. {
  914. uchar temp,i;
  915. EA = 0;
  916. for( i=0;i<8;i++)
  917.         {
  918.         DQ=1;
  919.         ds_18b20_DelayXus(2);
  920.         DQ=0;
  921.         ds_18b20_DelayXus(3);
  922.         DQ=1;
  923.         ds_18b20_DelayXus(2);
  924.         temp>>=1;
  925.         if(DQ)
  926.                 {
  927.                 temp=temp|0x80;
  928.                 }
  929.         ds_18b20_DelayXus(50);
  930.         }
  931. EA = 1;
  932. return temp;
  933. }


  934. void ds_18b20_write_date(uchar date)//写一个字节
  935. {
  936. uchar i;
  937. //EA = 0;
  938. for( i=0 ;i<8;i++)
  939.         {
  940.         DQ=0;
  941.         ds_18b20_DelayXus(2);
  942.         DQ = date&0x01;
  943.         ds_18b20_DelayXus(50);//50us
  944.         DQ=1;
  945.         date>>=1;
  946.         }
  947. EA = 1;
  948. }


  949. float read_18b20_temp(void)//读出18b20的温度值 实际温度值返回 同时改变temp_zero_below_flag的值 如果是0 说明是0度以下
  950. {
  951. uchar themh=0;   
  952. uchar theml=0;
  953. uint temp_0 = 0;
  954. float temp_1;

  955. ds_18b20_init();
  956. if(ds_18b20_reset_ok_flag == 0)//检测传感器是否存在
  957.         {   
  958.         ds_18b20_write_date(0xcc);          //跳过ROM匹配
  959.         ds_18b20_write_date(0x44);          //发出温度转换命令
  960.         ds_18b20_DelayXus(1000);
  961.         }
  962. ds_18b20_init();
  963. if(ds_18b20_reset_ok_flag == 0)
  964.         {
  965.         ds_18b20_write_date(0x0cc);         //跳过ROM匹配
  966.         ds_18b20_write_date(0x0be);         //发出读温度命令
  967.         theml=ds_18b20_read_date() ;        //读出温度值并存放在 theml,themh
  968.         themh=ds_18b20_read_date() ;
  969.         }

  970. //temp_0 = themh*256 + theml;
  971. temp_0 = (themh<<8) | theml;  //2句作用一样

  972. if( temp_0 & 0xf000 ) //说明是 负温度
  973.     {
  974.     temp_0 =  (~temp_0)+ 1 ;//等于268  0000 0001 0000 1100 == 按位反 = 1111 1110 1111 0011 = fef3 = 65267 然后加1 = 65267+1 = 65268
  975.     //temp_0 = (65536 - temp_0) ;//负温度求补码  65268 + 268 = 65536  跟用这个办法计算出的值一样
  976.         temp_zero_below_flag = 0;
  977.         }
  978. else//为0 ,说明是 正温度
  979.     {
  980.     temp_zero_below_flag = 1;
  981.         }

  982. temp_1 = (float)(temp_0)*0.0625;

  983. return temp_1;
  984. }


  985. void dis_now_temp_test(void)//测试用 显示当前温度
  986. {
  987. if( global_sec_flag == 1 )//1秒1次
  988.         {
  989.         global_sec_flag = 0;
  990.         ssr_con_1;delay_ms(10);ssr_con_0;//test               
  991.         
  992.         now_temp = read_18b20_temp();
  993.         wenkong_now_temp = now_temp;
  994.     dis_now_temp = (long)(wenkong_now_temp*10);//*10是为了显示的需要
  995.         
  996.         //dis_now_temp = 396;//test
  997.         lcd_dis_position_16_16(1,1,"当");
  998.     lcd_dis_position_16_16(1,2,"前");
  999.     lcd_dis_position_16_16(1,3,"温");
  1000.     lcd_dis_position_16_16(1,4,"度");
  1001.    
  1002.         if (temp_zero_below_flag == 1)//正温度
  1003.                 {
  1004.                 lcd_dis_position_8_16(2,1, '+');
  1005.             lcd_dis_position_8_16(2,2, (dis_now_temp/100%10) + '0');
  1006.             lcd_dis_position_8_16(2,3, (dis_now_temp/10%10) + '0');
  1007.             lcd_dis_position_8_16(2,4, '.');
  1008.             lcd_dis_position_8_16(2,5, (dis_now_temp/1%10) + '0');
  1009.                 }
  1010.         else if (temp_zero_below_flag == 0)//负温度
  1011.                 {
  1012.                 lcd_dis_position_8_16(2,1, '-');
  1013.             lcd_dis_position_8_16(2,2, (dis_now_temp/100%10) + '0');
  1014.             lcd_dis_position_8_16(2,3, (dis_now_temp/10%10) + '0');
  1015.             lcd_dis_position_8_16(2,4, '.');
  1016.             lcd_dis_position_8_16(2,5, (dis_now_temp/1%10) + '0');
  1017.                 }
  1018.         }
  1019. }

  1020. //kkkkkkkkkkkkkkkkkkkk
  1021. void key_pro(void)
  1022. {
  1023. key_value = key_scan();
  1024. if     (key_value == 1)//A 作为 自整定 跟 pid 切换的开关
  1025.         {
  1026.         pid_tune_flag ^= 1;
  1027.         LcmClear();//清屏
  1028.         //清除最后一行的内容
  1029.         //dis_4_line_as_null();

  1030.         if(pid_tune_flag == 1)//自整定阶段
  1031.                 {
  1032.                
  1033.                 //记录此刻的状态 即设定温度是否 高于或等于 当前温度
  1034.                 if( SV_value >= PV_value )//设定温度 高于 或者 等于  当前温度  启动加热
  1035.                         {
  1036.                         pid_self_first_status_flag = 1;
  1037.                         once_add_1_flag = 0;
  1038.                         }
  1039.                 else//设定温度 低于 当前温度
  1040.                         {
  1041.                         pid_self_first_status_flag = 0;
  1042.                         once_add_1_flag = 1;
  1043.                         }
  1044.                
  1045.                 dis_tune_once_flag = 1;
  1046.                 zero_across_counter = 0;
  1047.                 pid_self_time_sec = 0;
  1048.                 pid_self_calc_buffer[0]=0.0;
  1049.         pid_self_calc_buffer[1]=0.0;
  1050.         pid_self_calc_buffer[2]=0.0;
  1051.         pid_self_calc_buffer[3]=0.0;        
  1052.                 k_pid_self_counter = 0;
  1053.                 enable_calc_min_max_flag = 0;
  1054.                 max_temp = 0.0 ;  //初始温度等于0
  1055.                 min_temp = 1024.0 ;//初始温度等于1024
  1056.                 sum_temp = 0.0 ;  //初始温度等于0
  1057.                 aver_temp = 0.0 ;
  1058.                 T_Hight  = 0.0;
  1059.                 T_LOW    = 1024.0; //温度
  1060.                 TIME_Hight = 0;
  1061.                 TIME_LOW   = 0;        //具体的0.2s
  1062.                
  1063.                 }
  1064.         else if(pid_tune_flag == 0)//pid阶段
  1065.                 {
  1066.                 comm_dis_once_flag    = 1;
  1067.                 special_dis_once_flag = 1;
  1068.                 }
  1069.         }
  1070. else if(key_value == 2)//B
  1071.         {
  1072.         
  1073.         }
  1074. else if((key_value == 3) || (key_value == 333))  //-  设定温度
  1075.         {
  1076.         special_dis_once_flag = 1;
  1077.         if(key_value == 3)
  1078.                 {
  1079.                 SV_value-=1.0;
  1080.                 }
  1081.         else
  1082.                 {
  1083.                 SV_value-=10.0;
  1084.                 }
  1085.         if(SV_value < 0.0)
  1086.                 {
  1087.                 SV_value = 999.9;
  1088.                 }
  1089.         }
  1090. else if((key_value == 4) || (key_value == 444)) //+
  1091.         {
  1092.         special_dis_once_flag = 1;
  1093.         if(key_value == 4)
  1094.                 {
  1095.                 SV_value+=1.0;
  1096.                 }
  1097.         else
  1098.                 {
  1099.                 SV_value+=10.0;
  1100.                 }
  1101.         if(SV_value > 999.9)
  1102.                 {
  1103.                 SV_value = 0.0;
  1104.                 }
  1105.         }

  1106. }        

  1107. //dddddddddddddddddddddd
  1108. void display_pro(void)
  1109. {
  1110. if( pid_tune_flag == 0 )//pid阶段
  1111.         {
  1112.         //第1行 当前温度
  1113.         //第2行 设定温度
  1114.         //第3行 显示pid 各参数的名字
  1115.         //第4行 显示pid 各参数的具体值
  1116.         if (comm_dis_once_flag == 1)//基本信息只显示一次
  1117.                 {
  1118.                 comm_dis_once_flag = 0;
  1119.                
  1120.                 lcd_dis_position_16_16(1,1,"当");
  1121.                 lcd_dis_position_16_16(1,2,"前");
  1122.                 lcd_dis_position_16_16(1,3,"温");
  1123.                 lcd_dis_position_16_16(1,4,"度");
  1124.                
  1125.                 lcd_dis_position_16_16(2,1,"设");
  1126.                 lcd_dis_position_16_16(2,2,"定");
  1127.                 lcd_dis_position_16_16(2,3,"温");
  1128.                 lcd_dis_position_16_16(2,4,"度");
  1129.                
  1130.                 lcd_dis_position_8_16(1,15,'C');
  1131.                 lcd_dis_position_8_16(2,15,'C');
  1132.                
  1133.                 lcd_dis_position_16_16(3,1,"比");
  1134.                 lcd_dis_position_16_16(3,2,"例");
  1135.                 lcd_dis_position_16_16(3,4,"积");
  1136.                 lcd_dis_position_16_16(3,5,"分");
  1137.                 lcd_dis_position_16_16(3,7,"微");
  1138.                 lcd_dis_position_16_16(3,8,"分");
  1139.                
  1140.                 }
  1141.         
  1142.         if (special_dis_once_flag == 1)//独立信息  0.2秒1次
  1143.                 {
  1144.                 special_dis_once_flag = 0;
  1145.                
  1146.                 //lcd_s_12864_light_1;delay_ms(10);lcd_s_12864_light_0;//test

  1147.                 //当前温度
  1148.                 lcd_dis_position_8_16(1,9, ((uint)(PV_value*10)/1000)%10 + '0');//百位
  1149.                 lcd_dis_position_8_16(1,10,((uint)(PV_value*10)/100)%10 + '0');
  1150.                 lcd_dis_position_8_16(1,11,((uint)(PV_value*10)/10)%10 + '0');
  1151.                 lcd_dis_position_8_16(1,12,'.');
  1152.                 lcd_dis_position_8_16(1,13,((uint)(PV_value*10)/1)%10 + '0');
  1153.         
  1154.                 //设定温度
  1155.                 lcd_dis_position_8_16(2,9, ((uint)(SV_value*10)/1000)%10 + '0');
  1156.                 lcd_dis_position_8_16(2,10,((uint)(SV_value*10)/100)%10 + '0');
  1157.                 lcd_dis_position_8_16(2,11,((uint)(SV_value*10)/10)%10 + '0');
  1158.                 lcd_dis_position_8_16(2,12,'.');
  1159.                 lcd_dis_position_8_16(2,13,((uint)(SV_value*10)/1)%10 + '0');
  1160.                
  1161.                 lcd_dis_position_8_16(4,6,'%');
  1162.                 lcd_dis_position_8_16(4,11,'S');
  1163.                 lcd_dis_position_8_16(4,16,'S');
  1164.         
  1165.                 if( pid_tune_flag == 1 )//如果启动了pid自整定 ,则显示 pid自整定中...
  1166.                         {
  1167.                         lcd_dis_position_8_16(4,1,'P');
  1168.                         lcd_dis_position_8_16(4,2,'I');
  1169.                         lcd_dis_position_8_16(4,3,'D');
  1170.                         
  1171.                         lcd_dis_position_16_16(4,3,"自");
  1172.                         lcd_dis_position_16_16(4,4,"整");
  1173.                         lcd_dis_position_16_16(4,5,"定");
  1174.                         lcd_dis_position_16_16(4,6,"中");
  1175.                         
  1176.                         if     ( three_dot_dis_flag == 1 )//显示不断闪烁的3个点 表示运算中
  1177.                                 {
  1178.                                 lcd_dis_position_8_16(4,14,'.');
  1179.                                 lcd_dis_position_8_16(4,15,'.');
  1180.                                 lcd_dis_position_8_16(4,16,'.');
  1181.                                 }
  1182.                         else if( three_dot_dis_flag == 0 )
  1183.                                 {
  1184.                                 lcd_dis_position_8_16(4,14,' ');
  1185.                                 lcd_dis_position_8_16(4,15,' ');
  1186.                                 lcd_dis_position_8_16(4,16,' ');
  1187.                                 }
  1188.                         }
  1189.                 else if( pid_tune_flag == 0 )//整定ok后 显示计算获得的pid值 正常pid控制的时候显示的内容
  1190.                         {
  1191.                         //比例 积分 微分
  1192.                         lcd_dis_position_8_16(4,1,((uint)(P_value*10)/1000)%10 + '0');
  1193.                         lcd_dis_position_8_16(4,2,((uint)(P_value*10)/100)%10 + '0');
  1194.                         lcd_dis_position_8_16(4,3,((uint)(P_value*10)/10)%10 + '0');
  1195.                         lcd_dis_position_8_16(4,4,'.');
  1196.                         lcd_dis_position_8_16(4,5,((uint)(P_value*10)/1)%10 + '0');
  1197.                         
  1198.                         lcd_dis_position_8_16(4,7,((I_value*1)/1000)%10 + '0');
  1199.                         lcd_dis_position_8_16(4,8,((I_value*1)/100)%10 + '0');
  1200.                         lcd_dis_position_8_16(4,9,((I_value*1)/10)%10 + '0');
  1201.                         lcd_dis_position_8_16(4,10,((I_value*1)/1)%10 + '0');
  1202.                         
  1203.                         lcd_dis_position_8_16(4,13,((D_value*1)/100)%10 + '0');
  1204.                         lcd_dis_position_8_16(4,14,((D_value*1)/10)%10 + '0');
  1205.                         lcd_dis_position_8_16(4,15,((D_value*1)/1)%10 + '0');
  1206.                         }
  1207.                 }        
  1208.         }
  1209. else if( pid_tune_flag == 1 )//自整定阶段
  1210.         {
  1211.         if(dis_tune_once_flag == 1)//显示一次  
  1212.                 {
  1213.                 dis_tune_once_flag = 0;
  1214.                 dis_pid_self_value();
  1215.                 }
  1216.         }
  1217. }


  1218. int pid_calc(float set_temp ,float now_temp )// pid计算  set_temp 为设定的温度  now_temp  代表实际输入的当前温度值  0 - 100的输出值
  1219. {
  1220. Error = set_temp - now_temp;                 // 偏差
  1221. if(( Error < max_value_error  ) && ( Error > (min_value_error)  ))//只有在一定的温差范围内才pid计算
  1222.     {   
  1223.     SumError += Error;
  1224.     dError    = LastError - PrevError;   // 当前微分
  1225.     PrevError = LastError;
  1226.     LastError = Error;
  1227.     temp_pid  =  (int)((Proportion * Error) + (Integral * SumError) + (Derivative * dError));   
  1228.     //temp_pid  =  (int)(temp_pid * 0.5) ;//输出比例控制
  1229.         }
  1230. else//只有开关作用
  1231.     {
  1232.     if( Error >= max_value_error )//远大于当前温度,加热
  1233.         {
  1234.         temp_pid = 100;
  1235.         //temp_pid = 80;
  1236.                 }
  1237.     else if( Error <= (min_value_error) )//远小于当前温度,不加热
  1238.         {
  1239.         temp_pid = 0;
  1240.         }
  1241.     }
  1242. if( temp_pid < 0 )
  1243.     {
  1244.     temp_pid = 0;
  1245.     }
  1246. else if( temp_pid > 100 )
  1247.     {
  1248.     temp_pid = 100;
  1249.     }
  1250. return temp_pid;
  1251. }


  1252. void pid_con(void)//由计算结果控制输出
  1253. {

  1254. //适用于 pwm
  1255. //每200ms根据结果改变一次输出电压的值
  1256. if( pwm_con_time_flag == 1)
  1257.         {
  1258.         pwm_con_time_flag = 0;
  1259.         
  1260.         //lcd_s_12864_light_1;delay_ms(10);lcd_s_12864_light_0;//test

  1261.         //set_pwm_value(40 + (uchar)(pid_result * (((float)(237-40))/100.0)) );
  1262.         set_pwm_value(40 + (uchar)(pid_result * 1.97) );//跟上面这句话等价
  1263.         
  1264.         }

  1265. }


  1266. void pid_pro(void)//pid 自整定及控制输出 ppppppppppppppppppppppppppppp
  1267. {
  1268. //每200ms获得一次温度
  1269. if( get_now_temp_flag == 1)//200ms秒获得一次温度
  1270.         {
  1271.         get_now_temp_flag = 0;
  1272.         
  1273.         //lcd_s_12864_light_1;delay_ms(10);lcd_s_12864_light_0;//test

  1274.         PV_value = read_max6675_temper();
  1275.         }

  1276. if     ( pid_tune_flag == 1 )//自整定阶段  完毕之后转成pid控制
  1277.         {
  1278.         //自整定ok后自动转为pid阶段
  1279.         //自整定失败的情况下 让基本参数恢复默认值

  1280.         if( pid_self_sec_flag == 1 )//自整定过程  0.2秒1次
  1281.                 {
  1282.                 pid_self_sec_flag = 0;
  1283.                 dis_tune_once_flag = 1;//0.2秒显示1次基本信息
  1284.                 //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test

  1285.                 pid_self_time_sec++;
  1286.                 if(pid_self_time_sec > (3600*3)) // 如果总的自整定时间大于了3/5=0.6个小时,则说明整定失败
  1287.                         {
  1288.                         pid_self_time_sec = 0;                        
  1289.                         //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
  1290.                         LcmClear();//清屏
  1291.                         comm_dis_once_flag    = 1;
  1292.                         special_dis_once_flag = 1;
  1293.                         pid_tune_flag = 0;//那么将自动退出自整定过程 同时采用默认值  进入pid阶段
  1294.                         KC = 1.0;//临界比例系数  初始默认的值
  1295.                         TC = 40; //振荡周期    初始默认的值

  1296.                         }

  1297.                 if(( pid_self_first_status_flag == 1) || ( pid_self_first_status_flag == 0))//0 设定温度 低于 当前温度  //1设定温度 高于 或者 等于  当前温度  启动加热
  1298.                         {

  1299.                         //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test

  1300.                         //基本on/off控制
  1301.                         if( SV_value >= PV_value )//启动加热
  1302.                                 {
  1303.                                 cool_ack_counter = 0;
  1304.                                 hot_ack_counter++;
  1305.                                 if(hot_ack_counter > 3)//连续3次都是一样的结果 说明确定 SV_value >= PV_value
  1306.                                         {
  1307.                                        
  1308.                                         ssr_con_1;
  1309.                                         //pwm_con_1;//一旦pwm参与将不能通过操作io的形式控制该口线
  1310.                                         set_pwm_value(237);//全速加热

  1311.                                         if(once_add_1_flag == 0)
  1312.                                                 {
  1313.                                                 once_add_1_flag = 1;
  1314.                                                 zero_across_counter++;
  1315.                                                 
  1316.                                                 //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
  1317.                                                 
  1318.                                                 if(zero_across_counter == 3 )
  1319.                                                         {
  1320.                                                         TIME_LOW = pid_self_time_sec - 3;//此时的时间不是最低温度对应的时间
  1321.                                                         }
  1322.                                                 }
  1323.                                         }
  1324.                                 }
  1325.                         else//当前温度 大于 设定温度 停止加热
  1326.                                 {
  1327.                                 
  1328.                                 //lcd_s_12864_light_0;delay_ms(10);lcd_s_12864_light_1;//test
  1329.                                                                
  1330.                                 hot_ack_counter = 0;
  1331.                                 cool_ack_counter++;
  1332.                                 if(cool_ack_counter > 3)
  1333.                                         {
  1334.                                         ssr_con_0;
  1335.                                         set_pwm_value(40);//不加热
  1336.                                         if(once_add_1_flag == 1)
  1337.                                                 {
  1338.                                                 once_add_1_flag = 0;
  1339.                                                 zero_across_counter++;
  1340.                                                 if(zero_across_counter == 3 )
  1341.                                                         {
  1342.                                                         TIME_LOW = pid_self_time_sec - 3;//此时的时间不是最低温度对应的时间
  1343.                                                         }
  1344.                                                 }
  1345.                                         }
  1346.                                 }

  1347.                         //最低温度 出现在 zero_across_counter = 3 的阶段
  1348.                         //最高温度 出现在 zero_across_counter = 4 的阶段
  1349.                         if((zero_across_counter == 3 ) || (zero_across_counter == 4 ))
  1350.                                 {                                
  1351.                                 pid_self_calc_buffer[k_pid_self_counter] = PV_value;
  1352.                                 k_pid_self_counter++;
  1353.                                 if(k_pid_self_counter > 3)//0--3 共4个元素
  1354.                                         {
  1355.                                         k_pid_self_counter = 0;
  1356.                                         enable_calc_min_max_flag = 1;
  1357.                                         }
  1358.                                 if(enable_calc_min_max_flag == 1)//只要有4个值,就可以计算了 后面来的值覆盖了前面的值
  1359.                                         {
  1360.                                         //去掉最小值 最大值 取剩下2个值的平均值
  1361.                                         sum_temp = 0.0;  //先清0
  1362.                                         min_temp = 1024.0;
  1363.                                         max_temp = 0.0;
  1364.                                                 
  1365.                                         for(k_max_min = 0; k_max_min < 4; k_max_min++ )
  1366.                                                 {                                                
  1367.                                                 if(pid_self_calc_buffer[k_max_min] <= min_temp)
  1368.                                                         {
  1369.                                                         min_temp = pid_self_calc_buffer[k_max_min];
  1370.                                                         }
  1371.                                                 if(pid_self_calc_buffer[k_max_min] >= max_temp)
  1372.                                                         {
  1373.                                                         max_temp = pid_self_calc_buffer[k_max_min];
  1374.                                                         }                                                
  1375.                                                 sum_temp = (sum_temp + pid_self_calc_buffer[k_max_min]);
  1376.                                                 }
  1377.                                         sum_temp =  sum_temp - min_temp - max_temp ;
  1378.                                        
  1379.                                        
  1380.                                         //pid_self_first_status_flag = 1 时 最低温度出现在3阶段
  1381.                                         //pid_self_first_status_flag = 0 时 最低温度出现在4阶段
  1382.                                         if(pid_self_first_status_flag == 1)
  1383.                                                 {
  1384.                                                 if(zero_across_counter == 3 )//最低温度
  1385.                                                         {
  1386.                                                         aver_temp = (sum_temp/2.0);                                       
  1387.                                                         if( aver_temp <= T_LOW )
  1388.                                                                 {
  1389.                                                                 T_LOW = aver_temp;
  1390.                                                                 }                                
  1391.                                                         }
  1392.                                                 else if(zero_across_counter == 4 )//最高温度
  1393.                                                         {
  1394.                                                         aver_temp = (sum_temp/2.0);
  1395.                                                         if( aver_temp >= T_Hight )
  1396.                                                                 {
  1397.                                                                 T_Hight = aver_temp;
  1398.                                                                 }
  1399.                                                         }
  1400.                                                 }
  1401.                                         else if(pid_self_first_status_flag == 0)
  1402.                                                 {
  1403.                                                 if(zero_across_counter == 4 )//最低温度
  1404.                                                         {
  1405.                                                         aver_temp = (sum_temp/2.0);                                       
  1406.                                                         if( aver_temp <= T_LOW )
  1407.                                                                 {
  1408.                                                                 T_LOW = aver_temp;
  1409.                                                                 }                                
  1410.                                                         }
  1411.                                                 else if(zero_across_counter == 3 )//最高温度
  1412.                                                         {
  1413.                                                         aver_temp = (sum_temp/2.0);
  1414.                                                         if( aver_temp >= T_Hight )
  1415.                                                                 {
  1416.                                                                 T_Hight = aver_temp;
  1417.                                                                 }
  1418.                                                         }
  1419.                                                 }
  1420.                                         }
  1421.                                 }
  1422.                         else if(zero_across_counter == 5 )//4次过0 则说明出现了振荡 整定成功
  1423.                                 {
  1424.                                 zero_across_counter = 0;                                
  1425.                                 pid_tune_flag = 0;//进入pid阶段
  1426.                                 //pid_tune_flag = 1;//test
  1427.                                 TIME_Hight = pid_self_time_sec - 3;//此时的时间不是最高温度对应的时间
  1428.                                 LcmClear();//清屏
  1429.                                 comm_dis_once_flag    = 1;
  1430.                                 special_dis_once_flag = 1;                                
  1431.                                 //dis_4_line_as_null();//清除最后一行的内容
  1432.                                 //计算 T_Hight T_LOW TIME_Hight TIME_LOW 这4个值
  1433.                                 //根据以上4个值  KC 与 TC 的值便会计算出来
  1434.                                 
  1435.                                 KC = 12.7/(T_Hight - T_LOW);
  1436.                                 KC = 5.0 * KC;//因为是0.2s一次 所以扩大5倍
  1437.                                 TC = 1 * (TIME_Hight - TIME_LOW);//如果记录了 最低温度 与 最高温度对应的时间 那么沿用这个公式:TC = 2 * (TIME_Hight - TIME_LOW);
  1438.                                 }
  1439.                         }
  1440.                 //显示具体的值  测试用
  1441.                 //dis_pid_self_value(); //test
  1442.                 }
  1443.         }
  1444. else if( pid_tune_flag == 0 )//pid 阶段  默认开机进入此阶段
  1445.         {
  1446.         //0 算出 临界增益 KC 及 振荡周期 TC
  1447.         // KC = (4*d)/(3.14*A)  ---> d = 5(输出幅值) ; A = 记录的温度最高值与最低值的差值的0.5倍 即:(T_Hight - T_LOW)*0.5
  1448.         // KC = (4*5)/(3.14*((T_Hight - T_LOW)*0.5)) = 40/3.14/(T_Hight - T_LOW) =  12.7/(T_Hight - T_LOW)
  1449.         // KC = 12.7/(T_Hight - T_LOW)
  1450.         // TC = 2 * (TIME_Hight - TIME_LOW) ---> 2 * ( 高点温度对应时间 - 低点温度对应时间 )
  1451.         // TC = 2 * (TIME_Hight - TIME_LOW)
  1452.         //1 算出 具体的比例系数 积分秒数 微分秒数
  1453.         //Proportion = 0.6*KC
  1454.         //I_value    = 0.5*TC
  1455.         //D_value    = 0.125*TC
  1456.         //2 算出具体的 比例带 积分系数 微分系数
  1457.         //P_value     = (1/Proportion)*100
  1458.         //Integral          = Proportion/I_value = (0.6*KC)/(0.5*TC)
  1459.         //Derivative  = Proportion*D_value = (0.6*KC)*(0.125*TC)  
  1460.         //3显示用的3个变量的值
  1461.         //P_value     = (1/Proportion)*100  百分比
  1462.         //I_value     = 0.5*TC                                秒
  1463.         //D_value     = 0.125*TC                        秒
  1464.         //4pid计算用的3个变量的值
  1465.         //Proportion  = 0.6*KC
  1466.         //Integral          = Proportion/I_value = (0.6*KC)/(0.5*TC)
  1467.         //Derivative  = Proportion*D_value = (0.6*KC)*(0.125*TC)  
  1468.         
  1469.         //KC = 21.4;//test
  1470.         //TC = 471;//test
  1471.         
  1472.         if(enable_pid_sec_flag == 1)//进入pid时,0.2秒计算1次
  1473.                 {
  1474.   

  1475. ……………………

  1476. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
热风 自整定 PID 51单片机程序 + 原理图 PCB.7z (162.76 KB, 下载次数: 270)


评分

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

查看全部评分

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

使用道具 举报

沙发
ID:228467 发表于 2020-2-29 09:54 | 只看该作者
好资料,感谢!!!
回复

使用道具 举报

板凳
ID:97678 发表于 2020-2-29 10:03 | 只看该作者
好东西,值得分享。。。。。。
回复

使用道具 举报

地板
ID:196702 发表于 2020-2-29 10:41 | 只看该作者
慢慢学习  谢谢楼主分享!
回复

使用道具 举报

5#
ID:399111 发表于 2020-2-29 13:08 | 只看该作者
这个自整定PID,有详细解说过程就好了,,,,
回复

使用道具 举报

6#
ID:764574 发表于 2020-5-30 09:28 | 只看该作者
可惜自己不懂没有学过单片机
回复

使用道具 举报

7#
ID:667717 发表于 2020-6-19 21:20 | 只看该作者
新手学习中
回复

使用道具 举报

8#
ID:430492 发表于 2021-3-29 22:59 | 只看该作者
自整定PID,还是有点难度的,谢谢楼主分享!!!
回复

使用道具 举报

9#
ID:253710 发表于 2021-7-10 12:25 | 只看该作者
正需要研究自整定,不错的资料,谢谢楼主分享
回复

使用道具 举报

10#
ID:33455 发表于 2021-8-31 22:08 | 只看该作者
感谢楼主正在搞自整定pid可以借鉴
回复

使用道具 举报

11#
ID:842922 发表于 2021-12-19 12:21 | 只看该作者
分析了一下感觉程序不会引起震荡首先zero_across_counter每次都会在主循环里复位如果温度在很短的时间不会震荡的话zero_across_counter会不断的清零,所以就采集不到最高和最低温度,如果把zero_across_counter清零语句屏蔽掉zero_across_counter会瞬间加到5然后在清零,这样程序会直接跳到自整定结束。有没有人看明白讨论一下
回复

使用道具 举报

12#
ID:933601 发表于 2024-1-25 08:56 | 只看该作者
慢慢学习  谢谢楼主分享!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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