stm32高級定時器例子—stm32 PWM互補輸出
時基結構體,用於定時器基礎參數設置,與TIM_TimeBaseInit函數配合使用,完成配置。
typedef struct { TIM_Prescaler /*定時器預分頻器設置,時鍾源經該預分頻器才是定時器計 數時鍾CK_CNT,它設定PSC寄存器的值。 計數器時鍾頻率 (fCK_CNT) 等於 fCK_PSC/(PSC[15:0]+1),可實現1至65536分頻。*/ TIM_CounterMode /*定時器計數方式,可設置為 向上計數、向下計數、中心對齊*/ TIM_Period /*定時器周期,設定自動重載寄存器ARR的值 可設置范圍為0至65535*/ TIM_ClockDivision /*時鍾分頻,設置定時器時鍾CK_INT頻率與死區發生器 以及數字濾波器采樣時鍾頻率分頻比。 可以選擇 1、2、4 分頻。*/ TIM_RepetitionCounter /*重復計數器,只有 8 位,只存在於高級定時器*/ }TIM_TimeBaseInitTypeDef;
輸出比較結構體,用於輸出比較模式。與TIM_OCxInit函數配合使用,完成指定定時器輸出通道初始化配置。
typedef struct { uint16_t TIM_OCMode; /*比較輸出模式選擇,共有八種。 常用的為 PWM1/PWM2。 設定CCMRx寄存器OCxM[2:0]位的值*/ uint16_t TIM_OutputState; /*比較輸出使能,決定最終的輸出比較信號OCx是否 通過外部引腳輸出。 設定TIMx_CCER寄存器CCxE/CCxNE位的值。*/ uint16_t TIM_OutputNState; /*比較互補輸出使能,決定OCx的互補信號OCxN 是否通過外部引腳輸出。 設定CCER寄存器CCxNE位的值*/ uint16_t TIM_Pulse; /*比較輸出脈沖寬度,設定比較寄存器CCR的值, 決定脈沖寬度。可設置范圍為0至65535。*/ uint16_t TIM_OCPolarity; /*比較輸出極性, 可選OCx為高電平有效或低電平有效。 決定定時器通道有效電平。 設定CCER寄存器的CCxP位的值*/ uint16_t TIM_OCNPolarity; /*比較互補輸出極性, 可選OCxN為高電平有效或低電平有效。 設定TIMx_CCER寄存器的CCxNP位的值。*/ uint16_t TIM_OCIdleState; /*空閑狀態時,通道輸出電平設置, 可選輸出1或輸出0, 即在空閑狀態(BDTR_MOE位為0)時, 經過死區時間后定時器通道輸出高電平或低電平。 設定CR2寄存器的OISx位的值*/ uint16_t TIM_OCNIdleState; /*空閑狀態時互補通道輸出電平設置, 可選輸出1或輸出0, 即在空閑狀態(BDTR_MOE位為0)時, 經過死區時間后定時器互補通道 輸出高電平或低電平, 設定值必須與TIM_OCIdleState相反。 設定CR2寄存器的OISxN位的值。*/ } TIM_OCInitTypeDef;
輸入捕獲結構體,用於輸入捕獲模式。
與TIM_ICInit函數配合使用,完成定時器輸入通道初始化配置。
如果使用PWM輸入模式,與TIM_PWMIConfig函數配合使用,完成定時器輸入通道初始化配置。
typedef struct { uint16_t TIM_Channel; /*捕獲通道ICx選擇, 可選TIM_Channel_1、2、3、4四個通道。 設定CCMRx寄存器CCxS位的值*/ uint16_t TIM_ICPolarity; /*輸入捕獲邊沿觸發選擇, 可選上升沿觸發、下降沿觸發、邊沿跳變觸發。 設定CCER寄存器CCxP位和CCxNP位的值。*/ uint16_t TIM_ICSelection; /*輸入通道選擇, 捕獲通道ICx的信號可來自三個輸入通道, 分別為TIM_ICSelection_DirectTI、 TIM_ICSelection_IndirectTI TIM_ICSelection_TRC 普通的輸入捕獲,4個通道都可以使用, PWM輸入,只能使用通道1和通道2。 設定CCRMx寄存器的CCxS[1:0]位的值*/ uint16_t TIM_ICPrescaler; /*輸入捕獲通道預分頻器, 可設置1、2、4、8分頻, 設定CCMRx寄存器的ICxPSC[1:0]位的值。 如果需捕獲輸入信號的每個有效邊沿, 則設置1分頻。*/ uint16_t TIM_ICFilter; /*輸入捕獲濾波器設置, 可設置0x0至0x0F。 設定CCMRx寄存器ICxF[3:0]位的值。 一般不使用濾波器,設置為0*/ } TIM_ICInitTypeDef;
關於捕獲通道ICx的信號可來自三個輸入通道:

