目錄
基本原理
自然采樣法
規(guī)則采樣法
單極性
雙極性
如何編寫程序
總結(jié)
基本原理
SPWM的全稱是(Sinusoidal PWM
),正弦脈沖寬度調(diào)制是一種非常成熟,使用非常廣泛的技術(shù);
之前在PWM的文章中介紹過,基本原理就是面積等效原理,即沖量相等而形狀不同的窄脈沖加在具有慣性的環(huán)節(jié)上時,其效果基本相同 。
換句話說就是通過一系列形狀不同的窄脈沖信號,相對應(yīng)時間的積分相等(面積相等),其最終效果相同;
所以SPWM就是輸入一段幅值相等的脈沖序列去等效正弦波,因此輸出為高的脈沖時間寬度基本上呈正弦規(guī)律變化;
這里通常使用的采樣方法是:自然采樣法和規(guī)則采樣法;
自然采樣法
自然采樣法是用需要調(diào)制的正弦波與載波鋸齒波的交點,
來確定最終PWM脈沖所需要輸出的時間寬度,最終由此生成SPWM波;
具體如下圖所示,這里會對局部①部分進行簡單分析,下面進一步介紹;
局部①的情況如下圖所示;簡單分析一下整個圖形的情況;
-
鋸齒波和調(diào)制正弦波的交點為 A和 B; -
因此 A點所需時間為 T1, B點所需時間為 T2; -
所以在該周期內(nèi),PWM所需要的脈沖時間寬度 Ton滿足: -
最終結(jié)論就是,只要求出 A點和 B點位置,就可以求出 ;
這里對于求解A,B位置的推導(dǎo)不做介紹,但是計算量比較大,因此在微處理器中進行運算會占用大量資源,下面再介紹另一種優(yōu)化的采樣方法:規(guī)則采樣法。
規(guī)則采樣法
根據(jù)載波PWM的電壓極性,一般可以分為單極性SPWM和雙極性SPWM;下面進一步介紹;
單極性
單極性SPWM在正弦波的正版周期,PWM只有一種極性,在正弦波的負半周期,PWM同樣只有一種極性,但是與正半周期恰恰相反,具體如下圖所示;
下面取正弦波的正半周期的情況進行分析;
正弦波的正半周期整體如下所示;由圖中我們可以知道以下幾點;
-
載波PWM的周期為 T; -
線段 BO為當前這個等腰三角形的垂線; -
線段 BO與正弦曲線 相較于點 A; -
所以在該周期內(nèi) ,PWM所需要的脈沖時間寬度 Ton滿足:
具體的推導(dǎo)過程如下:
-
第一步:由于O點的位置比較好確認,因此,線段
-
第二步:這里載波鋸齒波的最大幅值為1,因此線段
-
第三步:根據(jù)初中學過的相似三角形定理,滿足:
最終簡化得到:
這里對載波的幅值做了歸一化處理,如果鋸齒波的最大值為 ,正弦波的幅值最大為 ,則 ;
雙極性
只要符合面積等效原理,PWM還可以是雙極性的,具體如下圖所示;這種調(diào)制方式叫雙極性SPWM,在實際應(yīng)用中更為廣泛。
如何編寫程序
上面講到這里PWM的 時間滿足:
其中 為正弦波幅值, 為載波鋸齒波幅值;
那么下面以STM32為例,介紹以下如何進行程序編寫;
首先得先STM32是如何產(chǎn)生PWM?
通過數(shù)據(jù)手冊可以知道,STM32通過TIM輸出PWM,這里有幾個寄存器;
-
計數(shù)寄存器: CNT -
比較寄存器: CCR (決定了占空比,決定了脈沖寬度) -
自動重裝寄存器: AAR(決定了PWM的周期)
可能這么說,還是云里霧里的,先看下圖;
STM32中PWM的模式有普通的PWM,和中央對齊的PWM,上圖使用的就是中央對齊PWM;
產(chǎn)生PWM的過程可以分為以下幾個過程;
-
第一步:配置好TIM, 通常時基和ARR都會配置好,這時候PWM的周期就已經(jīng)被設(shè)定好了,另外時基決定了CNT計數(shù)寄存器增加一次技術(shù)所需的時間; -
第二步:剛開始, CNT ,并且 CNT開始增加,這時候PWM的輸出都是低電平;當 CNT>CCR之后,PWM輸出為高電平; -
第三步:當 CNT的值等于AAR之后, CNT開始減少,同理 CNT ,PWM的輸出低電平;當 CNT>CCR,PWM輸出為高電平; -
第四步:循環(huán)上述三個步驟;
程序中如何實現(xiàn)?
從上述STM32產(chǎn)生PWM的過程中不難發(fā)現(xiàn), 滿足;
上一節(jié)推導(dǎo)的公式如下:
結(jié)合①式和②式,可以得到:
上面公式中用CCR表示CCR寄存器中的值,ARR表示ARR寄存器中的值;
最后需要做的三件事
-
計算出ARR,一般配置TIM定時器的時候能在數(shù)據(jù)手冊找到公式; -
調(diào)制比,也就是 的系數(shù); -
根據(jù)③式生成正弦表,然后查表(實時計算因為涉及到較多運算量,所以利用查表,空間換時間,提高效率), 利用PWM的事件去觸發(fā)中斷,更新下一次CCR的值;
正弦函數(shù)表:
const?uint16_t?indexWave[]?=?{
?0,?9,?18,?27,?36,?45,?54,?63,?72,?81,?89,?98,
?107,?116,?125,?133,?142,?151,?159,?168,?176,
?184,?193,?201,?209,?218,?226,?234,?242,?249,
?257,?265,?273,?280,?288,?295,?302,?310,?317,?
?324,?331,?337,?344,?351,?357,?364,?370,?376,?
?382,?388,?394,?399,?405,?410,?416,?421,?426,?
?431,?436,?440,?445,?449,?454,?458,?462,?465,?
?469,?473,?476,?479,?482,?485,?488,?491,?493,?
?496,?498,?500,?502,?503,?505,?506,?508,?509,?
?510,?510,?511,?512,?512,?512,?512,?512,?512,
?511,?510,?510,?509,?508,?506,?505,?503,?502,
?500,?498,?496,?493,?491,?488,?485,?482,?479,
?476,?473,?469,?465,?462,?458,?454,?449,?445,?
?440,?436,?431,?426,?421,?416,?410,?405,?399,?
?394,?388,?382,?376,?370,?364,?357,?351,?344,?
?337,?331,?324,??317,?310,?302,?295,?288,?280,?
?273,?265,?257,?249,?242,?234,?226,?218,?209,?
?201,?193,?184,?176,?168,?159,?151,?142,?133,?
????125,?116,?107,?98,?89,?81,?72,?63,?54,?45,?36,
????27,?18,?9,?0
};
中斷服務(wù)函數(shù):
extern?uint16_t?indexWave[];
extern?__IO?uint32_t?rgb_color;
/*?呼吸燈中斷服務(wù)函數(shù)?*/
void?BRE_TIMx_IRQHandler(void)
{?
?static?uint16_t?pwm_index?=?0;??//用于PWM查表
?static?uint16_t?period_cnt?=?0;??//用于計算周期數(shù)
?static?uint16_t?amplitude_cnt?=?0;?//用于計算幅值等級
?if?(TIM_GetITStatus(BRE_TIMx,?TIM_IT_Update)?!=?RESET)?//TIM_IT_Update
??{??
??amplitude_cnt++;
??//每個PWM表中的每個元素有AMPLITUDE_CLASS個等級,
??//每增加一級多輸出一次脈沖,即PWM表中的元素多使用一次
??//使用256次,根據(jù)RGB顏色分量設(shè)置通道輸出
??if(amplitude_cnt?>?(AMPLITUDE_CLASS-1)){??
???period_cnt++;
???//每個PWM表中的每個元素使用period_class次
???if(period_cnt?>?period_class){????
????
????//標志PWM表指向下一個元素
????pwm_index++;????????????
????//若PWM表已到達結(jié)尾,重新指向表頭
????if(?pwm_index?>=??POINT_NUM){
?????pwm_index=0;
????}
????//重置周期計數(shù)標志
????period_cnt?=?0;
???}
???//重置幅值計數(shù)標志
???amplitude_cnt=0;???????????
??
??}else{?
???//每個PWM表中的每個元素有AMPLITUDE_CLASS個等級,
???//每增加一級多輸出一次脈沖,即PWM表中的元素多使用一次
???//根據(jù)RGB顏色分量值,設(shè)置各個通道是否輸出當前的PWM表元素表示的亮度
???//紅
???if(((rgb_color&0xFF0000)>>16)?>=?amplitude_cnt)?{
????//根據(jù)PWM表修改定時器的比較寄存器值
????BRE_TIMx->BRE_RED_CCRx?=?indexWave[pwm_index];?
???}else{
????//比較寄存器值為0,通道輸出高電平,該通道LED燈滅
????BRE_TIMx->BRE_RED_CCRx?=?0;??
???}
???//綠
???if(((rgb_color&0x00FF00)>>8)?>=?amplitude_cnt){
????//根據(jù)PWM表修改定時器的比較寄存器值
????BRE_TIMx->BRE_GREEN_CCRx?=?indexWave[pwm_index];?
???}else{
????//比較寄存器值為0,通道輸出高電平,該通道LED燈滅
????BRE_TIMx->BRE_GREEN_CCRx?=?0;?
???}???
???//藍
???if((rgb_color&0x0000FF)?>=?amplitude_cnt){
????//根據(jù)PWM表修改定時器的比較寄存器值
????BRE_TIMx->BRE_BLUE_CCRx?=?indexWave[pwm_index];?
???}else{
????//比較寄存器值為0,通道輸出高電平,該通道LED燈滅?
????BRE_TIMx->BRE_BLUE_CCRx?=?0;??
???}
???//必須要清除中斷標志位
???TIM_ClearITPendingBit?(BRE_TIMx,?TIM_IT_Update);?
??}
?}
}
總結(jié)
本文簡單介紹了SPWM的原理和調(diào)制方法,推導(dǎo)了SPWM的PWM脈沖寬度的計算時間,最后給出了基于STM32單片機產(chǎn)生SPWM驅(qū)動呼吸燈的部分代碼,完整代碼關(guān)注公眾號私信發(fā)送SPWM獲取。
由于作者能力和水平有限,文中難免存在錯誤和紕漏,請不吝賜教。
原創(chuàng)不易,如果本文幫到了你;
請幫忙?轉(zhuǎn)發(fā)、留言、點贊、分享?給你的朋友,感謝您的支持!
長按識別二維碼添加我的微信
免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!