定時器用來產生PWM輸出:
STM32 的定時器除了 TIM6 和 7。其他的定時器都可以用來產生 PWM 輸出。其中高級定時器 TIM1 和 TIM8 可以同時產生多達 7 路的 PWM 輸出。而通用定時器也能同時產生多達 4路的 PWM 輸出,這樣,STM32 最多可以同時產生 30 路 PWM 輸出!
STM32 PWM工作過程
STM32 PWM工作過程(通道1為例:
-
CCR1:捕獲比較(值)寄存器(x=1,2,3,4):設置比較值。
-
CCMR1: OC1M[2:0]位:對于PWM方式下,用于設置PWM模式1【110】或者PWM模式2【111】
-
CCER:CC1P位:輸入/捕獲1輸出極性。0:高電平有效,1:低電平有效。
-
CCER:CC1E位:輸入/捕獲1輸出使能。0:關閉,1:打開。
總結幾個關鍵詞:
-
有效電平:高電平
-
無效電平:低電平
-
高電平有效:高電平可以使能相應功能
-
低電平有效:低電平可以使能相應功能
PWM模式1 & PWM模式2
寄存器TIMx_CCMR1的OC1M[2:0]位來分析:
STM32 PWM工作過程
STM32 PWM
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
自動重載的預裝載寄存器
- 捕獲/比較模塊由一個預裝載寄存器和一個影子寄存器組成。讀寫過程僅操作預裝載寄存器。在捕獲模式下,捕獲發生在影子寄存器上,然后再復制到預裝載寄存器中。在比較模式下,預裝載寄存器的內容被復制到影子寄存器中,然后影子寄存器的內容和計數器進行比較。
- 根據TIMx_CR1寄存器中APRE位的設置:APRE=0時,預裝載寄存器的內容可以隨時傳送到影子寄存器,此時二者是連通的;而APRE=1時,在每一次更新事件(UEV)時,才把預裝在寄存器的內容傳送到影子寄存器。
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
簡單的說,ARPE=1,ARR立即生效,APRE=0,ARR下個比較周期生效。
STM32 定時器3輸出通道引腳
PWM輸出庫函數
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);typedef struct
{uint16_t TIM_OCMode; //PWM模式1或者模式2uint16_t TIM_OutputState; //輸出使能 OR失能uint16_t TIM_OutputNState;uint16_t TIM_Pulse; //比較值,寫CCRxuint16_t TIM_OCPolarity; //比較輸出極性uint16_t TIM_OCNPolarity; uint16_t TIM_OCIdleState; uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure. TIM_Pulse=100;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根據T指定的參數初始化外設TIM3 OC2
設置比較值函數:
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare2);
使能輸出比較預裝載:
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
使能自動重裝載的預裝載寄存器允許位:
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
PWM輸出配置步驟:
1、 使能定時器3和相關IO口時鐘
- 使能定時器3時鐘:
RCC_APB1PeriphClockCmd();
- 使能GPIOB時鐘:
RCC_APB2PeriphClockCmd();
2、 初始化IO口為復用功能輸出
- 函數:
GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
3、 這里我們是要把PB5用作定時器的PWM輸出引腳,所以要重映射配置,所以需要開啟AFIO時鐘。同時設置重映射。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
4、 初始化定時器:ARR,PSC等:
TIM_TimeBaseInit();
5、 初始化輸出比較參數:
TIM_OC2Init();
6、 使能預裝載寄存器:
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
7、 使能定時器:
TIM_Cmd();
8、 不斷改變比較值CCRx,達到不同的占空比效果:
TIM_SetCompare2();
PWM 初始化代碼:
#include "pwm.h"
#include "sys.h"void PWM_Init(u16 arr,u16 psc)
{GPIO_InitTypeDef GPIO_InitStrue;TIM_TimeBaseInitTypeDef TIM_TimStrue;TIM_OCInitTypeDef TIM_OCInitStrue;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能相應定時器的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能相應GPIO的時鐘GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;//設置模式為復用輸出GPIO_InitStrue.GPIO_Pin=GPIO_Pin_5;GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStrue);//初始化GPIOB.5RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//開啟AFIO時鐘GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//設置重映射TIM_TimStrue.TIM_ClockDivision=TIM_CKD_DIV1;//設置時鐘分割:TDTS = Tck_timTIM_TimStrue.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimStrue.TIM_Period=arr;//自動裝載值TIM_TimStrue.TIM_Prescaler=psc;//預分頻系數的設置TIM_TimeBaseInit(TIM3,&TIM_TimStrue);//初始化定時器TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM2;//PWM模式2TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;//比較輸出極性,TIM輸出比較極性高TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;//輸出使能 TIM_OCInitStrue.TIM_Pulse=100;//比較值,寫CCRxTIM_OC2Init(TIM3,&TIM_OCInitStrue);//根據指定的參數初始化外設TIM3 OC2(因為是通道2,所以是OC2)TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能預裝載寄存器TIM_Cmd(TIM3,ENABLE);//使能定時器
}
主函數代碼:
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "pwm.h"int main(void){ u16 led0pwmval=0;u8 dir=1; delay_init(); //延時函數初始化 LED_Init(); //LED端口初始化PWM_Init(899,0); //不分頻。PWM頻率=72000000/900=80Khzwhile(1){delay_ms(10); if(dir)led0pwmval++;else led0pwmval--;if(led0pwmval>300)dir=0;if(led0pwmval==0)dir=1; TIM_SetCompare2(TIM3,led0pwmval);//不斷改變比較值CCRx,達到不同的占空比效果 } }
以上代碼可以實現呼吸燈的效果