通用定時器作爲輸入捕獲的使用。我們將用 TIM5 的通道 1 (PA0)來做輸入捕獲,捕獲 PA0 上高電平的脈寬(用 WK_UP 按鍵輸入高電平),通過串口打印高電平脈寬時間
輸入捕獲簡介
輸入捕獲模式可以用來測量脈衝寬度或者測量頻率。 STM32 的定時器,除了 TIM6 和 TIM7,其他定時器都有輸入捕獲功能。STM32 的輸入捕獲,簡單的說就是通過檢測 TIMx_CHx 上的邊沿信號,在邊沿信號發生跳變(比如上升沿/下降沿)的時候,將當前定時器的值(TIMx_CNT)存放到對應的通道的捕獲/比較寄存器(TIMx_CCRx)裏面,完成一次捕獲。同時還可以配置捕獲時是否觸發中斷/DMA 等。
我們用到 TIM5_CH1 來捕獲高電平脈寬,也就是要先設置輸入捕獲爲上升沿檢測,記錄發生上升沿的時候 TIM5_CNT 的值。然後配置捕獲信號爲下降沿捕獲,當下降沿到來時,發生捕獲,並記錄此時的 TIM5_CNT 值。這樣,前後兩次 TIM5_CNT 之差,就是高電平的脈寬,同時 TIM5 的計數頻率我們是知道的,從而可以計算出高電平脈寬的準確時間。
輸入捕獲的配置步驟:
1)開啓 TIM5 時鐘和 GPIOA 時鐘,配置 P A0 爲下拉輸入。
要使用 TIM5,我們必須先開啓 TIM5 的時鐘。這裏我們還要配置 P A0 爲下拉輸入,因爲我們要捕獲 TIM5_CH1 上面的高電平脈寬,而 TIM5_CH1 是連接在 PA0 上面的。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能 TIM5 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 時鐘
2)初始化 TIM5,設置 TIM5 的 ARR 和 PSC。
在開啓了 TIM5 的時鐘之後,我們要設置 ARR 和 PSC 兩個寄存器的值來設置輸入捕獲的自動重裝載值和計數頻率。 這在庫函數中是通過 TIM_TimeBaseInit 函數實現的
點擊(此處)摺疊或打開
-
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
-
TIM_TimeBaseStructure.TIM_Period = arr; //設定計數器自動重裝值
-
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置預分頻值
-
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //
TDTS = Tck_tim
-
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM
向上計數模式
- TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
3)設置 TIM5 的輸入比較參數,開啓輸入捕獲
輸入比較參數的設置包括映射關係,濾波,分頻以及捕獲方式等。這裏我們需要設置通道 1爲輸入模式,且 IC1 映射到 TI1(通道 1)上面,並且不使用濾波(提高響應速度)器,上升沿捕獲。庫函數是通過 TIM_ICInit 函數來初始化輸入比較參數的:
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
同樣,我們來看看參數設置結構體 TIM_ICInitTypeDef 的定義:
點擊(此處)摺疊或打開
-
typedef struct
-
{
-
uint16_t TIM_Channel; //設置通道
-
uint16_t TIM_ICPolarity; //設 置 輸 入 信 號 的 有效 捕獲 極性
-
uint16_t TIM_ICSelection; //設置映射關係
-
uint16_t TIM_ICPrescaler; //設置 輸入捕獲分頻係數
-
uint16_t TIM_ICFilter; //設置濾波器長度
- } TIM_ICInitTypeDef;
配置代碼是:
點擊(此處)摺疊或打開
-
TIM_ICInitTypeDef TIM5_ICInitStructure;
-
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇輸入端
IC1 映射到 TI1 上
-
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲
-
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到
TI1 上
-
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置輸入分頻,不分頻
-
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000
配置輸入濾波器 不濾波
- TIM_ICInit(TIM5, &TIM5_ICInitStructure);
4)使能捕獲和更新中斷(設置 TIM5 的 DIER 寄存器)
因爲我們要捕獲的是高電平信號的脈寬,所以,第一次捕獲是上升沿,第二次捕獲時下降沿,必須在捕獲上升沿之後,設置捕獲邊沿爲下降沿,同時,如果脈寬比較長,那麼定時器就會溢出,對溢出必須做處理,否則結果就不準了。這兩件事,我們都在中斷裏面做,所以必須開啓捕獲中斷和更新中斷。
這裏我們使用定時器的開中斷函數 TIM_ITConfig 即可使能捕獲和更新中斷:
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允許更新中斷和捕獲中斷
5)設置中斷分組,編寫中斷服務函數
設置中斷分組主要是通過函數 NVIC_Init()來完成。分組完成後,我們還需要在中斷函數裏面完成數據處理和捕獲設置等關鍵操作,從而實現高電平脈寬統計。在中斷服務函數裏面,跟以前的外部中斷和定時器中斷實驗中一樣,我們在中斷開始的時候要進行中斷類型判斷,在中斷結束的時候要清除中斷標誌位。使用到的函數分別爲 TIM_GetITStatus()函數和 TIM_ClearITPendingBit()函數。
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判斷是否爲更新中斷
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判斷是否發生捕獲事件
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中斷和捕獲標誌位
6)使能定時器(設置 TIM5 的 CR1 寄存器)
最後,必須打開定時器的計數器開關, 啓動 TIM5 的計數器,開始輸入捕獲。
TIM_Cmd(TIM5,ENABLE ); //使能定時器 5
例程:
點擊(此處)摺疊或打開
-
#include "timer.h"
-
#include "led.h"
-
#include "usart.h"
-
-
/**
-
* 定時器5通道1輸入捕獲配置
-
*/
-
void TIM5_Cap_Init(u16 arr,u16 psc)
-
{
-
GPIO_InitTypeDef GPIO_InitStructure;
-
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
-
TIM_ICInitTypeDef TIM5_ICInitStructure;
-
NVIC_InitTypeDef NVIC_InitStructure;
-
-
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); /*使能TIM5時鐘*/
-
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); /*使能GPIOA時鐘*/
-
-
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; /**/
-
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; /*PA0
輸入*/
-
GPIO_Init(GPIOA,&GPIO_InitStructure);
-
GPIO_ResetBits(GPIOA,GPIO_Pin_0); /*PA0
下拉*/
-
-
/*初始化定時器5 TIM5*/
-
TIM_TimeBaseStructure.TIM_Period = arr; /*設定計數器自動重裝值
*/
-
TIM_TimeBaseStructure.TIM_Prescaler = psc; /*預分頻器
*/
-
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; /*設置時鐘分割:TDTS
= Tck_tim*/
-
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /*TIM向上計數模式*/
-
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure); /*根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位*/
-
-
/* 初始化TIM5輸入捕獲參數 */
-
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; /*CC1S=01
選擇輸入端 IC1映射到TI1上*/
-
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; /*上升沿捕獲*/
-
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; /*映射到TI1上*/
-
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; /*配置輸入分頻,不分頻*/
-
TIM5_ICInitStructure.TIM_ICFilter = 0; /*IC1F=0000
配置輸入濾波器 不濾波*/
-
TIM_ICInit(TIM5,&TIM5_ICInitStructure);
-
-
/*中斷分組初始化*/
-
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; /*TIM5中斷*/
-
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; /*先佔優先級2級*/
-
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /*從優先級0級*/
-
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /*IRQ通道被使能*/
-
NVIC_Init(&NVIC_InitStructure);
-
-
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);/*允許更新中斷
,允許CC1IE捕獲中斷*/
-
TIM_Cmd(TIM5,ENABLE); /*使能定時器5*/
-
}
-
-
u8 TIM5CH1_CAPTURE_STA=0; //輸入捕獲狀態
-
u16 TIM5CH1_CAPTURE_VAL; //輸入捕獲值
-
-
/**
-
* 定時器5中斷服務程序
-
*/
-
void TIM5_IRQHandler(void)
-
{
-
if((TIM5CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲
-
{
-
if(TIM_GetITStatus(TIM5,TIM_IT_Update) != RESET)
-
{
-
if(TIM5CH1_CAPTURE_STA&0X40)//已經捕獲到高電平了
-
{
-
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
-
{
-
TIM5CH1_CAPTURE_STA|=0X80;//標記成功捕獲了一次
-
TIM5CH1_CAPTURE_VAL=0XFFFF;
-
}else TIM5CH1_CAPTURE_STA++;
-
}
-
}
-
-
if(TIM_GetITStatus(TIM5,TIM_IT_CC1) !=RESET)
-
{
-
if(TIM5CH1_CAPTURE_STA & 0x40)
-
{
-
TIM5CH1_CAPTURE_STA|=0X80; //標記成功捕獲到一次上升沿
-
TIM5CH1_CAPTURE_VAL = TIM_GetCounter(TIM5);
-
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0
設置爲上升沿捕獲
-
}
-
else
-
{
-
TIM5CH1_CAPTURE_STA=0; //清空
-
TIM5CH1_CAPTURE_VAL=0;
-
-
TIM_SetCounter(TIM5,0);
-
TIM5CH1_CAPTURE_STA|=0X40; //標記捕獲到了上升沿
-
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1
設置爲下降沿捕獲
-
}
-
}
-
-
}
-
TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update); /*清除中斷標誌位*/
- }
點擊(此處)摺疊或打開
-
extern u8 TIM5CH1_CAPTURE_STA; //輸入捕獲狀態
-
extern u16 TIM5CH1_CAPTURE_VAL; //輸入捕獲值
-
int main(void)
-
{
-
u32 temp=0;
-
delay_init(); //延時函數初始化
-
NVIC_Configuration(); //設置NVIC中斷分組2:2位搶佔優先級,2位響應優先級
-
uart_init(9600); //串口初始化爲9600
-
LED_Init(); //LED端口初始化
-
-
TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz的頻率計數
-
while(1)
-
{
-
delay_ms(10);
-
-
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上升沿
-
{
-
temp=TIM5CH1_CAPTURE_STA&0X3F;
-
temp*=65536;//溢出時間總和
-
temp+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
-
printf("HIGH:%d us\r\n",temp);//打印總的高點平時間
-
TIM5CH1_CAPTURE_STA=0;//開啓下一次捕獲
-
}
-
}
- }