輸入捕獲模式可以用來測量脈沖寬度或者測量頻率。STM32 的定時器,除了 TIM6 和 TIM7,其他定時器都有輸入捕獲功能。以下是對脈沖寬度及頻率的計算。
1、脈沖寬度
如下圖所示,采集該高電平脈沖的寬度,只需要進入輸入捕獲上升沿檢測,記錄當前的發生上升沿時的CNT值,再進行輸入捕獲下降沿檢測,也記錄當前發生下降沿時的CNT值,兩次CNT值的差值再根據計數的頻率就可以算出脈沖的寬度。
上升沿及下降沿捕獲的程序具體實現如下:
TIM8_Cap_Init(0XFFFF,72-1); //以1Mhz的頻率計數
void TIM8_UP_IRQHandler(void)
{
if((TIM8CH4_CAPTURE_STA&0X80)==0) //還未成功捕獲
{
if (TIM_GetITStatus(TIM8,TIM_IT_Update) != RESET)
{
if(TIM8CH4_CAPTURE_STA&0X40) //已經捕獲到高電平了
{
if((TIM8CH4_CAPTURE_STA&0X3F)==0X3F) //高電平太長了
{
TIM8CH4_CAPTURE_STA|=0X80; //標記成功捕獲了一次
TIM8CH4_CAPTURE_VAL=0XFFFF;
}
else
TIM8CH4_CAPTURE_STA++; //捕獲高電平后定時器溢出的次數++
}
}
}
TIM_ClearITPendingBit(TIM8,TIM_IT_Update); //清除中斷標志位
}
void TIM8_CC_IRQHandler(void)
{
if((TIM8CH4_CAPTURE_STA&0X80)==0)
{
if(TIM_GetITStatus(TIM8,TIM_IT_CC4) != RESET) //捕獲1發生捕獲事件
{
if(TIM8CH4_CAPTURE_STA&0X40) //捕獲到一個下降沿
{
TIM8CH4_CAPTURE_STA|=0X80;//標記成功捕獲到一次高電平脈寬
TIM8CH4_CAPTURE_VAL=TIM_GetCapture4(TIM8);
TIM_OC4PolarityConfig(TIM8,TIM_ICPolarity_Rising); //CC1P=0 設置為上升沿捕獲
}
else //還未開始,第一次捕獲上升沿
{
TIM8CH4_CAPTURE_STA=0; //清空
TIM8CH4_CAPTURE_VAL=0;
TIM_SetCounter(TIM8,0); //計數器清零
TIM8CH4_CAPTURE_STA|=0X40;//標記捕獲到了上升沿
TIM_OC4PolarityConfig(TIM8,TIM_ICPolarity_Falling);//CC1P=1 設置為下降沿捕獲
}
}
}
TIM_ClearITPendingBit(TIM8, TIM_IT_CC4); //清除中斷標志位
程序中定時器輸入捕獲配置的TIM8CH4通道,CNT計數的頻率1MHZ,即計數1個就是1us。TIM8_UP_IRQHandler
是一個定時中斷函數,根據TIM8_Cap_Init(0XFFFF,72-1)
可知65536us會中斷一次,所以總的脈沖寬度時間如下:
temp=TIM8CH4_CAPTURE_STA&0X3F; //從TIM8_UP_IRQHandler中斷知中捕獲上升沿及下降沿期間進行此中斷的次數
temp*=65536;//溢出時間總和
temp+=TIM8CH4_CAPTURE_VAL; //得到總的高電平時間 TIM8CH4_CAPTURE_VAL為CNT計數的值
2、頻率測量
如下圖所示,測量脈沖的頻率,則分別采集兩次輸入捕獲上升沿的CNT值,脈沖的頻率=f/△CNT
兩次上升沿捕獲的程序具體實現如下:
TIM8_Cap_Init(0XFFFF,72-1); //以1Mhz的頻率計數
void TIM8_CC_IRQHandler(void)
{
if(TIM_GetITStatus(TIM8,TIM_IT_CC4)!=RESET)
{
TIM_ClearITPendingBit(TIM8, TIM_IT_CC4); //清除中斷標志位
if(state==0) //捕獲第一個上升沿
{
state=1;
timecount=TIM_GetCapture4(TIM8); //記錄第一次上升沿的CNT值
}
else if(state==1)//捕獲第二個上升沿
{
state=0;
timecount1=TIM_GetCapture4(TIM8); //記錄第二次上升沿的CNT值
if(timecount<timecount1)
{
test=timecount1-timecount; //兩次上升沿的差值
}
else if(timecount>timecount1)
{
test=(0xffff-timecount)+timecount1; //兩次上升沿的差值
}
else
test=0;
fq=1000000/test; //脈沖的頻率
}
}
}
由程序可知配置的定時器的輸入捕獲的計數的頻率為1MHZ,兩次捕獲上升沿的差值test為計數器CNT計的次數,所以總的周期即為T=1us*test
,所以頻率就fq=1000000/test HZ
;
另外,測量頻率除了還可以使用定時器的外部脈沖信號計數來進行。
3、定時器的外部計數模式測頻率
因為STM32有外部時鍾源模式,即可以根據外部脈沖信號進行計數,然后另外設定定時器定時中斷去讀取計數器的值,頻率=CNT/定時中斷時間
。程序代碼實現如下:
TIM3_Int_Init(9999,7199); //定時1s中斷一次
TIM2_Cap_Init(); //外部信號引腳脈沖檢測 TIM2_CH1_ETR
void TIM2_Cap_Init(void) //配置 TIM2_CH1_ETR 為外部脈沖計數
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2時鍾
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA時鍾
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 清除之前設置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
//初始化定時器2 TIM2
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //設定計數器自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler =0; //預分頻器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鍾分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
TIM_ITRxExternalClockConfig(TIM2,TIM_TS_ETRF); //配置外部觸發,否則不會計數
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2,ENABLE ); //使能定時器2
}
/*******************************************************************************
* 名稱: TIM3_IRQHandler
* 功能: 通用定時器3中斷服務函數
* 形參: 無
* 返回: 無
* 說明: 1S定時中斷一次
******************************************************************************/
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!= RESET) //檢查TIM3更新中斷發生與否
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIMx更新中斷標志
CNT=TIM_GetCounter(TIM2); //讀取1s內計數器計的CNT值
fq=CNT; //脈沖的頻率
TIM_SetCounter(TIM2,0);
}
}
因為知道定時中斷時間為1s,所以測量的頻率fq=CNT/1(HZ)
,頻率的計算及脈沖寬度的測量有以上方法測試。
by 羊羊得億
2017-02-24 ShenZhen