STM32F103_通用定時器“輸入捕獲”測量輸入脈衝寬度
阿新 • • 發佈:2019-02-08
一、硬體設計
選用通用定時器TIM5的CH1,其輸入管腳為PA0,在開發板上PA0連線按鍵,當按鍵按下輸入高電平,按鍵鬆開輸入低電平,實驗測量高電平的脈衝寬度。
二、軟體設計
1. 配置中斷向量表的優先順序
因只使用一箇中斷 TIM5_IRQn,搶佔優先順序與子優先順序可隨意配置。
程式碼如下:
static void General_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig (NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_Init(&NVIC_InitStructure); }
2. GPIO配置
PA0配置為浮空輸入模式。
static void General_GPIO_Gonfig(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK , ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN; GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure); }
3. 定時器模式配置,其中包含時基結構體、輸入捕獲結構體的初始化以及中斷的開啟。
static void GeneralTim_Config(void) { // 開啟定時器時鐘,即內部時鐘CK_INT=72M GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE); /*--------------------時基結構體初始化-------------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 自動重灌載暫存器的值,累計TIM_Period+1個頻率後產生一個更新或者中斷 TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD; // 驅動CNT計數器的時鐘 = Fck_int/(psc+1) TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_PSC; // 時鐘分頻因子 ,配置死區時間時需要用到 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 計數器計數模式,設定為向上計數 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重複計數器的值,沒用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter=0; // 初始化定時器 TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure); /*--------------------輸入捕獲結構體初始化-------------------*/ TIM_ICInitTypeDef TIM_ICInitStructure; // 配置輸入捕獲的通道,需要根據具體的GPIO來配置 TIM_ICInitStructure.TIM_Channel = GENERAL_TIM_CHANNEL_x; // 輸入捕獲訊號的極性配置 TIM_ICInitStructure.TIM_ICPolarity = GENERAL_TIM_STRAT_ICPolarity; // 輸入通道和捕獲通道的對映關係,有直連和非直連兩種 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 輸入的需要被捕獲的訊號的分頻係數 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 輸入的需要被捕獲的訊號的濾波係數 TIM_ICInitStructure.TIM_ICFilter = 0; // 定時器輸入捕獲初始化 TIM_ICInit(GENERAL_TIM, &TIM_ICInitStructure); // 清除更新和捕獲中斷標誌位 TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update|GENERAL_TIM_IT_CCx); // 開啟更新和捕獲中斷 TIM_ITConfig (GENERAL_TIM, TIM_IT_Update | GENERAL_TIM_IT_CCx, ENABLE ); // 使能計數器 TIM_Cmd(GENERAL_TIM, ENABLE); }
4. 輸入捕獲初始化函式
void GeneralTim_Init(void)
{
General_NVIC_Config();
General_GPIO_Gonfig();
GeneralTim_Config();
}
5. 中斷函式
首先判斷定時器是否溢位定時週期,並做處理。然後上升沿捕獲時將計數器暫存器的值清零,中斷改為下降沿觸發。下降沿捕獲中斷時,讀取計數值,改為上升沿觸發,開始捕獲標識清零,結束捕獲置1,。。。。。。。。
void GENERAL_TIM_INT_FUN(void)
{
// 當要被捕獲的訊號的週期大於定時器的最長定時時,定時器就會溢位,產生更新中斷
// 這個時候我們需要把這個最長的定時週期加到捕獲訊號的時間裡面去
if ( TIM_GetITStatus ( GENERAL_TIM, TIM_IT_Update) != RESET )
{
TIM_ICUserValueStructure.Capture_Period ++;
TIM_ClearITPendingBit ( GENERAL_TIM, TIM_FLAG_Update );
}
// 上升沿捕獲中斷
if ( TIM_GetITStatus (GENERAL_TIM, GENERAL_TIM_IT_CCx ) != RESET)
{
// 第一次捕獲
if ( TIM_ICUserValueStructure.Capture_StartFlag == 0 )
{
// 計數器清0
TIM_SetCounter ( GENERAL_TIM, 0 );
// 自動重灌載暫存器更新標誌清0
TIM_ICUserValueStructure.Capture_Period = 0;
// 存捕獲比較暫存器的值的變數的值清0
TIM_ICUserValueStructure.Capture_CcrValue = 0;
// 當第一次捕獲到上升沿之後,就把捕獲邊沿配置為下降沿
GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Falling);
// 開始捕獲標準置1
TIM_ICUserValueStructure.Capture_StartFlag = 1;
}
// 下降沿捕獲中斷
else // 第二次捕獲
{
// 獲取捕獲比較暫存器的值,這個值就是捕獲到的高電平的時間的值
TIM_ICUserValueStructure.Capture_CcrValue =
GENERAL_TIM_GetCapturex_FUN (GENERAL_TIM);
// 當第二次捕獲到下降沿之後,就把捕獲邊沿配置為上升沿,好開啟新的一輪捕獲
GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Rising);
// 開始捕獲標誌清0
TIM_ICUserValueStructure.Capture_StartFlag = 0;
// 捕獲完成標誌置1
TIM_ICUserValueStructure.Capture_FinishFlag = 1;
}
TIM_ClearITPendingBit (GENERAL_TIM,GENERAL_TIM_IT_CCx);
}
}
6. 主函式,計算脈衝寬度利用串列埠輸出
int main()
{
uint32_t time;
// TIM 計數器的驅動時鐘
float TIM_PscCLK = 72000000.0 / (GENERAL_TIM_PSC+1);
USART_Config();
GeneralTim_Init();
printf("\r\n ----輸入捕獲測量脈寬實驗----\r\n");
while(1)
{
if(TIM_ICUserValueStructure.Capture_FinishFlag == 1)
{
time = (TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD + 1)
+ TIM_ICUserValueStructure.Capture_CcrValue + 1);
printf("t=%f\n",time/TIM_PscCLK);
TIM_ICUserValueStructure.Capture_FinishFlag = 0;
}
}
}
7. 相關巨集定義
#define GENERAL_TIM TIM5
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM5
#define GENERAL_TIM_PERIOD 0XFFFF
#define GENERAL_TIM_PSC (72-1)
// TIM 輸入捕獲通道GPIO相關巨集定義
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_0
#define GENERAL_TIM_CHANNEL_x TIM_Channel_1
// 中斷相關巨集定義
#define GENERAL_TIM_IT_CCx TIM_IT_CC1
#define GENERAL_TIM_IRQ TIM5_IRQn
#define GENERAL_TIM_INT_FUN TIM5_IRQHandler
// 獲取捕獲暫存器值函式巨集定義
#define GENERAL_TIM_GetCapturex_FUN TIM_GetCapture1
// 捕獲訊號極性函式巨集定義
#define GENERAL_TIM_OCxPolarityConfig_FUN TIM_OC1PolarityConfig
// 測量的起始邊沿
#define GENERAL_TIM_STRAT_ICPolarity TIM_ICPolarity_Rising
// 測量的結束邊沿
#define GENERAL_TIM_END_ICPolarity TIM_ICPolarity_Falling
// 定時器輸入捕獲使用者自定義變數結構體宣告
typedef struct
{
uint8_t Capture_FinishFlag; // 捕獲結束標誌位
uint8_t Capture_StartFlag; // 捕獲開始標誌位
uint16_t Capture_CcrValue; // 捕獲暫存器的值
uint16_t Capture_Period; // 自動重灌載暫存器更新標誌
}TIM_ICUserValueTypeDef;
extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure ; / /在c檔案中已經定義
/**************************函式宣告********************************/
void GENERAL_TIM_Init(void);
參考資料:野火《stm32庫卡發實戰指南》