找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4406|回復: 1
打印 上一主題 下一主題
收起左側(cè)

一個單片機PWM調(diào)壓程序,怎么編寫PID函數(shù)調(diào)節(jié)電壓?

[復制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:160658 發(fā)表于 2018-12-14 19:11 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本帖最后由 lern01 于 2018-12-14 19:59 編輯

一個PWM調(diào)壓程序,怎么編寫PID函數(shù)來調(diào)節(jié)電壓?也望大老能指點,十分地感謝!

附單片機程序:

  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--選擇轉(zhuǎn)換速度
  7. unsigned char Lcd_Dis1_table[] = {"SetValue:       "};     //第一行顯示框架
  8. unsigned char Lcd_Dis2_table[] = {"Voltage :       "};     //第二行顯示框架

  9. float Show, NUM;
  10. unsigned char volt = 0;  //作為顯示的數(shù)據(jù)
  11. bit flag300ms = 1;       //300ms定時標志
  12. unsigned char T0RH = 0;  //T0重載值的高字節(jié)
  13. unsigned char T0RL = 0;  //T0重載值的低字節(jié)
  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); //讀取輸入電壓模數(shù)轉(zhuǎn)換函數(shù)

  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轉(zhuǎn)換完成
  108.     ADC_CONTR &= ~ADC_FLAG;               //關閉ADC
  109.     val = ADC_RES;
  110.     val = (val << 2) | (0x03 & ADC_RESL);

  111.     return val;   //返回A/D轉(zhuǎn)換結果
  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轉(zhuǎn)換值轉(zhuǎn)為實際電壓值的字符串形式,str-字符串指針,val-AD轉(zhuǎn)換值 */
  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:以系統(tǒng)時鐘/12 為時鐘源,0X02:系統(tǒng)時鐘/2,0x08:系統(tǒng)時鐘
  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輸出,下降沿產(chǎn)生中斷;0X63:上升沿產(chǎn)生中斷;0X73:跳變沿產(chǎn)生中斷
  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;      //定時器計數(shù)頻率
  226.     tmp = (tmp * ms) / 1000;  //計算所需的計數(shù)值
  227.     tmp = 65536 - tmp;        //計算定時器重載值
  228.     tmp = tmp + 12;           //補償中斷響應延時造成的誤差
  229.     T0RH = (unsigned char)(tmp>>8);  //定時器重載值拆分為高低字節(jié)
  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中斷服務函數(shù),執(zhí)行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. }
復制代碼


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

沙發(fā)
ID:405033 發(fā)表于 2018-12-18 13:57 | 只看該作者
pid函數(shù)網(wǎng)上都有的,你可以去網(wǎng)上找找,然后把pid函數(shù)返回來的值傳給所要控制的函數(shù)就可以了
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表