51單片機(jī)軟模PWM誤差率之研究
軟模PWM輸出一般有兩種方式:利用定時器0控制PWM頻率輸出,結(jié)合定時器1控制占空比,這是其一;第二種方式,僅使用一個定時器,工作于16bit手工裝載模式,同時控制輸出頻率和占空比,這種方式不占用太多資源,而且實現(xiàn)起來也不失其靈活性,俺本人就建議采用這樣方式,建議剔除第一種方式。本文的研究也是基于方式二展開的。
本文引用地址:http://www.ex-cimer.com/article/201611/315617.htm網(wǎng)絡(luò)上常見MCS-51軟模輸出PWM波的文章,而至于對這種方式實現(xiàn)的可行性或者說局限性,卻無一例外的被小覷了。本文就51單片機(jī)模擬PWM波輸出的劣根性進(jìn)行了探討,不正之處,歡迎大家提點(diǎn)。
1、產(chǎn)生PWM波的子模塊例程(PWM.C):
#include "Includes.h" //文件包含
/*******************************************************************************
*** 函 數(shù) 名: extern void PWM_Init(void)
*** 功能描述: PWM參數(shù)初始化;
*** 全局變量: NO !
*** 輸 入: NO !
*** 輸 出: NO !
*** 創(chuàng) 建 人:huangtiexiong 日期:2006-11-28
*** 修 改 人: 日期:2006-11-28
*** 函數(shù)說明: 外部函數(shù);
/******************************************************************************/
extern void PWM_Init(void)
{
TMOD &= 0x0f; TMOD |= 0x10; //定時器1方式1,16位手動裝載模式;
TH1 = (65536 - PWM_HIGH) / 256 ;
TL1 = (65536 - PWM_HIGH) % 256 ;
PWM_PIN = 1; //初始化先輸出高電平;
ET1 = 1; //開定時器1中斷;
EA = 1; TR1 = 1; //啟動定時器1;
}
/*******************************************************************************
*** 函 數(shù) 名: extern void Timer1_ISR(void) interrupt 3
*** 功能描述: 定時器1中斷服務(wù)例程;
*** 全局變量: NO !
*** 輸 入: NO !
*** 輸 出: NO !
*** 創(chuàng) 建 人:huangtiexiong 日期:2006-11-28
*** 修 改 人: 日期:2006-11-28
*** 函數(shù)說明: 中斷服務(wù)函數(shù);
PWM_LOW: 低電平持續(xù)時間us;
PWM_HIGH: 高電平持續(xù)時間us;
PWM_PIN: PWM波輸出引腳,接P1.7;
/******************************************************************************/
extern void Timer1_ISR(void) interrupt 3
{
if(PWM_PIN) {PWM_PIN = 0;
TH1 = (65536 - PWM_LOW) / 256 ;
TL1 = (65536 - PWM_LOW) % 256 ; }
else {PWM_PIN = 1;
TH1 = (65536 - PWM_HIGH) / 256 ;
TL1 = (65536 - PWM_HIGH) % 256 ; }
}
/*******************************************************************************
**** End Of File
*******************************************************************************/
其中斷服務(wù)例程在Keil C中編譯后的匯編代碼如下(默認(rèn)8級代碼優(yōu)化):
; FUNCTION Timer1_ISR (BEGIN)
; SOURCE LINE # 43
; SOURCE LINE # 45
0000 309709 JNB PWM_PIN,?C0002
; SOURCE LINE # 46
; SOURCE LINE # 47
0003 C297 CLR PWM_PIN
; SOURCE LINE # 48
0005 758DFF MOV TH1,#0FFH
; SOURCE LINE # 49
0008 758BB5 MOV TL1,#0B5H
; SOURCE LINE # 50
000B 32 RETI
000C ?C0002:
; SOURCE LINE # 52
; SOURCE LINE # 53
000C D297 SETB PWM_PIN
; SOURCE LINE # 54
000E 758DFF MOV TH1,#0FFH
; SOURCE LINE # 55
0011 758BE7 MOV TL1,#0E7H
; SOURCE LINE # 56
; SOURCE LINE # 57
0014 ?C0004:
0014 32 RETI
; FUNCTION Timer1_ISR (END)
2、主入口模塊(BootLoader.c):在主模塊main函數(shù)中,首先清零PWM_PIN引腳,接著調(diào)用PWM_Init()例程,然后就是一個簡單的空循環(huán),其經(jīng)由Keil C編譯后的匯編代碼為:
; FUNCTION main (BEGIN)
0000 C297 CLR PWM_PIN
; SOURCE LINE # 31
0002 120000 E LCALL PWM_Init
0005 ?C0001:
; SOURCE LINE # 32
0005 80FE SJMP ?C0001
; FUNCTION main (END)
3、另外還有兩個重要的參數(shù)宏,定義在在PWM模塊的頭文件PWM.H中:
#define PWM_CYCLE 100 //100us,則PWM波的頻率為10kHz;
#define PWM_HIGH 25 //高電平持續(xù)時間,占空比1/4;
#define PWM_LOW 75 //低電平持續(xù)時間;
4、首先取PWM_CYCLE, PWM_HIGH, PWM_LOW分別為100、25、75,則設(shè)定的PWM波頻率為10kHz,占空比0.25。編譯連接正確后在Proteus中仿真(單片機(jī)晶振頻率設(shè)置為12.0mHz),抓出一個周期的波形圖如下:
可計算:高電平持續(xù)時間為810us-773us=37us,低電平持續(xù)時間897us-810us=87us,實際輸出PWM波的占空比為:37/(37+87)=0.298387,占空比誤差率為(0.298387-0.25)/0.25=19.35%;一般工程實踐要求的誤差率不超過5%,顯然這19.35%的誤差率是不符合要求的。(注-Proteus的圖形仿真精度:對模擬量的采樣最小間隔為1e-18s,典型值為1e-09,參見Proteus使用手冊。)
5、接著取PWM_CYCLE, PWM_HIGH, PWM_LOW分別為10、2、8,則設(shè)定的PWM波頻率為100kHz,占空比0.2。編譯連接正確后在Proteus中仿真(12.0mHz晶振)后抓出的單個周期波形圖如下:
由圖可計算得:實際輸出的PWM_HIGH, PWM_LOW分別為15、19,占空比0.4412,占空比誤差率120.59%,也就是說,實際輸出的PWM波占空比翻番了。
6、繼續(xù)取PWM_CYCLE, PWM_HIGH, PWM_LOW分別為1000、250、750,則設(shè)定的PWM波頻率為1kHz,占空比0.25。編譯連接正確后在Proteus中仿真(12.0mHz晶振)后抓出的單個周期波形圖如下:
由圖可計算:實際輸出的PWM_HIGH, PWM_LOW分別為262、762,占空比0.2558,占空比誤差率2.34%(<5%)。
7、綜上,本文得出的結(jié)論為:在51單片機(jī)上采用軟件模擬的方式輸出PWM波,其頻率越大,占空比誤差越不可收拾;在PWM波形頻率不是很高的情況下(比如小于1kHz),采用軟模方式輸出PWM是完全可行的。
8、為什么會出現(xiàn)這種情況呢 ?首先將每次仿真調(diào)試,程序中設(shè)定的PWM_HIGH, PWM_LOW值及實際輸出值列表如下:
比較發(fā)現(xiàn)實際輸出的PWM波形時間參數(shù)總比我們當(dāng)然中預(yù)期的多約12個us,也就是本仿真單片機(jī)的12個機(jī)器周期。再次查看中斷服務(wù)函數(shù)的匯編代碼:
; FUNCTION Timer1_ISR (BEGIN)
; SOURCE LINE # 43
; SOURCE LINE # 45
0000 309709 JNB PWM_PIN,?C0002 ;;;2us
; SOURCE LINE # 46
; SOURCE LINE # 47
0003 C297 CLR PWM_PIN ;;;1us
; SOURCE LINE # 48
0005 758DFF MOV TH1,#0FFH;;;2us
; SOURCE LINE # 49
0008 758BB5 MOV TL1,#0B5H ;;;2us
; SOURCE LINE # 50
000B 32 RETI ;;;2us
000C ?C0002:
; SOURCE LINE # 52
; SOURCE LINE # 53
000C D297 SETB PWM_PIN;;1us
; SOURCE LINE # 54
000E 758DFF MOV TH1,#0FFH ;;2us
; SOURCE LINE # 55
0011 758BE7 MOV TL1,#0E7H;;2us
; SOURCE LINE # 56
; SOURCE LINE # 57
0014 ?C0004:
0014 32 RETI ;;2us
; FUNCTION Timer1_ISR (END)
這次把每條指令的執(zhí)行時間注釋了在后,考慮指令流進(jìn)入了定時器中斷,執(zhí)行CLR PWM_PIN指令完成,則經(jīng)4us的PWM_HIGH計時參數(shù)裝載,2us的中斷返回操作,運(yùn)行main流程中的SJMP ?C0001空轉(zhuǎn)指令至定時器再次溢出中斷(Xus,X為程序設(shè)定PWM_HIGH取值),CPU中斷響應(yīng)再次轉(zhuǎn)入中斷服務(wù)例程(可計算中斷響應(yīng)時間為3~4us),執(zhí)行JNB PWM_PIN,?C0002SETB PWM_PIN
9、到這里,單片機(jī)軟模PWM波在高頻輸出下占空比誤差率變得不可收拾的原因終于畢露原形。實際輸出占空比計算式為:(PWM_HIGH+12)/(PWM_HIGH+PWM_LOW+24)。
評論