STM32標準庫定時器輸入捕獲 1.輸入捕獲介紹 輸入捕獲為STM32定時器的一個功能,可以用來測量輸入信號的頻率和占空比。 具體原理:當輸入信號經過比較捕獲通道時,STM32會依據通道的極性設置決定是否觸發捕獲中斷TIM_IT_CCx。此時定時器會將當前計數值TIMx->CNT的值保存在TIMx- ...
STM32標準庫定時器輸入捕獲
1.輸入捕獲介紹
輸入捕獲為STM32定時器的一個功能,可以用來測量輸入信號的頻率和占空比。
具體原理:當輸入信號經過比較捕獲通道時,STM32會依據通道的極性設置決定是否觸發捕獲中斷TIM_IT_CCx。此時定時器會將當前計數值TIMx->CNT的值保存在TIMx->CCRx中,通過計算兩次捕獲中斷的時間差便可計算出捕獲的電平時長,由此可計算出輸入信號的頻率、周期、占空比等信息。
在本文中,使用野火指南者開發板,配置TIM2定時器的通道4為輸入通道,TIM3定時器的通道1為輸出通道。
2. 輸入捕獲通道與定時器初始化
需要引用頭文件
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
void TIM2_Init() // 定時器2初始化
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); // 使能定時器2的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 使能GPIOA的時鐘
GPIO_InitTypeDef GPIO_InitStructure; // 定義GPIO_InitTypeDef類型的結構體
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; // 定義TIM_TimeBaseInitTypeDef類型的結構體
TIM_ICInitTypeDef TIM_IC_nitStructure; // 定義TIM_ICInitTypeDef類型的結構體
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ; // 選擇通道4的引腳
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 設置通道4為浮空輸入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 設置引腳速度為50MHz
GPIO_Init(GPIOA,&GPIO_InitStructure); // 初始化GPIOA
TIM_TimeBaseInitStructure.TIM_Period = 1000-1; // 設置定時器2的自動重裝值,計數到1000-1
TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1; // 設置定時器2的預分頻值,分頻720-1
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 設置時鐘分割
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 設置計數器模式為向上計數
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); // 初始化定時器2
TIM_IC_nitStructure.TIM_Channel = TIM_Channel_4; // 選擇通道4
TIM_IC_nitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 設置通道4的上升沿觸發
TIM_IC_nitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 設置通道4的輸入分頻器
TIM_IC_nitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 設置通道4映射到TI4
TIM_IC_nitStructure.TIM_ICFilter = 0x00; // 設置通道4的濾波器
TIM_ICInit(TIM2,&TIM_IC_nitStructure); // 初始化定時器2的通道4
NVIC_InitTypeDef NVIC_InitStructure; // 定義NVIC_InitTypeDef結構體變數
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 選擇定時器2的中斷通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 設置中斷優先順序
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 設置中斷子優先順序
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中斷通道
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC_InitTypeDef結構體變數
TIM_ITConfig(TIM2,TIM_IT_CC4 | TIM_IT_Update ,ENABLE); // 使能定時器2的通道4的中斷和更新中斷
TIM_Cmd(TIM2,ENABLE); // 使能定時器2
}
需要註意輸入通道引腳為GPIO_Mode_IN_FLOATING模式,TIM_Period為定時器溢出值。
-
TIM_ICInitTypeDef:輸入捕獲通道配置結構體。
-
TIM_Channel:輸入通道,可選參數為TIM_Channel_x。
-
TIM_ICPolarity:輸入通道極性設置,可選參數為TIM_ICSelection_DirectTI、TIM_ICSelection_IndirectTI、TIM_ICSelection_TRC。
-
TIM_ICSelection_DirectTI:將定時器輸入通道1、2、3、4依次映射到IC1、IC2、IC3、IC4。
-
TIM_ICSelection_IndirectTI:將定時器輸入通道1、2、3、4依次映射到IC2、IC1、IC4、IC3。
-
TIM_ICSelection_TRC:將定時器輸入通道1、2、3、4連接至TRC
我暫時也不知道這個TRC是啥。
-
-
TIM_ICFilter:輸入通道濾波器設置,可選參數為0x0~0xF。決定了多少次邊沿變換會觸發一次輸入捕獲。
-
3. 中斷函數編寫
輸入捕獲中斷與定時器中斷共用一個中斷NVIC。
uint16_t Up_Capture_Cnt,Down_Capture_Cnt,Up_Capture,Up_Capture_Cnt_Temp,Down_Capture;
uint16_t timer_cnt2,timer_cnt1 = 0;
uint16_t Get_State = 0,Get_State1 = 0;
void TIM2_IRQHandler() // 定時器2中斷函數
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET) // 定時器2更新中斷
{
timer_cnt1++; // 定時器計數標誌量1每溢出一次加一
timer_cnt2++; // 定時器計數標誌量2每溢出一次加一
if(timer_cnt1 == 10000) // 定時器計數標誌量1溢出時清零
{
timer_cnt1 = 0; // 定時器計數標誌量1清零
}
if(timer_cnt2 == 10000) // 定時器計數標誌量2溢出時清零
{
timer_cnt2 = 0; // 定時器計數標誌量2清零
}
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC4) == SET) // 定時器2輸入捕獲中斷
{
switch(Get_State) // 判斷輸入捕獲狀態
{
case 0 :
Up_Capture_Cnt_Temp = Up_Capture_Cnt; // 保存上一次輸入捕獲通道的值
Down_Capture_Cnt = TIM_GetCapture4(TIM2); // 獲取當前輸入捕獲通道的值
Down_Capture = Down_Capture_Cnt + (timer_cnt2 * 1000) - Up_Capture_Cnt_Temp; // 計算脈衝寬度
timer_cnt1 = 0; // 定時器計數標誌量1清零
timer_cnt2 = 0; // 定時器計數標誌量2清零
TIM_ClearITPendingBit(TIM2,TIM_IT_CC4); // 清除輸入捕獲通道的中斷標誌位
TIM_OC4PolarityConfig(TIM2,TIM_ICPolarity_Falling); // 設置輸入捕獲通道的極性為下降沿
Get_State = 1; // 設置輸入捕獲通道的狀態為1
break; // 跳出switch語句
case 1:
Up_Capture_Cnt = TIM_GetCapture4(TIM2); // 獲取當前輸入捕獲通道的值
Up_Capture = Up_Capture_Cnt + (timer_cnt1 * 1000) - Down_Capture_Cnt; // 計算脈衝寬度
timer_cnt1 = 0; // 定時器計數標誌量1清零
timer_cnt2 = 0; // 定時器計數標誌量2清零
TIM_ClearITPendingBit(TIM2,TIM_IT_CC4); // 清除輸入捕獲通道的中斷標誌位
TIM_OC4PolarityConfig(TIM2,TIM_ICPolarity_Rising); // 設置輸入捕獲通道的極性為上升沿
Get_State = 0; // 設置輸入捕獲通道的狀態為0
break; // 跳出switch語句
}
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); // 清除定時器溢出中斷標誌位
}
4. 中斷函數代碼具體邏輯解釋
光看代碼可能捋不清先後關係,來看下圖就知道了,如圖1所示: