使用兩個定時器實現PWM(脈寬調製)——呼吸燈
阿新 • • 發佈:2019-02-09
PWM(脈寬調製)大家可以上網查查,其原理講解很多。為了更好的學習PWM,我特意參照別人寫的文章,自己也寫了一份程式碼來實現PWM。程式碼如下:
#include <stc12c5a60s2.h> unsigned long cnt; unsigned int cnt_T1; unsigned int high; unsigned int low; unsigned char TH0_high; unsigned char TL0_high; unsigned char TH0_low; unsigned char TL0_low; unsigned char T1H1; unsigned char T1L1; unsigned char flag=0; unsigned char duty[19] = {5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95}; unsigned char index=0; void config_Fy_and_dy(unsigned char fy, unsigned char dy); void config_Timer1(unsigned char ms); void modify_duty(unsigned char dy); sbit PWM_OUT = P2^5; void main() { TMOD = 0X11; // 定時器0/1都工作在方式1,是2^16計數 EA=1; config_Fy_and_dy(100, 20); config_Timer1(50); while(1); } void config_Fy_and_dy(unsigned char fy, unsigned char dy) // 輸入頻率fy,佔空比dy { cnt = (11059200/fy)/12; // 要產生頻率為fy,定時器0所要計的數值 high = (cnt*dy)/100; // 計算出高電平所要計的數值 low = cnt - high; // 計算出低電平所要計的數值 high = 65536 - high; // 確定定時器0,從哪個初值開始計時,記錄的是高電平 low = 65536 - low; // 確定定時器0,從哪個初值開始計時,記錄的是低電平 TH0_high = (unsigned char)(high>>8); // 高電平,給TH0預備重灌初值 TL0_high = (unsigned char)high; // 高電平,給TL0預備重灌初值 TH0_low = (unsigned char)(low>>8); // 低電平,給TH0預備重灌初值 TL0_low = (unsigned char)low; // 低電平,給TL0預備重灌初值 TH0 = TH0_high; TL0 = TL0_high; PWM_OUT = 1; ET0 = 1; TR0 = 1; } void config_Timer1(unsigned char ms) { unsigned long temp; temp = 11059200/1000; temp = (temp*ms)/12; cnt_T1 = 65536 - temp; T1H1 = (unsigned char)(cnt_T1>>8); T1L1 = (unsigned char)cnt_T1; TH1 = T1H1; TL1 = T1L1; ET1=1; TR1=1; } void modify_duty(unsigned char dy) { high = (cnt*dy)/100; low = cnt - high; high = 65536 - high; low = 65536 - low; TH0_high = (unsigned char)(high>>8); // 高電平,給TH0預備重灌初值 TL0_high = (unsigned char)high; // 高電平,給TL0預備重灌初值 TH0_low = (unsigned char)(low>>8); // 低電平,給TH0預備重灌初值 TL0_low = (unsigned char)low; // 低電平,給TL0預備重灌初值 } void T0_Timer0() interrupt 1 { if(PWM_OUT==0) // 準備產生高電平 { TH0 = TH0_high; // 高電平產生 初值重灌 TL0 = TL0_high; PWM_OUT = 1; } else { TH0 = TH0_low; // 低電平產生 初值重灌 TL0 = TL0_low; PWM_OUT = 0; } } void T1_Timer1() interrupt 3 { TH1 = T1H1; TL1 = T1L1; modify_duty(duty[index]); if(0 == flag) // flag=0時,表示呼吸燈由暗變亮 { index++; if(index >=18) { flag = 1; } } else { index--; if(index <=0) { flag=0; } } }
其實,PWM這種實現方法並不適合程式設計,因為它佔用了兩個定時器中斷口,會影響程式的執行效率。
我是通過兩個定時器來更好的掌握PWM的調製原理。
接下來,我將會通過微控制器(STC12C5A60S2)內部模組實現PWM,實現比較簡單,將在下個文章來完成。