斷路和死區結構體,用於斷路和死區參數的設置,高級定時器專用。
用於配置斷路時,通道輸出狀態、死區時間。
與TIM_BDTRConfig函數配置使用,完成參數配置。
這個結構體的成員只對應BDTR寄存器。
typedef struct { uint16_t TIM_OSSRState; /*運行模式下的關閉狀態選擇, 設定BDTR寄存器OSSR位的值*/ uint16_t TIM_OSSIState; /*空閑模式下的關閉狀態選擇, 設定BDTR寄存器OSSI位的值。*/ uint16_t TIM_LOCKLevel; /*鎖定級別配置, 設定BDTR寄存器LOCK[1:0]位的值*/ uint16_t TIM_DeadTime; /*配置死區發生器,定義死區持續時間, 可選設置范圍為0x0至0xFF。 設定BDTR寄存器DTG[7:0]位的值*/ uint16_t TIM_Break; /*斷路輸入功能選擇, 可選使能或禁止。 設定BDTR寄存器BKE位的值*/ uint16_t TIM_BreakPolarity; /*斷路輸入通道BRK極性選擇, 可選高電平有效或低電平有效。 設定BDTR寄存器BKP位的值。*/ uint16_t TIM_AutomaticOutput; /*自動輸出使能,可選使能或禁止, 設定BDTR寄存器AOE位的值。*/ } TIM_BDTRInitTypeDef;
在主輸出通道輸出波形,在互補通道輸出與主通道互補的的波形,添加斷路和死區功能。
使用高級定時器TIM1的通道1及其互補通道作為本實驗的波形輸出通道。對應PA8和PB13。
將示波器的兩個輸入通道分別與PA8和PB13引腳連接,共地,觀察波形。
增加斷路功能,用到TIM1_BKIN引腳。對應PB12引腳。
設置該引腳為高電平有效,BKIN引腳置高電平時,兩路互補的PWM輸出就被停止,像是剎車一樣。
Main函數,調用ADVANCE_TIM_Init()函數。
該函數調用ADVANCE_TIM_GPIO_Config()和ADVANCE_TIM_Mode_Config()進行定時器GPIO引腳和工作模式的初始化。
相應的GPIO引腳上可以檢測到互補輸出的PWM信號,而且帶死區時間。
程序運行的過程中,如果BKIN引腳被拉高,PWM輸出會被禁止,像是斷路或者剎車。
#include "stm32f10x.h" #include "bsp_led.h" #include "bsp_AdvanceTim.h" /** * @brief 主函數 * @param 無 * @retval 無 */ int main(void) { /* 高級定時器初始化 */ ADVANCE_TIM_Init(); while(1) { } }
修改PWM的周期和占空比,只需修改下面的ADVANCE_TIM_PERIOD、ADVANCE_TIM_PSC和ADVANCE_TIM_PULSE這三個宏即可。具體原因,看之前寫的文章—高級定時器里面的PWM輸出模式。
TIM_CLK等於72MHZ,ARR是自動重裝載寄存器的值,對應ADVANCE_TIM_PERIOD;PSC是計數器時鍾的分頻因子,對應ADVANCE_TIM_PSC。
PWM信號的頻率:F = TIM_CLK/{(ARR+1)*(PSC+1)}
計數器時鍾CK_CNT:
定時器時鍾經過PSC預分頻器后,即CK_CNT,用來驅動計數器計數。
PSC是16位的預分頻器,可以對定時器時鍾TIMxCLK進行1~65536之間的任何一個數進行分頻。CK_CNT=TIMxCLK/(PSC+1)。
ARR=8,CCR=4,CNT從0開始計數。
當CNT<CCR,OCxREF為有效的高電平,同時,比較中斷寄存器CCxIF置位。
CCR<=CNT<=ARR,OCxREF為無效的低電平。
計數器在CK_CNT的驅動下,計一個數的時間,1/(TIMxCLK/(PSC+1))=1/(CK_CNT)=(PSC+1)/TIMxCLK
計一個數的時間乘上一個波形的計數次數(ARR+1),就是整個波形的所需時間。
時間取倒數就是PWM信號的頻率。
由此可知F = TIM_CLK/{(ARR+1)*(PSC+1)}的含義。
ARR :自動重裝載寄存器的值
CLK_cnt:計數器的時鍾,等於 Fck_int / (psc+1) = 72M/(psc+1) PWM 信號的周期 T = (ARR+1) * (1/CLK_cnt) = (ARR+1)*(PSC+1) / 72M 占空比P=CCR/(ARR+1)
#ifndef __BSP_ADVANCETIME_H #define __BSP_ADVANCETIME_H #include "stm32f10x.h" /************高級定時器TIM參數定義,只限TIM1和TIM8************/ // 當使用不同的定時器的時候,對應的GPIO是不一樣的,這點要注意 // 這里我們使用高級控制定時器TIM1 #define ADVANCE_TIM TIM1 #define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd #define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1 // PWM 信號的頻率 F = TIM_CLK/{(ARR+1)*(PSC+1)} #define ADVANCE_TIM_PERIOD (8-1) #define ADVANCE_TIM_PSC (9-1) #define ADVANCE_TIM_PULSE 4 #define ADVANCE_TIM_IRQ TIM1_UP_IRQn #define ADVANCE_TIM_IRQHandler TIM1_UP_IRQHandler // TIM1 輸出比較通道 #define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA #define ADVANCE_TIM_CH1_PORT GPIOA #define ADVANCE_TIM_CH1_PIN GPIO_Pin_8 // TIM1 輸出比較通道的互補通道 #define ADVANCE_TIM_CH1N_GPIO_CLK RCC_APB2Periph_GPIOB #define ADVANCE_TIM_CH1N_PORT GPIOB #define ADVANCE_TIM_CH1N_PIN GPIO_Pin_13 // TIM1 輸出比較通道的剎車通道 #define ADVANCE_TIM_BKIN_GPIO_CLK RCC_APB2Periph_GPIOB #define ADVANCE_TIM_BKIN_PORT GPIOB #define ADVANCE_TIM_BKIN_PIN GPIO_Pin_12 /**************************函數聲明********************************/ void ADVANCE_TIM_Init(void); #endif /* __BSP_ADVANCETIME_H */
#include "bsp_AdvanceTim.h" static void ADVANCE_TIM_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 輸出比較通道 GPIO 初始化 RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure); // 輸出比較通道互補通道 GPIO 初始化 RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure); // 輸出比較通道剎車通道 GPIO 初始化 RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure); // BKIN引腳默認先輸出低電平 GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN); } ///* // * 注意:TIM_TimeBaseInitTypeDef結構體里面有5個成員,TIM6和TIM7的寄存器里面只有 // * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的時候只需初始化這兩個成員即可, // * 另外三個成員是通用定時器和高級定時器才有. // *----------------------------------------------------------------------------- // *typedef struct // *{ TIM_Prescaler 都有 // * TIM_CounterMode TIMx,x[6,7]沒有,其他都有 // * TIM_Period 都有 // * TIM_ClockDivision TIMx,x[6,7]沒有,其他都有 // * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有 // *}TIM_TimeBaseInitTypeDef; // *----------------------------------------------------------------------------- // */ /* ---------------- PWM信號 周期和占空比的計算--------------- */ // ARR :自動重裝載寄存器的值 // CLK_cnt:計數器的時鍾,等於 Fck_int / (psc+1) = 72M/(psc+1) // PWM 信號的周期 T = (ARR+1) * (1/CLK_cnt) = (ARR+1)*(PSC+1) / 72M // 占空比P=CCR/(ARR+1) static void ADVANCE_TIM_Mode_Config(void) { // 開啟定時器時鍾,即內部時鍾CK_INT=72M ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE); /*--------------------時基結構體初始化-------------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 自動重裝載寄存器的值,累計TIM_Period+1個頻率后產生一個更新或者中斷 TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD; // 驅動CNT計數器的時鍾 = Fck_int/(psc+1) TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC; // 時鍾分頻因子 ,配置死區時間時需要用到 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 計數器計數模式,設置為向上計數 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重復計數器的值,沒用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定時器 TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure); /*--------------------輸出比較結構體初始化-------------------*/ TIM_OCInitTypeDef TIM_OCInitStructure; // 配置為PWM模式1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 輸出使能 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 互補輸出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 設置占空比大小 TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE; // 輸出通道電平極性配置 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 互補輸出通道電平極性配置 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; // 輸出通道空閑電平極性配置 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; // 互補輸出通道空閑電平極性配置 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure); TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable); /*-------------------剎車和死區結構體初始化-------------------*/ // 有關剎車和死區結構體的成員具體可參考BDTR寄存器的描述 TIM_BDTRInitTypeDef TIM_BDTRInitStructure; TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; // 輸出比較信號死區時間配置,具體如何計算可參考 BDTR:UTG[7:0]的描述 // 這里配置的死區時間為152ns TIM_BDTRInitStructure.TIM_DeadTime = 11; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; // 當BKIN引腳檢測到高電平的時候,輸出比較信號被禁止,就好像是剎車一樣 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure); // 使能計數器 TIM_Cmd(ADVANCE_TIM, ENABLE); // 主輸出使能,當使用的是通用定時器時,這句不需要 TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE); } void ADVANCE_TIM_Init(void) { ADVANCE_TIM_GPIO_Config(); 