山東網(wǎng)站制作團隊網(wǎng)店培訓教程
一、輸入捕獲介紹
????????在定時器中斷實驗章節(jié)中我們介紹了通用定時器具有多種功能,輸入捕獲就是其中一種。 STM32F1除了基本定時器TIM6和TIM7,其他定時器都具有輸入捕獲功能 。輸入捕獲可以對輸入的信號的上升沿,下降沿或者雙邊沿進行捕獲,通常用于測量輸入信號的脈寬、測量 PWM 輸入信號的頻率及占空比。
????????輸入捕獲的工作原理比較簡單,在輸入捕獲模式下,當相應的 ICx信號檢測到跳變沿后,將使用捕獲/比較寄存器(TIMx_CCRx)來鎖存計數(shù)器的值。簡單的說就是通過檢測TIMx_CHx上的邊沿信號,在邊沿信號發(fā)生跳變(比如上升沿/下降沿)的時候,將當前定時器的值(TIMx_CNT)存放到對應的通道的捕獲/比較寄存(TIMx_CCRx)里面,完成一次捕獲。同時還可以配置捕獲時是否觸發(fā)中斷/DMA 等。
?????????在stm32中文手冊中有如下圖(也就是通用定時器的結(jié)構圖):
在通用定時器中,輸入捕獲主要用到以上部分,STM32的每個通用定時器都有4個輸入捕獲的通道,分別是TIMx_CH1、TIMx_CH2、TIMx_CH3、TIMx_CH4。我們可以在輸入濾波器和邊沿檢測器中設置我們需要捕獲的是上升沿還是下降沿,假設我們需要捕獲上升沿,則當濾波器和邊沿檢測器捕獲到上升沿后,CNT計數(shù)器中的值會加1,同時捕獲/比較寄存器中會鎖存計數(shù)器的值。
二、輸入捕獲配置步驟
接下來我們介紹下如何使用庫函數(shù)對通用定時器的輸入捕獲進行配置 。這個也是在編寫程序中必須要了解的。其實輸入捕獲和前面定時器中斷一樣也是通用定時器的一個功能,因此還是要用到定時器的相關配置函數(shù),具體步驟如下:(定時器相關庫函數(shù)在stm32f10x_tim.c和
stm32f10x_tim.h文件中)。
(1)使能定時器及端口時鐘,并設置引腳復用器映射和引腳模式等(以PA0為例)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

其中需要將PA0端口進行復用,復用為TIM5的通道1,所以我們需要開啟復用時鐘,GPIOA時鐘。
(2)初始化定時器參數(shù),包含自動重裝值,分頻系數(shù),計數(shù)方式等
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct);
?(3)設置通用定時器的輸入捕獲參數(shù),開啟輸入捕獲功能
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
其中TIM_ICInitTypeDef結(jié)構體中的成員大致意思為:
typedef struct{uint16_t TIM_Channel; //通道uint16_t TIM_ICPolarity; //捕獲極性uint16_t TIM_ICSelection;//映射uint16_t TIM_ICPrescaler;//分頻系數(shù)uint16_t TIM_ICFilter; //濾波器長度} TIM_ICInitTypeDef;
如果我們需要配置TIM5的通道1為輸入捕獲功能,并且為上升沿捕獲。不分頻、直接映射到TI,可以如下配置:
?TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; //通道1TIM_ICInitStructure.TIM_ICFilter=0x00; //濾波TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//捕獲極性TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //分頻系數(shù)TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//直接映射到TI1TIM_ICInit(TIM5,&TIM_ICInitStructure);
?(4)開啟捕獲和定時器溢出(更新)中斷
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE)
(5)設置定時器中斷優(yōu)先級,使能定時器中斷通道?
?NVIC初始化庫函數(shù)是NVIC_Init()
(6)編寫定時器中斷服務函數(shù)?
TIM5_IRQHandlerITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);TIM_SetCounter(TIM5,0); //定時器初值為0
(7)使能定時器?
?void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
?下面有一個輸入捕獲大致代碼(以判斷但雙擊按鍵為例):
void Tim_Input_Capture(u16 per,u16 psc)
{GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_ICInitTypeDef TIM_ICInitStruct;NVIC_InitTypeDef NVIC_InitStruct;/*1、打開外設時鐘*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO , ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);/*2、配置GPIO*/GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA, &GPIO_InitStruct);/*3、配置定時器*/TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period = per;TIM_TimeBaseInitStruct.TIM_Prescaler = psc;TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStruct);/*4、配置輸入捕獲*/TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;TIM_ICInitStruct.TIM_ICFilter = 0x0;TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM5, &TIM_ICInitStruct);/*5、配置定時器中斷*/TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1, ENABLE);/*6、配置NVIC*/NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStruct);/*7、使能定時器*/TIM_Cmd(TIM5, ENABLE);
}
服務中斷函數(shù):
void TIM5_IRQHandler(void)
{if((input_state & NEXT_RISING ) != SET){if(TIM_GetITStatus(TIM5, TIM_IT_Update) == SET){if(input_state & NEXT_FALLING)//捕獲到上升沿{if((input_state & 0x3F) == 0x3F)//如果溢出次數(shù)超出閾值{input_value = 0xFFFF;input_state |= NEXT_RISING;}elseinput_state++;}}if(TIM_GetITStatus(TIM5, TIM_IT_CC1) == SET){if(input_state & NEXT_FALLING)//捕獲到下降沿{//獲取捕獲到的值//改為上升沿捕獲input_value = TIM_GetCapture1(TIM5);TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);input_state |= NEXT_RISING;}else//捕獲到上升沿{//清零input_state和input_value//關閉定時器//清空當前計數(shù)值//將下一次捕獲改為下降沿捕獲//標志下一次捕獲下降沿//打開定時器input_state = 0;input_value = 0;TIM_Cmd(TIM5, DISABLE);TIM_SetCounter(TIM5, 0);TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);input_state |= NEXT_FALLING;TIM_Cmd(TIM5, ENABLE);}}}TIM_ClearITPendingBit(TIM5, TIM_IT_Update | TIM_IT_CC1);
}