找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10591|回复: 1
收起左侧

936焊台用AVR模糊PID恒温控制

  [复制链接]
ID:75926 发表于 2015-4-2 22:40 | 显示全部楼层 |阅读模式
本帖最后由 xiaos 于 2015-4-2 22:41 编辑

用放大用LM324比较差··不过温度还是可以稳定,用M8 AD10位 pwm10位温度范围为200-500

精确度1度··

因为程序的原因加上要慢慢整定所以每次升温到设定值前15度就开始整定··

有个缺点就是PID控制恒温时的那几度温度升的很慢··

设置部分还没写好

自己的思路是直接用那个可变电阻做设置

AD转换采样可变电阻来设定温度

设置一按键为温度设定

当按了那按键后可变电阻设定温度有效

没按的话不管你怎么转都不能调节温度

那部分写完后整个代码,发出来大家一起参考

发觉问题还很多的。。希望大家多提下意见,小弟初学的

还有如果要改的话可以不改那电路的引一条采样跟控制线出来直接连上M8也可以的













  1. /*******************************
  2. project        :A/D转换数码管显示
  3. chip type      : atmega8               
  4. clock frequency:内部RC(INT) 8MHz
  5. Author         :周远峰               
  6. ********************************/
  7. #include "iom8v.h"
  8. #include "macros.h"
  9. #define osccal 0x7d                        
  10. unsigned long adc_rel;              //处理后世界转换结果
  11. unsigned long adc_rl;               //A/D转换结
  12. unsigned int tmp;                   //设置的温度参数                          
  13. unsigned char adc_mux;              //A/D通道
  14. unsigned char led_buff[3]={0,0,0};  //显示缓存
  15. signed int error0;                  //当前偏差
  16. signed int error1;                  //上次偏差
  17. signed int error2;                  //上上次偏差
  18. signed char Kp;                     //比例常数
  19. signed char Ki;                     //积分常数
  20. signed char Kd;                     //微分常数
  21. signed int kk1;                     //当前控制输出
  22. signed int kk2;                     //上次控制输出
  23. #define NB -3
  24. #define NM -2
  25. #define NS -1
  26. #define ZO 0
  27. #define PS 1
  28. #define PM 2
  29. #define PB 3
  30. #pragma data:code     
  31. //设置数据区位程序储存器
  32. const unsigned char seg_table[16]={0x40,0x79,0x24,0x30,0x19,0x90,0x80,0x78,0x00,0x10,0x08,0x81,0x44,0x21,0x04,0x8c};
  33. const unsigned char KP_table[49]={PB,PB,PM,PM,PS,ZO,ZO,PB,PB,PM,PS,PS,ZO,NS,PM,PM,PM,PS,ZO,NS,NS,PM,PM,PS,ZO,NS,NM,NM,PS,PS,ZO,NS,NS,NM,NM,PS,ZO,NS,NM,NM,NM,NB,ZO,ZO,NM,NM,NM,NB,NB};
  34. const unsigned char KI_table[49]={NB,NB,NM,NM,NS,ZO,ZO,NB,NB,NM,NS,NS,ZO,ZO,NB,NM,NS,NS,ZO,PS,PS,NM,NM,NS,ZO,PS,PM,PM,NM,NS,ZO,PS,PS,PM,PB,ZO,ZO,PS,PS,PM,PB,PB,ZO,ZO,PS,PM,PM,PB,PB};
  35. const unsigned char KD_table[49]={PS,NS,NB,NB,NB,NM,NS,PS,NS,NB,NM,NM,NS,ZO,ZO,NS,NM,NM,NS,NS,ZO,ZO,NS,NS,NS,NS,NS,ZO,ZO,ZO,ZO,ZO,ZO,ZO,ZO,PB,NS,PS,PS,PS,PS,PB,PB,PM,PM,PM,PS,PS,PB};
  36. #pragma data:data   
  37. //设置数据区回到数据储存器
  38. /*********************************************************

  39. 延时函数

  40. *********************************************************/
  41. void delay_us(int time) //微秒级延时
  42. {
  43. do
  44. time--;
  45. while (time>1);
  46. }
  47. void delay_ms(unsigned int time)  //毫秒级延时
  48. {
  49. while (time!=0)
  50.    {
  51.    delay_us(1000);
  52.    time--;
  53.    }
  54. }
  55. /************************************************************
  56. 中断显示初始化
  57. TIMER2 initialize - prescale:1024
  58. WGM: Normal
  59. desired value: 10mSec
  60. actual value:  9.984mSec (0.2%)
  61. *************************************************************/
  62. void timer2_init(void)
  63. {
  64. TCCR2 = 0x00; //stop
  65. ASSR  = 0x00; //set async mode
  66. TCNT2 = 0xB2; //setup
  67. OCR2  = 0x4E;
  68. TCCR2 = 0x07; //start
  69. DDRB=0xff;  //PC口为推挽1输出
  70. PORTB=0xff; //PC口内部上拉
  71. DDRD|=0xf1;
  72. PORTD&=0x1f;  //关闭LED
  73. }
  74. /***********************************************

  75. 中断显示

  76. *************************************************/
  77. #pragma interrupt_handler timer2_ovf_isr:5
  78. void timer2_ovf_isr(void)
  79. {
  80. unsigned char i;
  81. static unsigned k;
  82. SEI();
  83. TCNT2 = 0xB2; //reload counter value
  84. for(i=0;i<3;i++)
  85.    {
  86.    PORTB=led_buff[i];
  87.    PORTD|=(1<<(i+5));//待显示的位置1
  88.    delay_ms(1);
  89.    PORTD&=0x1f;     //关闭LED
  90.    }
  91. }
  92. /************************************************************

  93. PWM初始化,OC1A口输出

  94. *************************************************************/
  95. void timer1_init(void)
  96. {
  97. TCCR1B = 0x00; //stop
  98. TCNT1H = 0x00; //setup
  99. OCR1A  = 200;
  100. TCCR1A = (1<<WGM11)|(1<<WGM10)|(1<<COM1A1);//输出低电平
  101. TCCR1B = (1<<CS11)|(1<<CS10); //
  102. }
  103. /*****************************************************

  104. PID初始化

  105. ******************************************************/
  106. void pidcalc_init(void)  
  107. {
  108. Kp=3;
  109. Ki=3;
  110. Kd=3;
  111. kk1=0; //当前
  112. kk2=100;
  113. error0=0;
  114. error1=0;
  115. error2=0;
  116. tmp=300;
  117. }
  118. void pidcalc_zizheng(void)
  119. {
  120. if (tmp>adc_rel)
  121.    {
  122.         if (kk2<500) kk2+=3;
  123.         else kk2=500;
  124.    }
  125. if ((tmp-1)>adc_rel)
  126.    {
  127.         if (kk2<500) kk2+=3;
  128.         else kk2=500;
  129.    }
  130. /*if ((tmp-2)>adc_rel)
  131.    {
  132.         if (kk2<600) kk2+=3;
  133.         else kk2=600;
  134.    }*/
  135. if (tmp<adc_rel)
  136.    {
  137.    if (kk2>10) kk2-=3;
  138.    else kk2=10;
  139.    }
  140. if ((tmp+1)<adc_rel)
  141.    {
  142.    if (kk2>10) kk2-=3;
  143.    else kk2=10;
  144.    }
  145. /*if ((tmp+2)<adc_rel)
  146.    {
  147.    if (kk2>10) kk2-=3;
  148.    else kk2=10;
  149.    }
  150. /*if (tmp>adc_rel)
  151.    {
  152.    if (Ki<200) Ki+=4;
  153.    else Ki=400;
  154.    }
  155. if (tmp<adc_rel)
  156.    {
  157.    if (Ki>0) Ki-=4;
  158.    else Ki=0;
  159.    }  */
  160. }
  161. /*******************************************************

  162. PID函数

  163. ********************************************************/
  164. void pidcalc(void)
  165. {
  166. signed long KPP;
  167. signed long KII;
  168. signed long KDD;
  169. signed int i;
  170. signed char j;
  171. error0=tmp-adc_rel;
  172. j=error0-error1;
  173. i=7*(3+error0)+(3+j);
  174. if(i<49)
  175.     {
  176.      if (i>0)
  177.             {
  178.                 Kp=KP_table[i];
  179.                 Ki=KI_table[i];
  180.                 Kd=KD_table[i];
  181.                 }
  182.      }                        //输出                     
  183. if ((tmp-15)<adc_rel)                         //比设定低一定值时开始PID
  184.   {
  185.    if((tmp+5)>adc_rel)                        //比设定高时关PID
  186.        {
  187.        KPP=Kp*(error0-error1);                //比例
  188.        KII=error0*Ki;                         //积分
  189.        KDD=Kd*(error0-(2*error1)+error2);     //微分
  190.        kk1=(KPP+KII+KDD)*4+kk2;  
  191.        if(kk1<0x3ef)
  192.                    {
  193.                            if (kk1>=10) OCR1A=kk1;   
  194.                            else OCR1A=0;               
  195.                }
  196.            else
  197.                    {   
  198.                     OCR1A=0x3ff;
  199.                }      
  200.                            /*if((tmp-2)>adc_rel)
  201.                                 {
  202.                                 if(OCR1A<500) OCR1A+=20;
  203.                                 else OCR1A=500;
  204.                                         }*/
  205.            }
  206.     else
  207.            {
  208.            //if (tmp<adc_rel)
  209.                  // {
  210.                   ///  if (OCR1A>50) OCR1A-=20;
  211.                   //  else OCR1A=50;
  212.            OCR1A=0;  
  213.                  // }
  214.        }
  215.    }
  216. else
  217.    {
  218.     OCR1A=0x3ff;
  219.    }
  220. error2=error1;
  221. error1=error0;  
  222. }
  223. /***********************************************

  224. ADC初始化

  225. ************************************************/
  226. void adc_init(void)  
  227. {
  228. DDRC=0x00;
  229. PORTC=0X00;
  230. ADCSRA=0X00;
  231. ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V为基准AREF外加滤波电容
  232. ACSR=(1<<ACD);                  //关闭模拟比较器
  233. ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//128分频
  234. }
  235. /*********************************************

  236. ADC中断处理函数

  237. **********************************************/
  238. #pragma interrupt_handler adc_isr:15
  239. void adc_isr(void)
  240. {
  241. static unsigned i;
  242. adc_rl+=ADC&0x3ff;
  243. ADMUX=(1<<REFS1)|(1<<REFS0)|(adc_mux&0x0f); //选择内部2.56V位基准
  244. ADCSRA|=(1<<ADSC); //启动AD转换   
  245. if (i<2048)
  246.     i++;
  247. else  
  248.      {
  249.          adc_rel=adc_rl/2048;
  250.          adc_rel=adc_rel*3/5;
  251.          i=0;
  252.          adc_rl=0;
  253.          }
  254. }
  255. /******************************************************

  256. ADC数据转压缩BCD

  257. ******************************************************/
  258. void ADCtoBCD(unsigned int temp)
  259. {
  260. unsigned char i;
  261. for (i=0;i<3;i++)
  262.    {
  263.    led_buff[i]=seg_table[temp%10];/*temp%10求余数‘假设一个数是234那么234/10=23余4也就是查找4的段码*/
  264.    
  265.    temp=temp/10;// 234/10=23因为不处理小数实际就等于右移了
  266.    }
  267.    
  268. }
  269. /***************************************************************

  270. 主程序

  271. ***************************************************************/
  272. void main(void)
  273. {
  274. unsigned char i;
  275. unsigned int  k;
  276. unsigned int adc_old;
  277. unsigned long adc_ol;
  278. unsigned int adc_o;
  279. DDRD=0xff;
  280. PORTD=0xf0;
  281. OSCCAL=osccal;
  282. TIMSK = 0x40; //timer interrupt sources
  283. adc_mux=0;
  284. adc_init();
  285. timer1_init();
  286. pidcalc_init();
  287. SEI();
  288. for(i=0;i<3;i++)
  289.    led_buff[i]=seg_table[8];
  290. for(i=0;i<200;i++)
  291.    timer2_init();
  292.    adc_old=0;
  293.    adc_rel=0;
  294.   while(1)
  295.      {
  296.                 if(adc_old!=adc_rel)//ADC更新完毕就执行数据处理
  297.                  {
  298.                       adc_old=adc_rel;
  299.                           pidcalc();
  300.                           pidcalc_zizheng();
  301.                             if(k<5)
  302.                                     {
  303.                                         k++;
  304.                                         adc_ol+=adc_old;
  305.                                         }
  306.                                 else
  307.                                     {
  308.                                         adc_o=adc_ol/5;
  309.                                         adc_ol=0;
  310.                                         k=0;
  311.                                         }        
  312.                           }  
  313.             ADCtoBCD(adc_o);  
  314.          }
  315. }
复制代码






回复

使用道具 举报

ID:73848 发表于 2016-2-15 16:03 | 显示全部楼层
最近在做加热垫的控温程序,希望用上PID让曲线好看一点
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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