本帖最后由 lern01 于 2018-12-14 19:59 編輯
一個PWM調(diào)壓程序,怎么編寫PID函數(shù)來調(diào)節(jié)電壓?也望大老能指點,十分地感謝!
附單片機程序:
- #include "stc12c5a60s2.h"
- #include "intrins.h"
- #define ADC_POWER 0x80 //ADC電源控制位,0-關閉,1-打開
- #define ADC_FLAG 0x10 //ADC結束標志位
- #define ADC_START 0x08 //ADC啟動控制位
- #define ADC_SPEEDLL 0x00 //540 clocks--選擇轉(zhuǎn)換速度
- unsigned char Lcd_Dis1_table[] = {"SetValue: "}; //第一行顯示框架
- unsigned char Lcd_Dis2_table[] = {"Voltage : "}; //第二行顯示框架
- float Show, NUM;
- unsigned char volt = 0; //作為顯示的數(shù)據(jù)
- bit flag300ms = 1; //300ms定時標志
- unsigned char T0RH = 0; //T0重載值的高字節(jié)
- unsigned char T0RL = 0; //T0重載值的低字節(jié)
- //PID算法公式:
- sbit key1 = P2^7; //定義按鍵1
- sbit key2 = P2^6; //定義按鍵2
- sbit key3 = P2^5; //定義按鍵3
- sbit key4 = P2^4; //定義按鍵4
- sbit key_gnd = P2^3; //定義接地
- void ConfigTimer0(unsigned int ms);
- void InitADC();
- void InitPWM();
- void PWM0_change(unsigned char type, unsigned char change);
- void Delay(unsigned int n);
- void KeyAction(unsigned char keycod);
- void NumToString(unsigned char num);
- void ValueToString(unsigned char *str, unsigned int val);
- unsigned int GetADCResult(unsigned char ch); //讀取輸入電壓模數(shù)轉(zhuǎn)換函數(shù)
- extern void KeyScan();
- extern void KeyDriver();
- extern void InitLcd1602();
- extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- void main()
- {
- unsigned int val;
- unsigned char str[10];
- key_gnd = 0;
- EA = 1; //開總中斷
- ConfigTimer0(10); //配置T0定時10ms
- InitADC();
- InitPWM();
- InitLcd1602();
- LcdShowStr(0, 0, Lcd_Dis1_table);
- LcdShowStr(0, 1, Lcd_Dis2_table);
- while(1)
- {
- KeyDriver();
- if(flag300ms)
- {
- flag300ms = 0;
- val = GetADCResult(7);
- ValueToString(str, val);
- LcdShowStr(9, 1, str);
- }
- NumToString(volt);
- /* NUM = 10 * NUM;
- Show = ldata;
- if((NUM < (Show - 0.1))||(NUM > (Show + 0.1)))
- {
- if(NUM < (Show - 0.1))
- {
- if((Show - 0.1) - NUM > 1)
- {
- PWM1_change(1, 0X05);
- }
- else
- {
- PWM1_change(1, 0X01);
- }
- }
- else
- {
- if(NUM - (Show + 0.1) > 1)
- {
- PWM1_change(0, 0X05);
- }
- else
- {
- PWM1_change(0, 0X01);
- }
- }
- Delay(500);
- }
- else
- {
- Delay(2000);
- } */
- }
- }
- void NumToString(unsigned char num)
- {
- unsigned char str[10];
- str[0] = num/100 + '0';
- str[1] = num/10%100 + '0';
- str[2] = '.';
- str[3] = num%10 + '0';
- str[4] = 'V';
- str[5] = '\0';
- LcdShowStr(9, 0, str);
- }
- /*------------ADC 取值 --------------*/
- unsigned int GetADCResult(unsigned char ch) //ch--AD輸入通道
- {
- unsigned int val = 0;
- ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START |ch;
- _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
- while(!(ADC_CONTR & ADC_FLAG)); //等待AD轉(zhuǎn)換完成
- ADC_CONTR &= ~ADC_FLAG; //關閉ADC
- val = ADC_RES;
- val = (val << 2) | (0x03 & ADC_RESL);
- return val; //返回A/D轉(zhuǎn)換結果
- }
- void InitADC()
- {
- P1ASF = 0x80; //設置P1.7為AD輸入通道
- ADC_RES = 0; //清除高8位RES和低2位RESL
- ADC_RESL = 0;
- ADC_CONTR = ADC_POWER | ADC_SPEEDLL;
- Delay(20); //打開ADC電源并延時
- }
- /* ADC轉(zhuǎn)換值轉(zhuǎn)為實際電壓值的字符串形式,str-字符串指針,val-AD轉(zhuǎn)換值 */
- void ValueToString(unsigned char *str, unsigned int val)
- {
- NUM = (val * 5.03) / 1024.0;
- str[0] = (unsigned int)NUM/10 + '0';
- str[1] = (unsigned int)NUM%10 + '0';
- str[2] = '.';
- str[3] = (unsigned int)(NUM*10)%10 + '0';
- str[4] = (unsigned int)(NUM*100)%10 + '0';
- str[5] = 'V';
- str[6] = '\0';
- }
- void InitPWM()
- {
- CCON = 0; //Initial PCA control register
- //PCA timer stop runing
- //Clear CF flag
- //Clear all module interrupt flag
- CL = CH = 0; //Reset PCA base timer
- CMOD = 0x02; //Set PCA timer clock source as Fousc/2 0X00:以系統(tǒng)時鐘/12 為時鐘源,0X02:系統(tǒng)時鐘/2,0x08:系統(tǒng)時鐘
- //Disable PCA timer overflow interrupt
- CCAP0L = CCAP0H = 0xff; //起始占空比,0XC0:占空比為25%,0X80:占空比為50%,0X40:占空比為75%
- PCA_PWM0 = 0x00;
- CCAPM0 = 0x42;//0X42:8位PWM P1.4輸出,無中斷;0X53:8位PWM輸出,下降沿產(chǎn)生中斷;0X63:上升沿產(chǎn)生中斷;0X73:跳變沿產(chǎn)生中斷
- CR = 1; //計時器開始工作
- }
- void PWM0_change(unsigned char type, unsigned char change) //type=0減占空比,1增加占空比 change: 0X0C約5%,0X05約2%
- {
- if(type == 0)
- {
- if(CCAP0L < 0xff) //占空比 < 90%
- {
- CCAP0L += change;
- CCAP0H += change;
- }
- }
- else
- {
- if(CCAP0L > 0x00) // > 10%
- CCAP0L -= change;
- CCAP0H -= change;
- }
- }
- void KeyAction(unsigned char keycod)
- {
- switch(keycod)
- {
- case 0x26:
- if(volt < 50);
- {
- volt++;
- PWM0_change(1, 0x05);
- }
- break;
- case 0x28:
- if(volt > 0)
- {
- volt--;
- PWM0_change(0, 0x05);
- }
- break;
-
- case 0x27:
- if(volt < 50)
- {
- volt += 10;
- PWM0_change(1, 0x0C);
- }
- break;
- case 0x25:
- if(volt > 0)
- {
- volt -= 10;
- PWM0_change(0, 0x0C);
- }
- break;
- default: break;
- }
- }
- void Delay(unsigned int n)
- {
- unsigned int x;
- while (n--)
- {
- x = 500;
- while (x--);
- }
- }
- /*
- void DelayMs(unsigned char ms) //延時程序
- {
- unsigned int i;
- while(ms--)
- {
- for(i=0; i<850; i++)
- ;
- }
- }
- */
- /* 配置并啟動T0,ms-T0定時時間 */
- void ConfigTimer0(unsigned int ms)
- {
- unsigned long tmp; //臨時變量
-
- tmp = 11059200 / 12; //定時器計數(shù)頻率
- tmp = (tmp * ms) / 1000; //計算所需的計數(shù)值
- tmp = 65536 - tmp; //計算定時器重載值
- tmp = tmp + 12; //補償中斷響應延時造成的誤差
- T0RH = (unsigned char)(tmp>>8); //定時器重載值拆分為高低字節(jié)
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0; //清零T0的控制位
- TMOD |= 0x01; //配置T0為模式1
- TH0 = T0RH; //加載T0重載值
- TL0 = T0RL;
- ET0 = 1; //使能T0中斷
- TR0 = 1; //啟動T0
- }
- /* T0中斷服務函數(shù),執(zhí)行300ms定時 */
- void InterruptTimer0() interrupt 1
- {
- static unsigned char tmr300ms = 0;
-
- TH0 = T0RH; //重新加載重載值
- TL0 = T0RL;
- KeyScan();
- tmr300ms++;
- if (tmr300ms >= 30) //定時300ms
- {
- tmr300ms = 0;
- flag300ms = 1;
- }
- }
復制代碼
|