单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

一个单片机PWM调压程序,怎么编写PID函数调节电压?

[复制链接]
lern01 发表于 2018-12-14 19:11 | 显示全部楼层 |阅读模式
本帖最后由 lern01 于 2018-12-14 19:59 编辑

一个PWM调压程序,怎么编写PID函数来调节电压?也望大老能指点,十分地感谢!

附单片机程序:

  1. #include "stc12c5a60s2.h"                                                   
  2. #include "intrins.h"  

  3. #define ADC_POWER   0x80  //ADC电源控制位,0-关闭,1-打开
  4. #define ADC_FLAG    0x10  //ADC结束标志位
  5. #define ADC_START   0x08  //ADC启动控制位
  6. #define ADC_SPEEDLL 0x00  //540 clocks--选择转换速度
  7. unsigned char Lcd_Dis1_table[] = {"SetValue:       "};     //第一行显示框架
  8. unsigned char Lcd_Dis2_table[] = {"Voltage :       "};     //第二行显示框架

  9. float Show, NUM;
  10. unsigned char volt = 0;  //作为显示的数据
  11. bit flag300ms = 1;       //300ms定时标志
  12. unsigned char T0RH = 0;  //T0重载值的高字节
  13. unsigned char T0RL = 0;  //T0重载值的低字节
  14.                                                   //PID算法公式:
  15. sbit key1 = P2^7;        //定义按键1
  16. sbit key2 = P2^6;        //定义按键2
  17. sbit key3 = P2^5;        //定义按键3
  18. sbit key4 = P2^4;        //定义按键4
  19. sbit key_gnd = P2^3;     //定义接地

  20. void ConfigTimer0(unsigned int ms);
  21. void InitADC();
  22. void InitPWM();
  23. void PWM0_change(unsigned char type, unsigned char change);
  24. void Delay(unsigned int n);
  25. void  KeyAction(unsigned char keycod);
  26. void NumToString(unsigned char num);
  27. void ValueToString(unsigned char *str, unsigned int val);
  28. unsigned int GetADCResult(unsigned char ch); //读取输入电压模数转换函数

  29. extern void KeyScan();
  30. extern void KeyDriver();
  31. extern void InitLcd1602();
  32. extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

  33. void main()
  34. {
  35.     unsigned int val;
  36.     unsigned char str[10];

  37.     key_gnd = 0;
  38.     EA = 1;            //开总中断
  39.     ConfigTimer0(10);  //配置T0定时10ms
  40.     InitADC();
  41.     InitPWM();
  42.     InitLcd1602();
  43.     LcdShowStr(0, 0, Lcd_Dis1_table);
  44.     LcdShowStr(0, 1, Lcd_Dis2_table);
  45.     while(1)
  46.     {
  47.         KeyDriver();        
  48.         if(flag300ms)
  49.         {
  50.             flag300ms = 0;
  51.             val = GetADCResult(7);
  52.             ValueToString(str, val);
  53.             LcdShowStr(9, 1, str);
  54.         }
  55.         NumToString(volt);
  56. /*        NUM = 10 * NUM;        
  57.         Show = ldata;
  58.         if((NUM < (Show - 0.1))||(NUM > (Show + 0.1)))
  59.         {         
  60.             if(NUM < (Show - 0.1))
  61.             {
  62.                 if((Show - 0.1) - NUM > 1)
  63.                 {
  64.                     PWM1_change(1, 0X05);
  65.                 }
  66.                 else
  67.                 {
  68.                     PWM1_change(1, 0X01);
  69.                 }
  70.             }
  71.             else
  72.             {
  73.                 if(NUM - (Show + 0.1) > 1)
  74.                 {
  75.                     PWM1_change(0, 0X05);
  76.                 }
  77.                 else
  78.                 {                                                  
  79.                     PWM1_change(0, 0X01);
  80.                 }
  81.             }
  82.             Delay(500);
  83.         }               
  84.         else
  85.         {
  86.             Delay(2000);
  87.         }           */
  88.     }
  89. }

  90. void NumToString(unsigned char num)
  91. {
  92.     unsigned char str[10];

  93.     str[0] = num/100 + '0';
  94.     str[1] = num/10%100 + '0';
  95.     str[2] = '.';
  96.     str[3] = num%10 + '0';
  97.     str[4] = 'V';
  98.     str[5] = '\0';
  99.     LcdShowStr(9, 0, str);
  100. }
  101. /*------------ADC 取值 --------------*/
  102. unsigned int GetADCResult(unsigned char ch)     //ch--AD输入通道
  103. {
  104.     unsigned int val = 0;

  105.     ADC_CONTR =    ADC_POWER | ADC_SPEEDLL | ADC_START |ch;
  106.     _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
  107.     while(!(ADC_CONTR & ADC_FLAG));       //等待AD转换完成
  108.     ADC_CONTR &= ~ADC_FLAG;               //关闭ADC
  109.     val = ADC_RES;
  110.     val = (val << 2) | (0x03 & ADC_RESL);

  111.     return val;   //返回A/D转换结果
  112. }

  113. void InitADC()
  114. {
  115.     P1ASF = 0x80;         //设置P1.7为AD输入通道
  116.     ADC_RES = 0;         //清除高8位RES和低2位RESL
  117.     ADC_RESL = 0;
  118.     ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
  119.     Delay(20);          //打开ADC电源并延时
  120. }
  121. /* ADC转换值转为实际电压值的字符串形式,str-字符串指针,val-AD转换值 */
  122. void ValueToString(unsigned char *str, unsigned int val)
  123. {
  124.     NUM = (val * 5.03) / 1024.0;

  125.     str[0] = (unsigned int)NUM/10 + '0';
  126.     str[1] = (unsigned int)NUM%10 + '0';
  127.     str[2] = '.';
  128.     str[3] = (unsigned int)(NUM*10)%10 + '0';
  129.     str[4] = (unsigned int)(NUM*100)%10 + '0';
  130.     str[5] = 'V';
  131.     str[6] = '\0';        
  132. }

  133. void InitPWM()
  134. {
  135.     CCON = 0;        //Initial PCA control register
  136.                     //PCA timer stop runing
  137.                     //Clear CF flag
  138.                     //Clear all module interrupt flag
  139.     CL = CH = 0;    //Reset PCA base timer
  140.     CMOD = 0x02;     //Set PCA timer clock source as Fousc/2    0X00:以系统时钟/12 为时钟源,0X02:系统时钟/2,0x08:系统时钟
  141.                     //Disable PCA timer overflow interrupt
  142.     CCAP0L = CCAP0H = 0xff;     //起始占空比,0XC0:占空比为25%,0X80:占空比为50%,0X40:占空比为75%
  143.     PCA_PWM0 = 0x00;
  144.     CCAPM0 = 0x42;//0X42:8位PWM P1.4输出,无中断;0X53:8位PWM输出,下降沿产生中断;0X63:上升沿产生中断;0X73:跳变沿产生中断
  145.     CR = 1;    //计时器开始工作
  146. }

  147. void PWM0_change(unsigned char type, unsigned char change) //type=0减占空比,1增加占空比 change: 0X0C约5%,0X05约2%
  148. {
  149.    if(type == 0)
  150.    {   
  151.         if(CCAP0L < 0xff) //占空比 < 90%
  152.         {
  153.             CCAP0L += change;
  154.             CCAP0H += change;
  155.         }
  156.    }                 
  157.    else
  158.    {   
  159.            if(CCAP0L > 0x00)  // > 10%               
  160.         CCAP0L -= change;
  161.         CCAP0H -= change;                        
  162.    }  
  163. }

  164. void  KeyAction(unsigned char keycod)
  165. {
  166.     switch(keycod)
  167.     {
  168.         case 0x26:
  169.             if(volt < 50);
  170.             {
  171.                 volt++;
  172.                 PWM0_change(1, 0x05);
  173.             }
  174.             break;
  175.         case 0x28:
  176.             if(volt > 0)
  177.             {
  178.                 volt--;
  179.                 PWM0_change(0, 0x05);
  180.             }
  181.             break;
  182.         
  183.         case 0x27:
  184.             if(volt < 50)
  185.             {
  186.                 volt += 10;
  187.                 PWM0_change(1, 0x0C);
  188.             }
  189.             break;
  190.         case 0x25:
  191.             if(volt > 0)
  192.             {
  193.                 volt -= 10;
  194.                 PWM0_change(0, 0x0C);
  195.             }
  196.             break;         
  197.         default: break;
  198.     }
  199. }

  200. void Delay(unsigned int n)                                                                                 
  201. {
  202.     unsigned int x;

  203.     while (n--)
  204.     {
  205.        x = 500;
  206.        while (x--);
  207.     }
  208. }
  209. /*
  210. void DelayMs(unsigned char ms) //延时程序
  211. {      
  212.     unsigned int i;

  213.     while(ms--)
  214.     {
  215.        for(i=0; i<850; i++)
  216.                ;
  217.     }
  218. }
  219.      */
  220. /* 配置并启动T0,ms-T0定时时间 */
  221. void ConfigTimer0(unsigned int ms)
  222. {
  223.     unsigned long tmp;  //临时变量
  224.    
  225.     tmp = 11059200 / 12;      //定时器计数频率
  226.     tmp = (tmp * ms) / 1000;  //计算所需的计数值
  227.     tmp = 65536 - tmp;        //计算定时器重载值
  228.     tmp = tmp + 12;           //补偿中断响应延时造成的误差
  229.     T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
  230.     T0RL = (unsigned char)tmp;
  231.     TMOD &= 0xF0;   //清零T0的控制位
  232.     TMOD |= 0x01;   //配置T0为模式1
  233.     TH0 = T0RH;     //加载T0重载值
  234.     TL0 = T0RL;
  235.     ET0 = 1;        //使能T0中断
  236.     TR0 = 1;        //启动T0
  237. }
  238. /* T0中断服务函数,执行300ms定时 */
  239. void InterruptTimer0() interrupt 1
  240. {
  241.     static unsigned char tmr300ms = 0;
  242.    
  243.     TH0 = T0RH;  //重新加载重载值
  244.     TL0 = T0RL;
  245.     KeyScan();
  246.     tmr300ms++;
  247.     if (tmr300ms >= 30)  //定时300ms
  248.     {
  249.         tmr300ms = 0;
  250.         flag300ms = 1;
  251.     }
  252. }
复制代码


回复

使用道具 举报

疯子本人 发表于 2018-12-18 13:57 | 显示全部楼层
pid函数网上都有的,你可以去网上找找,然后把pid函数返回来的值传给所要控制的函数就可以了
回复

使用道具 举报

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

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51hei电子论坛2群 联系QQ:125739409;技术交流QQ群219535678

Powered by 单片机教程网

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