運用通用定時器測量輸入脈沖寬度
隨著生活水平的提高,定時器的用途也越來越廣泛。比如對開水機、熱水器的定時控制,現(xiàn)在有了大功率定時器,定時開機、定時關(guān)機,實現(xiàn)節(jié)能、安全、健康的使用。
一、硬件設(shè)計
選用通用定時器TIM5的CH1,其輸入管腳為PA0,在開發(fā)板上PA0連接按鍵,當(dāng)按鍵按下輸入高電平,按鍵松開輸入低電平,實驗測量高電平的脈沖寬度。
二、軟件設(shè)計
1. 配置中斷向量表的優(yōu)先級
因只使用一個中斷 TIM5_IRQn,搶占優(yōu)先級與子優(yōu)先級可隨意配置。
代碼如下:
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. 定時器模式配置,其中包含時基結(jié)構(gòu)體、輸入捕獲結(jié)構(gòu)體的初始化以及中斷的開啟。
static void GeneralTim_Config(void)
{
// 開啟定時器時鐘,即內(nèi)部時鐘CK_INT=72M
GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
/*--------------------時基結(jié)構(gòu)體初始化-------------------------*/
TIM_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_ICInitTypeDef TIM_ICInitStructure;
// 配置輸入捕獲的通道,需要根據(jù)具體的GPIO來配置
TIM_ICInitStructure.TIM_Channel = GENERAL_TIM_CHANNEL_x;
// 輸入捕獲信號的極性配置
TIM_ICInitStructure.TIM_ICPolarity = GENERAL_TIM_STRAT_ICPolarity;
// 輸入通道和捕獲通道的映射關(guān)系,有直連和非直連兩種
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
// 輸入的需要被捕獲的信號的分頻系數(shù)
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
// 輸入的需要被捕獲的信號的濾波系數(shù)
TIM_ICInitStructure.TIM_ICFilter = 0;
// 定時器輸入捕獲初始化
TIM_ICInit(GENERAL_TIM, &TIM_ICInitStructure);
// 清除更新和捕獲中斷標(biāo)志位
TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update|GENERAL_TIM_IT_CCx);
// 開啟更新和捕獲中斷
TIM_ITConfig (GENERAL_TIM, TIM_IT_Update | GENERAL_TIM_IT_CCx, ENABLE );
// 使能計數(shù)器
TIM_Cmd(GENERAL_TIM, ENABLE);
}
4. 輸入捕獲初始化函數(shù)
void GeneralTim_Init(void)
{
General_NVIC_Config();
General_GPIO_Gonfig();
GeneralTim_Config();
}
5. 中斷函數(shù)
首先判斷定時器是否溢出定時周期,并做處理。然后上升沿捕獲時將計數(shù)器寄存器的值清零,中斷改為下降沿觸發(fā)。下降沿捕獲中斷時,讀取計數(shù)值,改為上升沿觸發(fā),開始捕獲標(biāo)識清零,結(jié)束捕獲置1,。。。。。。。。
void GENERAL_TIM_INT_FUN(void)
{
// 當(dāng)要被捕獲的信號的周期大于定時器的最長定時時,定時器就會溢出,產(chǎn)生更新中斷
// 這個時候我們需要把這個最長的定時周期加到捕獲信號的時間里面去
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 )
{
// 計數(shù)器清0
TIM_SetCounter ( GENERAL_TIM, 0 );
// 自動重裝載寄存器更新標(biāo)志清0
TIM_ICUserValueStructure.Capture_Period = 0;
// 存捕獲比較寄存器的值的變量的值清0
TIM_ICUserValueStructure.Capture_CcrValue = 0;
// 當(dāng)?shù)谝淮尾东@到上升沿之后,就把捕獲邊沿配置為下降沿
GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Falling);
// 開始捕獲標(biāo)準(zhǔn)置1
TIM_ICUserValueStructure.Capture_StartFlag = 1;
}
// 下降沿捕獲中斷
else // 第二次捕獲
{
// 獲取捕獲比較寄存器的值,這個值就是捕獲到的高電平的時間的值
TIM_ICUserValueStructure.Capture_CcrValue =
GENERAL_TIM_GetCapturex_FUN (GENERAL_TIM);
// 當(dāng)?shù)诙尾东@到下降沿之后,就把捕獲邊沿配置為上升沿,好開啟新的一輪捕獲
GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Rising);
// 開始捕獲標(biāo)志清0
TIM_ICUserValueStructure.Capture_StartFlag = 0;
// 捕獲完成標(biāo)志置1
TIM_ICUserValueStructure.Capture_FinishFlag = 1;
}
TIM_ClearITPendingBit (GENERAL_TIM,GENERAL_TIM_IT_CCx);
}
}
6. 主函數(shù),計算脈沖寬度利用串口輸出
int main()
{
uint32_t time;
// TIM 計數(shù)器的驅(qū)動時鐘
float TIM_PscCLK = 72000000.0 / (GENERAL_TIM_PSC+1);
USART_Config();
GeneralTim_Init();
printf("rn ----輸入捕獲測量脈寬實驗----rn");
while(1)
{
if(TIM_ICUserValueStructure.Capture_FinishFlag == 1)
{
time = (TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD + 1)
+ TIM_ICUserValueStructure.Capture_CcrValue + 1);
printf("t=%fn",time/TIM_PscCLK);
TIM_ICUserValueStructure.Capture_FinishFlag = 0;
}
}
}
7. 相關(guān)宏定義
#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相關(guān)宏定義
#define