STM32——PWM基本知識及配置過程
STM32——PWM基本知識及配置過程
將通用定時器分為四個部分:
1,選擇時鐘
2,時基電路
3,輸入捕獲
4,輸出比較
本節定時器PWM輸出主要涉及到定時器框圖右下方部分,即輸出比較部分
和上一講相同,時基時鐘來源於內部預設時鐘
對此有疑問請參考 : 定時器中斷實驗 中 定時器時鐘選擇部分 和 定時器時鐘來源部分
什麼是PWM
脈衝寬度調製(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調製,是利用微處理器的數字輸出來對類比電路進行控制的一種非常有效的技術,廣泛應用在從測量、通訊到功率控制與變換的許多領域中。
PWM工作過程
每個定時器有四個通道,每一個通道都有一個捕獲比較暫存器,
將暫存器值和計數器值比較,通過比較結果輸出高低電平,實現PWM訊號
先簡單說明一下:
如圖為向上計數: 定時器重灌載值為ARR,比較值CCRx t時刻對計數器值和比較值進行比較 如果計數器值小於CCRx值,輸出低電平 如果計數器值大於CCRx值,輸出高電平 PWM的一個週期 定時器從0開始向上計數 當0-t1段,定時器計數器TIMx_CNT值小於CCRx值,輸出低電平 t1-t2段,定時器計數器TIMx_CNT值大於CCRx值,輸出高電平 當TIMx_CNT值達到ARR時,定時器溢位,重新向上計數...迴圈此過程 至此一個PWM週期完成 影響因素 ARR : 決定PWM週期(在時鐘頻率一定的情況下,當前為預設內部時鐘CK_INT) CCRx : 決定PWM佔空比(高低電平所佔整個週期比例)
PWM工作過程(以通道1為例)
1,TIMx_CCMR1暫存器的OC1M[2:0]位,設定輸出模式控制器 110:PWM模式1 111:PWM模式2 2,計數器值TIMx_CNT與通道1捕獲比較暫存器CCR1進行比較,通過比較結果輸出有效電平和無效電平 OC1REF=0 無效電平 OC1REF=1 無效電平 3,通過輸出模式控制器產生的訊號 TIMx_CCER暫存器的CC1P位,設定輸入/捕獲通道1輸出極性 0:高電平有效 1:低電平有效 4,TIMx_CCER:CC1E位控制輸出使能電路,訊號由此輸出到對應引腳 0:關閉 1:開啟
PWM如何輸出高低電平
計數器值TIMx_CNT與捕獲比較暫存器值CCRx比較後,最終輸出高電平還是低電平,
由TIMx_CCMR1:OC1M位和TIMx_CCER:CC1P位共同決定
1,TIMx_CCMR1暫存器的OC1M[2:0]位,設定PWM模式1或模式2
通過設定模式1或模式2,決定了比較結果輸出有效或無效電平
2,TIMx_CCER暫存器的CC1P位,設定輸入/捕獲通道1輸出極性
通過設定輸出極性,確定有效或無效電平為最終輸出的高電平或低電平
總結:
模式1:
CNT<CCR為有效電平 //(OC1REF = 1)
CNT>CCR為無效電平 //(OC1REF = 0)
模式2:
CNT<CCR為無效電平 //(OC1REF = 0)
CNT>CCR為有效電平 //(OC1REF = 1)
CC1P:
0:高電平有效
1:低電平有效
PWM模式配置
TIM_OC1PreloadConfig函式:
作用:TIM_CCMRx暫存器OCxPE位使能相應的預裝在暫存器
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
TIM_ARRPreloadConfig函式:
作用:操作TIMx_CR1暫存器ARPE位,使能自動重灌載的預裝載暫存器
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
ARPE的使能-ARR變更生效配置
ARPE=1,ARR立即生效
ARPE=0,ARR下週期生效
定時器3輸出通道引腳
定時器3的4個通道對應的引腳及重對映
PWM輸出庫函式
1,定時器通道初始化-TIM_OC1Init
經過上面的講解,我們知道了要想使用PWM需要配置
配置引數對應框圖位置如下:
1,TIMx_CCMR1暫存器的OC1M[2:0]位,設定輸出模式控制器
2,TIMx_CCER暫存器的CC1P位,設定輸入/捕獲通道1輸出極性
3,TIMx_CCER:CC1E位控制輸出使能電路,訊號由此輸出到對應引腳
初始化定時器輸出比較通道
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
- 1
TIM_OCInitTypeDef結構體
typedef struct { uint16_t TIM_OCMode; // PWM模式1或者模式2 uint16_t TIM_OutputState; // 輸出使能 OR失能 uint16_t TIM_OutputNState; // PWM輸出不需要 uint16_t TIM_Pulse; // 比較值,寫CCRx,可以有次函式
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
寫入,這裡暫時不設定。 uint16_t TIM_OCPolarity; // 比較輸出極性 uint16_t TIM_OCNPolarity; // PWM輸出不需要 uint16_t TIM_OCIdleState; // PWM輸出不需要 uint16_t TIM_OCNIdleState; // PWM輸出不需要 } TIM_OCInitTypeDef;
2,設定比較值函式-TIM_SetCompare1
作用:外部改變TIM_Pulse值,即改變CCR的值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
- 1
3,使能輸出比較預裝載-TIM_OC1PreloadConfig
作用:TIM_CCMRx暫存器OCxPE位使能相應的預裝在暫存器
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
- 1
4,使能自動重灌載的預裝載暫存器允許位-TIM_ARRPreloadConfig
作用:操作TIMx_CR1暫存器ARPE位,使能自動重灌載的預裝載暫存器
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
- 1
5,修改通道極性
作用:操作TIMx_CCER的CC1P位,修改通道極性
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
- 1
PWM輸出實驗
使用定時器3初始PWM訊號,輸出佔空比可變的PWM波驅動LED(PB5引腳),實現LED亮度變換
LED:低電平點亮,高電平熄滅,佔空比越大,一個週期中高電平持續時間越長,亮度越大,反之越暗.
查詢手冊PB5引腳為定時器3的通道2,需要部分重對映
PWM輸出實驗步驟
1,使能定時器3和相關IO時鐘(LED-PB5)
使能定時器3時鐘:RCC_APB1PeriphClockCmd();
使能GPIOB時鐘:RCC_APB2PeriphClockCmd();
2,初始化IO口為複用功能輸出 GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
3,PB5輸出PWM(定時器3通道2),需要部分衝突對映
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//開啟AFIO時鐘設定
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//部分重對映
4,初始化定時器 (重灌載值ARR,與分頻係數PSC等)
TIM_TimeBaseInit();//決定PWM週期
5,初始化輸出比較引數:
TIM_OC2Init();//通道2輸出比較初始化
6,使能預裝載暫存器
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);//定時器3 通道2
7,使能定時器
TIM_Cmd();
8,不斷改變比較值CCRx,達到不同的佔空比效果
TIM_SetCompare2(); //通道2,改變比較值CCRx
程式碼實現
基於 定時器中斷實驗 程式碼進行編寫
timer.h新增PWM初始化函式定義 void TIM3_PWM_Init(u16 arr,u16 psc);
#ifndef __TIMER_H #define __TIMER_H #include "sys.h" void TIM3_PWM_Init(u16 arr,u16 psc); #endif
timer.c 實現定時器PWM初始化函式
#include "timer.h" //TIM3 PWM初始化 //arr 重灌載值 //psc 預分頻係數 void TIM3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStrue; TIM_OCInitTypeDef TIM_OCInitStrue; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //使能TIM3和相關GPIO時鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 使能GPIOB時鐘(LED在BP5引腳),使能AFIO時鐘(定時器3通道2需要重對映到BP5引腳) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStrue.GPIO_Pin=GPIO_Pin_5; // TIM_CH2 GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP; // 複用推輓 GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz; //設定最大輸出速度 GPIO_Init(GPIOB,&GPIO_InitStrue); //GPIO埠初始化設定 GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); TIM_TimeBaseInitStrue.TIM_Period=arr; //設定自動重灌載值 TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //預分頻係數 TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //計數器向上溢位 TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //時鐘的分頻因子,起到了一點點的延時作用,一般設為TIM_CKD_DIV1 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化設定(設定PWM的週期) TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM2; // PWM模式2:CNT>CCR時輸出有效 TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 設定極性-有效為高電平 TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 輸出使能 TIM_OC2Init(TIM3,&TIM_OCInitStrue); //TIM3的通道2PWM 模式設定 TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能預裝載暫存器 TIM_Cmd(TIM3,ENABLE); //使能TIM3 }
主程式的設計:
進行pwm的設定
TIM_SetCompare2(TIM3,led0pwmval); //改變比較值TIM3->CCR2達到調節佔空比的效果
int main(void)
{
u8 i=1; // 設定方向 0:變暗 1:變亮
u16 led0pwmval; // 設定CCR值
delay_init(); // 延時函式初始化
LED_Init(); // LED初始化
TIM3_PWM_Init(899,0); //設定頻率為80KHz,公式為:溢位時間Tout=(arr+1)(psc+1)/Tclk
//Tclk為通用定時器的時鐘,如果APB1沒有分頻,則就為系統時鐘,72MHZ
//PWM時鐘頻率=72000000/(899+1) = 80KHZ,設定自動裝載值899,預分頻係數0(不分頻)
while(1)
{
delay_ms(10);
if(i)led0pwmval++; // 由暗變亮
else led0pwmval--; // 由亮變暗
if(led0pwmval==0)i=1; // 已達到最亮,開始變暗
if(led0pwmval>100)i=0; // 已達到最暗,開始變亮
TIM_SetCompare2(TIM3,led0pwmval); //改變比較值TIM3->CCR2達到調節佔空比的效果
}
}
//此處led0pwmval值最大可以設定到899,輸出pwm波基本全為1,大小隨意設定。