PWM(Pulse Width Modulation)是脈沖寬度調制的英文單詞的縮寫。下面這段話是通信百科中對其的定義:
脈沖寬度調制(PWM)是利用微處理器的數(shù)字輸出來對模擬電路進行控制的一種非常有效的技術,廣泛應用在從測量、通信到功率控制與變換的許多領域中。脈寬調制是開關型穩(wěn)壓電源中的術語。這是按穩(wěn)壓的控制方式分類的,除了PWM型,還有PFM型和PWM、PFM混合型。脈寬調制式開關型穩(wěn)壓電路是在控制電路輸出頻率不變的情況下,通過電壓反饋調整其占空比,從而達到穩(wěn)定輸出電壓的目的。
讀起來有點晦澀難懂。其實簡單的說來,PWM技術就是通過調整一個周期固定的方波的占空比,來調節(jié)輸出電壓的平均當電壓,電流或者功率等被控量。我們可以用一個水龍頭來類比,把1S時間分成50等份,即每一個等份20MS。在這20MS時間里如果我們把水龍頭水閥一直打開,那么在這20MS里流過的水肯定是最多的,如果我們把水閥打開15MS,剩下的5MS關閉水閥,那么流出的水相比剛才20MS全開肯定要小的多。同樣的道理,我們可以通過控制20MS時間里水閥開啟的時間的長短來控制流過的水的多少。那么在1S內平均流出的水流量也就可以被控制了。
當我們調整PWM的占空比時,就會引起電壓或者電流的改變,LED的明暗狀態(tài)就會隨之發(fā)生相應的變化,聽起來好像可以通過這種方法來實現(xiàn)我們想要的漸明漸暗的效果。讓我們來試一下吧。
大家都知道人眼有一個臨界頻率,當LED的閃爍頻率達到一定的時候,人眼就分辨不出LED是否在閃爍了。就像我們平?措娨曇粯樱雌饋懋嬅媸沁B續(xù)的,實質不是這個樣子,所有連續(xù)動作都是一幀幀靜止的畫面在1S的時間里快速播放出來,譬如每秒24幀的速度播放,由于人眼的視覺暫留效應,看起來畫面就是連續(xù)的了。同樣的道理,為了讓我們的LED在變化的過程中,我們感覺不到其在閃爍,可以將其閃爍的頻率定在50Hz以上。同時為了看起來明暗過渡的效果更加明顯,我們在這里定義其變化范圍為0~99(100等分).即最亮的時候其灰度等級為99,為0的時候最暗,也就是熄滅了。
于是乎我們定義PWM的占空比上限為99, 下限定義為0
#define LED_PWM_LIMIT_MAX 99
#define LED_PWM_LIMIT_MIN 0
假定我們LED的閃爍頻率為50HZ,而亮度變化的范圍為0~99共100等分。則每一等分所占用的時間為 1/(50*100) = 200us 即我們在改變LED的亮滅狀態(tài)時,應該是在200us整數(shù)倍時刻時。在這里我們用單片機的定時器產生200us的中斷,同時每20MS調整一次LED的占空比。這樣在20MS * 100 = 2S的時間內LED可以從暗逐漸變亮,在下一個2S內可以從亮逐漸變暗,然后不斷循環(huán)。
由于大部分的內容都可以在中斷中完成,因此,我們的大部分代碼都在Timer.c這個文件中編寫,主函數(shù)中除了初始化之外,就是一個空的死循環(huán)。
Timer.c內容如下。
#include <reg52.h>
#include "MacroAndConst.h"
#define LED P0 //定義LED接口
#define LED_ON() LED = 0x00 ; //所有LED亮
#define LED_OFF() LED = 0xff ; //所有LED熄滅
#define LED_PWM_LIMIT_MAX 99
#define LED_PWM_LIMIT_MIN 0
static uint8 s_u8TimeCounter = 0 ; //中斷計數(shù)
static uint8 s_u8LedDirection = 0 ; //LED方向控制 0 :漸亮 1 :漸滅
static int8 s_s8LedPWMCounter = 0 ; //LED占空比
void Timer0Init(void)
{
TMOD &= 0xf0 ;
TMOD |= 0x01 ; //定時器0工作方式1
TH0 = 0xff ; //定時器初始值(200us中斷一次)
TL0 = 0x47 ;
TR0 = 1 ;
ET0 = 1 ;
}
void Time0Isr(void) interrupt 1
{
static int8 s_s8PWMCounter = 0 ;
TH0 = 0xff ; //定時器重新賦初值
TL0 = 0x47 ;
if(++s_u8TimeCounter >= 100) //每20MS調整一下LED的占空比
{
s_u8TimeCounter = 0 ;
//如果是漸亮方向變化,則占空比遞增
if((s_s8LedPWMCounter <= LED_PWM_LIMIT_MAX) &&(0 == s_u8LedDirection))
{
s_s8LedPWMCounter++ ;
if(s_s8LedPWMCounter > LED_PWM_LIMIT_MAX)
{
s_u8LedDirection = 1 ;
s_s8LedPWMCounter = LED_PWM_LIMIT_MAX ;
}
}
//如果是漸暗方向變化,則占空比遞漸
if((s_s8LedPWMCounter >= LED_PWM_LIMIT_MIN) &&(1 == s_u8LedDirection))
{
s_s8LedPWMCounter-- ;
if(s_s8LedPWMCounter < LED_PWM_LIMIT_MIN)
{
s_u8LedDirection = 0 ;
s_s8LedPWMCounter = LED_PWM_LIMIT_MIN ;
}
}
s_s8PWMCounter = s_s8LedPWMCounter ; //獲取LED的占空比
}
if(s_s8PWMCounter > 0) //占空比大于0,則點亮LED,否則熄滅LED
{
LED_ON() ;
s_s8PWMCounter-- ;
}
else
{
LED_OFF();
}
}
其實PWM技術在我們實際生活中應用的非常多。比較典型的應用就是控制電機的轉速,控制充電電流的大小,等等。而隨著技術的發(fā)展,也出現(xiàn)了其他類型的PWM技術,如相電壓PWM,線電壓PWM,SPWM等等,如果有興趣可以到網(wǎng)上去獲取相應資料學習。
|