stm32 PWM输入捕获
普通的輸入捕獲,可使用定時器的四個通道,一路捕獲占用一個捕獲寄存器.
PWM輸入,只能使用兩個通道,通道1和通道2。
一路PWM輸入占用兩個捕獲寄存器,一個捕獲周期,一個捕獲占空比。
這里,用通用定時器產(chǎn)生一路PWM信號,用高級定時器的通道1或通道2捕獲。
通用定時器TIM3的通道1,PA6,用于輸出PWM信號。
高級控制定時器TIM1的通道1,PA8,用于PWM輸入捕獲。
bsp_ AdvanceTim.c文件,高級定時器PWM輸入捕獲驅(qū)動程序。
bsp_ GeneralTim.c文件,通用定時器PWM信號輸出驅(qū)動程序。
通用定時器產(chǎn)生PWM配置
高級定時器PWM輸入配置
中斷服務(wù)程序,計算測量的頻率和占空比。
關(guān)鍵,PWM信號輸出,PWM信號輸入捕獲。
通用定時器PWM信號輸出
通用定時器宏定義:
PWM 輸出,就是對外輸出脈寬(即占空比)可調(diào)的方波信號,信號頻率由自動重裝寄存器ARR的值決定,占空比由比較寄存器CCR的值決定。可看之前寫的高級定時器基礎(chǔ)知識。
可算出PWM信號的頻率F:72M/( 10*72 )=100KHZ。
PWM 信號的周期 T = (ARR+1) * (1/CLK_cnt) = (ARR+1) * (PSC+1) / 72M
注釋:
定時器時鐘經(jīng)過PSC預(yù)分頻器后,即CK_CNT,用來驅(qū)動計數(shù)器計數(shù)。
PSC是16位的預(yù)分頻器,可以對定時器時鐘TIMxCLK進(jìn)行1~65536之間的任何一個數(shù)進(jìn)行分頻。CK_CNT=TIMxCLK/(PSC+1)。
定時器時鐘TIMxCLK,即內(nèi)部時鐘CK_INT,經(jīng)APB1預(yù)分頻器分頻提供。
APB1預(yù)分頻系數(shù)等于1,頻率不變。
庫函數(shù)中APB1預(yù)分頻的系數(shù)是2,即PCLK1=36M,所以定時器時鐘TIMxCLK=36*2=72M。
計一個數(shù)的時間乘上一個波形的計數(shù)次數(shù)(ARR+1),就是整個波形的所需時間。
時間取倒數(shù)就是PWM信號的頻率。
以CNT工作在遞增模式為例,上圖,ARR=8,CCR=4,CNT從0開始計數(shù).
當(dāng)CNT<CCR,OCxREF為有效的高電平,同時,比較中斷寄存器CCxIF置位。
CCR<=CNT<=ARR,OCxREF為無效的低電平。CNT又從0開始計數(shù),并生成計數(shù)器上溢事件,循環(huán)往復(fù)。
占空比:GENERAL_TIM_CCR1/(GENERAL_TIM_PERIOD+1)= 50%
// 自動重裝載寄存器的值,累計TIM_Period+1個頻率后產(chǎn)生一個更新或者中斷TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD; #define GENERAL_TIM_PERIOD 0XFFFF /************通用定時器TIM參數(shù)定義,只限TIM2、3、4、5************/ // 當(dāng)使用不同的定時器的時候,對應(yīng)的GPIO是不一樣的,這點要注意 // 這里默認(rèn)使用TIM3#define GENERAL_TIM TIM3 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM3 // 輸出PWM的頻率為 72M/{ (ARR+1)*(PSC+1) } #define GENERAL_TIM_PERIOD (10-1) #define GENERAL_TIM_PSC (72-1)#define GENERAL_TIM_CCR1 5 #define GENERAL_TIM_CCR2 4 #define GENERAL_TIM_CCR3 3 #define GENERAL_TIM_CCR4 2// TIM3 輸出比較通道1 #define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA #define GENERAL_TIM_CH1_PORT GPIOA #define GENERAL_TIM_CH1_PIN GPIO_Pin_6通用定時器引腳初始化,初始化了通用定時器PWM輸出用到的GPIO,使用不同的GPIO時,只需修改頭文件里的宏定義。
/*** @brief 通用定時器PWM輸出用到的GPIO初始化* @param 無* @retval 無*/ static void GENERAL_TIM_GPIO_Config(void) {GPIO_InitTypeDef GPIO_InitStructure;// 輸出比較通道1 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);// 輸出比較通道2 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH2_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH2_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH2_PORT, &GPIO_InitStructure);// 輸出比較通道3 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH3_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure);// 輸出比較通道4 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH4_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure); }通用定時器PWM輸出初始化。
GENERAL_TIM_Mode_Config()函數(shù)中初始化了兩個結(jié)構(gòu)體,時基結(jié)構(gòu)體和輸出比較結(jié)構(gòu)體。
若修改PWM的周期和占空比,需修改頭文件里面的GENERAL_TIM_PERIOD、GENERAL_TIM_PSC和GENERAL_TIM_CCR1這三個宏。
PWM信號的頻率的計算公式為:F=TIM_CLK/{(ARR+1)*(PSC+1)},TIM_CLK=72MHZ,ARR是自動重裝載寄存器的值,對應(yīng)GENERAL_TIM_PERIOD,PSC是計數(shù)器時鐘的分頻因子,對應(yīng)GENERAL_TIM_PSC。
/*** @brief 通用定時器PWM輸出初始化* @param 無* @retval 無* @note */ static void GENERAL_TIM_Mode_Config(void) {// 開啟定時器時鐘,即內(nèi)部時鐘CK_INT=72MGENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);/*--------------------時基結(jié)構(gòu)體初始化-------------------------*/// 配置周期,這里配置為100KTIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自動重裝載寄存器的值,累計TIM_Period+1個頻率后產(chǎn)生一個更新或者中斷TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD; // 驅(qū)動CNT計數(shù)器的時鐘 = Fck_int/(psc+1)TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_PSC; // 時鐘分頻因子 ,配置死區(qū)時間時需要用到TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 計數(shù)器計數(shù)模式,設(shè)置為向上計數(shù)TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重復(fù)計數(shù)器的值,沒用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定時器TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);/*--------------------輸出比較結(jié)構(gòu)體初始化-------------------*/ TIM_OCInitTypeDef TIM_OCInitStructure;// 配置為PWM模式1TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 輸出使能TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 輸出通道電平極性配置 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 輸出比較通道 1TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR1;TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 輸出比較通道 2TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR2;TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 輸出比較通道 3TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR3;TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 輸出比較通道 4TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR4;TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 使能計數(shù)器TIM_Cmd(GENERAL_TIM, ENABLE); }調(diào)用函數(shù)GENERAL_TIM_Init()后,相應(yīng)引腳就輸出PWM信號。
/*** @brief 通用定時器PWM輸出用到的GPIO和PWM模式初始化* @param 無* @retval 無*/ void GENERAL_TIM_Init(void) {GENERAL_TIM_GPIO_Config();GENERAL_TIM_Mode_Config(); }高級定時器PWM輸入捕獲
輸入到高級定時器捕獲引腳的PWM信號,來自通用定時器的輸出。
宏定義里面,可以算出計數(shù)器的計數(shù)周期為T=72M/(1000*72)=1MS。
這是定時器在不溢出的情況下的最大計數(shù)周期,也就是說,周期小于1ms的PWM信號都可以被捕獲到。轉(zhuǎn)換成頻率就是能捕獲到的最小的頻率為1KHZ。
要根據(jù)捕獲的PWM信號,調(diào)節(jié)ADVANCE_TIM_PERIOD和ADVANCE_TIM_PSC這兩個宏。
#ifndef __BSP_ADVANCETIME_H #define __BSP_ADVANCETIME_H#include "stm32f10x.h"/************高級定時器TIM參數(shù)定義,只限TIM1和TIM8************/ // 當(dāng)使用不同的定時器的時候,對應(yīng)的GPIO是不一樣的,這點要注意 // 這里我們使用高級控制定時器TIM1#define ADVANCE_TIM TIM1 #define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd #define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1// 輸入捕獲能捕獲到的最小的頻率為 72M/{ (ARR+1)*(PSC+1) } #define ADVANCE_TIM_PERIOD (1000-1) #define ADVANCE_TIM_PSC (72-1)// 中斷相關(guān)宏定義 #define ADVANCE_TIM_IRQ TIM1_CC_IRQn #define ADVANCE_TIM_IRQHandler TIM1_CC_IRQHandler// TIM1 輸入捕獲通道1 #define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA #define ADVANCE_TIM_CH1_PORT GPIOA #define ADVANCE_TIM_CH1_PIN GPIO_Pin_8#define ADVANCE_TIM_IC1PWM_CHANNEL TIM_Channel_1 #define ADVANCE_TIM_IC2PWM_CHANNEL TIM_Channel_2/**************************函數(shù)聲明********************************/void ADVANCE_TIM_Init(void);#endif /* __BSP_ADVANCETIME_H */高級定時器PWM輸入模式:
ADVANCE_TIM_Mode_Config()函數(shù)中初始化了兩個結(jié)構(gòu)體。
TIM_TimeBaseInitTypeDef,時基結(jié)構(gòu)體,用于定時器基礎(chǔ)參數(shù)設(shè)置。
TIM_OCInitTypeDef,輸出比較結(jié)構(gòu)體,用于輸出比較模式。
PWM輸入模式,只能使用通道1和通道2。
使用通道1,即TI1,輸入的PWM信號被分成兩路,分別是TI1FP1和TI1FP2,兩路都可以是觸發(fā)信號。
選擇TI1FP1為觸發(fā)信號,IC1捕獲到的是PWM信號的周期,IC2捕獲到的是占空比。
這種輸入通道TI和捕獲通道IC的映射關(guān)系叫直連,輸入捕獲結(jié)構(gòu)體TIM_ICSelection配置為TIM_ICSelection_DirectTI。
選擇TI1FP2為觸發(fā)信號,則IC2捕獲到的是周期,IC1捕獲到的是占空比。
這種輸入通道TI和捕獲通道IC的映射關(guān)系叫非直連,輸入捕獲結(jié)構(gòu)體的TIM_ICSelection要配置為TIM_ICSelection_IndirectTI。
輸入通道TI和捕獲通道IC的具體映射關(guān)系有直連和非直連兩種。
/*** @brief 高級定時器PWM輸入初始化和用到的GPIO初始化* @param 無* @retval 無*/ static void ADVANCE_TIM_Mode_Config(void) {// 開啟定時器時鐘,即內(nèi)部時鐘CK_INT=72MADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);/*--------------------時基結(jié)構(gòu)體初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自動重裝載寄存器的值,累計TIM_Period+1個頻率后產(chǎn)生一個更新或者中斷TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD; // 驅(qū)動CNT計數(shù)器的時鐘 = Fck_int/(psc+1)TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC; // 時鐘分頻因子 ,配置死區(qū)時間時需要用到TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 計數(shù)器計數(shù)模式,設(shè)置為向上計數(shù)TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重復(fù)計數(shù)器的值,沒用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定時器TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);/*--------------------輸入捕獲結(jié)構(gòu)體初始化-------------------*/ // 使用PWM輸入模式時,需要占用兩個捕獲寄存器,一個測周期,另外一個測占空比TIM_ICInitTypeDef TIM_ICInitStructure;// 捕獲通道IC1配置// 選擇捕獲通道TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;// 設(shè)置捕獲的邊沿TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 設(shè)置捕獲通道的信號來自于哪個輸入通道,有直連和非直連兩種TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;// 1分頻,即捕獲信號的每個有效邊沿都捕獲TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 不濾波TIM_ICInitStructure.TIM_ICFilter = 0x0;// 初始化PWM輸入模式TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);// 當(dāng)工作做PWM輸入模式時,只需要設(shè)置觸發(fā)信號的那一路即可(用于測量周期)// 另外一路(用于測量占空比)會由硬件自帶設(shè)置,不需要再配置// 捕獲通道IC2配置 // TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL; // TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; // TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI; // TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // TIM_ICInitStructure.TIM_ICFilter = 0x0; // TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);// 選擇輸入捕獲的觸發(fā)信號TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1); // 選擇從模式: 復(fù)位模式// PWM輸入模式時,從模式必須工作在復(fù)位模式,當(dāng)捕獲開始時,計數(shù)器CNT會被復(fù)位TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);// 使能捕獲中斷,這個中斷針對的是主捕獲通道(測量周期那個)TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE); // 清除中斷標(biāo)志位TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);// 使能高級控制定時器,計數(shù)器開始計數(shù)TIM_Cmd(ADVANCE_TIM, ENABLE); }高級定時器中斷優(yōu)先級:只有一個中斷源,優(yōu)先級可以隨便配置
// 中斷相關(guān)宏定義 #define ADVANCE_TIM_IRQ TIM1_CC_IRQn #define ADVANCE_TIM_IRQHandler TIM1_CC_IRQHandler /*** @brief 高級控制定時器 TIMx,x[1,8]中斷優(yōu)先級配置* @param 無* @retval 無*/ static void ADVANCE_TIM_NVIC_Config(void) {NVIC_InitTypeDef NVIC_InitStructure; // 設(shè)置中斷組為0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 設(shè)置中斷來源NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; // 設(shè)置搶占優(yōu)先級NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 設(shè)置子優(yōu)先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); }高級定時器中斷服務(wù)函數(shù):
捕獲到PWM信號的第一個上升沿時,產(chǎn)生中斷,計數(shù)器被復(fù)位,鎖存到捕獲寄存器IC1和IC2的值都為0。
下降沿到來時,IC2會捕獲,對應(yīng)的是占空比,會產(chǎn)生中斷。
當(dāng)捕獲到第二個上升沿時,IC1會捕獲,對應(yīng)的是周期,再次進(jìn)入中斷。
可以根據(jù)IC1和IC2的值計算出頻率和占空比。
中斷復(fù)位函數(shù)中,獲取輸入捕獲寄存器CCR1和CCR2寄存器中的值。
CCR1的值不為0,說明有效捕獲到了一個周期,然后計算出頻率和占空比。
計算時,CCR1和CCR2的值都必須加1,因為計數(shù)器從0開始計數(shù)。
/** 如果是第一個上升沿中斷,計數(shù)器會被復(fù)位,鎖存到CCR1寄存器的值是0,CCR2寄存器的值也是0* 無法計算頻率和占空比。當(dāng)?shù)诙紊仙氐絹淼臅r候,CCR1和CCR2捕獲到的才是有效的值。其中* CCR1對應(yīng)的是周期,CCR2對應(yīng)的是占空比。*/ void ADVANCE_TIM_IRQHandler(void) {/* 清除中斷標(biāo)志位 */TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);/* 獲取輸入捕獲值 */IC1Value = TIM_GetCapture1(ADVANCE_TIM);IC2Value = TIM_GetCapture2(ADVANCE_TIM);// 注意:捕獲寄存器CCR1和CCR2的值在計算占空比和頻率的時候必須加1if (IC1Value != 0){/* 占空比計算 */DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);/* 頻率計算 */Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);printf("占空比:%0.2f%% 頻率:%0.2fHz\n",DutyCycle,Frequency);}else{DutyCycle = 0;Frequency = 0;} }main
通用定時器初始化完之后,輸出PWM信號,高級定時器初始化完之后,捕獲通用定時器輸出的PWM信號。
通用定時器TIM3的通道1,PA6,用于輸出PWM信號。
高級控制定時器TIM1的通道1,PA8,用于PWM輸入捕獲。
用杜邦線短接PA6和PA8,用USB線連電腦,打開串口調(diào)試助手,可以看到捕獲到的PWM信號的頻率和占空比。
同時,可以通過仿真模擬的方法看到PA6,輸出的信號波形。
// TIM—高級定時器-PWM輸入捕獲應(yīng)用,通用定時器產(chǎn)生PWM波,高級定時器則捕獲這個PWM,并測量周期和占空比#include "stm32f10x.h" #include "bsp_led.h" #include "bsp_AdvanceTim.h" #include "bsp_GeneralTim.h" #include "bsp_usart.h"/*** @brief 主函數(shù)* @param 無 * @retval 無*/ int main(void) { /* 串口初始化 */USART_Config();/* 通用定時器初始化,用于生成PWM信號 */GENERAL_TIM_Init();/* 高級定時器初始化 ,用戶捕獲PWM信號*/ADVANCE_TIM_Init();while(1){ } }總結(jié)
以上是生活随笔為你收集整理的stm32 PWM输入捕获的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 方阵循环右移
- 下一篇: 使用权值衰减算法解决神经网络过拟合问题、