輸入捕獲作為定時器的一個功能,在工業(yè)測速上有很大的應(yīng)用。STM32的一些定時器具有四個外部通道,可利用一個定時器采集外部四路脈沖頻率,節(jié)約硬件資源和軟件代碼
如需要測量一個或多個外部方波脈沖頻率,頻率低于單片機運行頻率,可如下操作:(以TIM4為例)
初始化:(省略GPIO配置,將TIM4的四個通道引腳配置為上拉或浮空輸入,省略定時器RCC配置,省略中斷NVIC配置)
void TIM_Configuration(void)
{
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // TIM4 時基
TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Period =0xffff;//自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler =719;//預(yù)分頻值, 使TIMx_CLK=1MHz
TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;//輸入時鐘不分頻
TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//向上計數(shù)
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);//TIM4_TimeBase
// TIM_ICInitStructure.TIM_ICMode =TIM_ICMode_ICAP; //輸入捕捉方式
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//|TIM_Channel_2; //輸入通道
TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿
TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中斷
TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分頻
TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉輸入不濾波
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;//|TIM_Channel_2; //輸入通道
TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿
TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中斷
TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分頻
TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉輸入不濾波
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3 ;//|TIM_Channel_2; //輸入通道
TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿
TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中斷
TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分頻
TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉輸入不濾波
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4 ;//|TIM_Channel_2; //輸入通道
TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿
TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中斷
TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分頻
TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉輸入不濾波
TIM_ICInit(TIM4, &TIM_ICInitStructure);
TIM_Cmd(TIM4, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);
}
其中:
TIM_TimeBaseStructure.TIM_Period = 0xffff;為自動重裝值,與普通單片機一樣
TIM_TimeBaseStructure.TIM_Prescaler = 719; 預(yù)分頻值, 使TIMx_CLK=100KHz ,系統(tǒng)時鐘運行于72M時720分頻,定時器運行于100KHZ,即10us每分度
TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP; 此句選擇定時器為輸入捕獲模式,但在我的庫函數(shù)下未定義,所以注釋掉,未影響程序執(zhí)行
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;配置通道1
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;上升沿捕獲
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;捕獲中斷
TIM_ICInitStructure.TIM_ICFilter = 0x0;不濾波
TIM_ICInit(TIM4, &TIM_ICInitStructure);將配置應(yīng)用
以上每個通道都需要將整個配置再寫一遍,使用與'|'是無效的。
TIM_Cmd(TIM4, ENABLE);使能定時器4
TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);
TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);打開四個通道的捕獲中斷
以上將TIM配置完成,下面是中斷內(nèi)代碼:
void
TIM4_IRQHandler(void)
{
//頻率緩沖區(qū)計數(shù)
static u16 this_time_CH1 = 0;
static u16 last_time_CH1 = 0;
static u8 capture_number_CH1 = 0;
vu16 tmp16_CH1;
static u16 this_time_CH2 = 0;
static u16 last_time_CH2 = 0;
static u8 capture_number_CH2 = 0;
vu16 tmp16_CH2;
static u16 this_time_CH3 = 0;
static u16 last_time_CH3 = 0;
static u8 capture_number_CH3 = 0;
vu16 tmp16_CH3;
static u16 this_time_CH4 = 0;
static u16 last_time_CH4 = 0;
static u8 capture_number_CH4 = 0;
vu16 tmp16_CH4;
if(TIM_GetITStatus(TIM4, TIM_IT_CC1) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
if(capture_number_CH1 == 0)
{
capture_number_CH1 = 1;
last_time_CH1 = TIM_GetCapture1(TIM4);
}
else if(capture_number_CH1 == 1)
{
capture_number_CH1 = 0;
this_time_CH1 = TIM_GetCapture1(TIM4);
if(this_time_CH1 > last_time_CH1)
{
tmp16_CH1 = (this_time_CH1 - last_time_CH1);
}
else
{
tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);
}
//TIM2 counter clock = 1MHz
//
FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100為擴大顯示量程
Freq_Value[0]=tmp16_CH1;
}
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC2) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);
if(capture_number_CH2 == 0)
{
capture_number_CH2 = 1;
last_time_CH2 = TIM_GetCapture2(TIM4);
}
else if(capture_number_CH2 == 1)
{
capture_number_CH2 = 0;
this_time_CH2 = TIM_GetCapture2(TIM4);
if(this_time_CH2 > last_time_CH2)
{
tmp16_CH2 = (this_time_CH2 - last_time_CH2);
}
else
{
tmp16_CH2 = ((0xFFFF - last_time_CH2) + this_time_CH2);
}
//TIM2 counter clock = 1MHz
//
FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100為擴大顯示量程
Freq_Value[1]=tmp16_CH2;
}
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC3) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC3);
if(capture_number_CH3 == 0)
{
capture_number_CH3 = 1;
last_time_CH3 = TIM_GetCapture3(TIM4);
}
else if(capture_number_CH3 == 1)
{
capture_number_CH3 = 0;
this_time_CH3 = TIM_GetCapture3(TIM4);
if(this_time_CH3 > last_time_CH3)
{
tmp16_CH3 = (this_time_CH3 - last_time_CH3);
}
else
{
tmp16_CH3 = ((0xFFFF - last_time_CH3) + this_time_CH3);
}
//TIM2 counter clock = 1MHz //
FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100為擴大顯示量程
Freq_Value[2]=tmp16_CH3;
}
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC4) == SET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);
if(capture_number_CH4 == 0)
{
capture_number_CH4 = 1;
last_time_CH4 = TIM_GetCapture4(TIM4);
}
else if(capture_number_CH4 == 1)
{
capture_number_CH4 = 0;
this_time_CH4 = TIM_GetCapture4(TIM4);
if(this_time_CH4 > last_time_CH4)
{
tmp16_CH4 = (this_time_CH4 - last_time_CH4);
}
else
{
tmp16_CH4 = ((0xFFFF - last_time_CH4) + this_time_CH4);
}
//TIM2 counter clock = 1MHz //
FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100為擴大顯示量程
Freq_Value[3]=tmp16_CH4;
}
}//
GPIO_WriteBit(GPIOC, GPIO_Pin_13,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))));
}
中斷內(nèi)四部分代碼完全一樣,只分析其中一段輸入捕獲的原理是,
定時器正常計數(shù)運行,當(dāng)外部脈沖到來時,將定時器計數(shù)值存起來,當(dāng)下次脈沖到來時,求出這兩次計數(shù)值差值,即為這兩段脈沖的周期。
例如,
定時器計數(shù)到10,外部脈沖到來,使用last_time_CH1存儲10,
下次脈沖到來,此時定時器計數(shù)值運行到110,使用this_time_CH1存儲110,
之后做差,tmp16_CH1存儲差值100,由于定時器運行于100KHZ,10us計數(shù)值增加一次,所以脈沖周期為100*10=1000us=1ms,即為1KHZ。
當(dāng)然,定時器會溢出重裝,此時需要將差值補償運算,tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);
可測量的范圍取決于定時器運行的頻率,如果外部頻率慢到當(dāng)定時器整個計數(shù)一周后也沒有觸發(fā)兩次,會發(fā)生溢出,此時計數(shù)值已不準確。
所以定時器時鐘配置取決于外部脈沖頻率,應(yīng)配置得當(dāng)使得脈沖頻率范圍不致溢出。
由于每次外部脈沖都會觸發(fā)中斷,尤其是四通道時,所以使用中斷方式會略微占用CPU資源,使用DMA可以解決這一問題。
得到脈沖周期后,即可通過運算獲得外部頻率,進而測速。