STM32 輸入捕獲的脈沖寬度及頻率計算


輸入捕獲模式可以用來測量脈沖寬度或者測量頻率。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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM