STM32定時器----多通道PWM捕獲

由於項目需要利用一個定時器捕獲2通道的PWM輸入,所以近兩天研究了一下多通道PWM的捕獲。

功能實現:在頭文件中修改對應通道的宏定義的值(1或者0),開啓對應通道的PWM捕獲。

                可通過修改對應宏定義,更改定時器中斷間隔,以及中斷函數中的溢出次數,以此

                決定定時器所能捕獲的最低以及最高頻率。


代碼如下:

/***********************************頭文件********************************/

typedef struct
{
	  u16 Ccr1;         //緩存CCR寄存器的值
	  u16 Ccr2;
	  u16 Ccr3;
	  u16 Ccr4;
	  u16 Ic1_Over;     //記錄ARR溢出次數
	  u16 Ic2_Over;
      u16 Ic3_Over;
	  u16 Ic4_Over;
	  u16 Ic1_Fre;      //緩存頻率值
	  u16 Ic2_Fre;
	  u16 Ic3_Fre;
	  u16 Ic4_Fre;
	
}TIM_ICS;   //TIM3捕獲結構體

//TIM捕獲通道開啓宏定義,1:開啓 0:關閉
#define  TIM_ICCH1        1    
#define  TIM_ICCH2        1
#define  TIM_ICCH3        1
#define  TIM_ICCH4        1

//最小捕獲頻率:72000000/(120*60000)=10Hz
#define  TIM_ICARR        (60000-1)          //重裝載寄存器填充值
#define  TIM_ICPSC        0                  //分頻係數  
#define  TIM_ICFIT        0x0f               //定時器捕獲濾波係數  
#define  TIM_OverF        (120-1)            //最大ARR溢出次數

#define  TIM_ICSR         (u16 *)&TIM3->SR   //選擇定時器的SR寄存器地址
#define  TIM_ICCCR        (u16 *)&TIM3->CCR1 //選擇定時器的CCR寄存器地址


/***********************************C文件********************************/

//TIM3捕獲結構體變量
TIM_ICS TIM_Ic;    

//TIM_IcChannel 用來開啓TIM相應通道,且用在中斷函數判斷中斷狀態
u16 TIM_IcChannel = 1+(TIM_ICCH1<<1)+(TIM_ICCH2<<2)+(TIM_ICCH3<<3)+(TIM_ICCH4<<4);

void TIM3_PWMICInit(void)
{
	u8 i=0;
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef  TIM_ICInitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	/***********************NVIC配置*****************************/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	
	NVIC_Init(&NVIC_InitStruct);
	
	/**********************TIM3 GPIO配置*****************************/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

	/**********************初始化TIM3*******************************/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = TIM_ICARR;      
	TIM_TimeBaseInitStruct.TIM_Prescaler = TIM_ICPSC;     

	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	/**********************初始化TIM3 IC*******************************/
	TIM_ICInitStruct.TIM_ICFilter = TIM_ICFIT;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI ;

   	if(TIM_ICCH1==1)
	{
	  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	  GPIO_Init(GPIOA,&GPIO_InitStruct);
	  TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
	  TIM_ICInit(TIM3, &TIM_ICInitStruct);
	}
	
	if(TIM_ICCH2==1)
	{
	  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
	  GPIO_Init(GPIOA,&GPIO_InitStruct);
	  TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	  TIM_ICInit(TIM3, &TIM_ICInitStruct);
	}
	
	 if(TIM_ICCH3==1)
       {
	  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	  GPIO_Init(GPIOB,&GPIO_InitStruct);
	  TIM_ICInitStruct.TIM_Channel = TIM_Channel_3;
	  TIM_ICInit(TIM3, &TIM_ICInitStruct);	
	}
	
	if(TIM_ICCH4==1)
	{
	  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
	  GPIO_Init(GPIOB,&GPIO_InitStruct);
	  TIM_ICInitStruct.TIM_Channel = TIM_Channel_4;
	  TIM_ICInit(TIM3, &TIM_ICInitStruct);
	}

	TIM_ITConfig(TIM3, TIM_IcChannel,ENABLE);
	TIM_Cmd(TIM3, ENABLE);
}
void TIM3_IRQHandler(void)
{
	u8  j = 0;
	u16 i = 0, *pTimFre, *pTimCcrT, *pTimOver, *pTimSR, *pTimCCR;
	
        pTimSR  = TIM_ICSR;  //緩存TIM3 SR寄存器地址
	
	for(i=1;i<16;i<<=1)  //判斷觸發的中斷類型
	{
		  //例如開啓CH3其他通道關閉,其他通道在SR寄存器對應的中斷狀態標誌位會一直爲1
		  //所以在這裏,除了利用i判斷SR寄存器外,還需要通過TIM_IcChannel濾除不需要的中斷標誌位
		  //詳情參考 http://blog.csdn.net/a3748622/article/details/79075892
	    if( ((*pTimSR&i)&TIM_IcChannel) > 0 ) break;			
		  j++;
	}
	
	if(j>0)j--; //將j的取值由 0 1 2 3 4變爲 0 0 1 2 3,符合以下結構體地址偏移
	
	pTimCCR  = TIM_ICCCR+2*j; //根據觸發通道,緩存TIM3 CCR寄存器地址
	pTimFre  = &TIM_Ic.Ic1_Fre+j;      
	pTimCcrT = &TIM_Ic.Ccr1+j;
	pTimOver = &TIM_Ic.Ic1_Over+j;

	
	if(i==1)   //發生更新中斷,處理ARR溢出記錄
	{
		  
		  for(j=0;j<4;j++)
		 {
		        *(pTimOver+j)+=1;
			if(*(pTimOver+j)>TIM_OverF) { *(pTimOver+j) = 0; *(pTimCcrT+j) = 0; *(pTimFre+j) = 0; } 
		 }
		 *pTimSR &= ~i;       //清除中斷標誌位	
	}
	else       //發生CCR捕獲中斷,計算頻率
	{
		         if(*pTimCcrT< 1 )    //第一次觸發捕獲中斷
			{			    
			       *pTimCcrT  = *pTimCCR;		
                           if(*pTimCcrT <1) *pTimCcrT += 1; 
			       *pTimOver = 0;   //溢出記錄清零
			}
			else   //第二次觸發捕獲中斷
			{
			       *pTimFre= 72000000/( *pTimCCR - *pTimCcrT +  *pTimOver*60000 );	
                               *pTimCcrT  = 0;						
			}	
			*pTimSR &= ~i;       //清除中斷標誌位
         }
	
}






實際效果如下圖:



FRE3與FRE4爲CH3與CH4,連接的是X8以及X8互補輸出(TIM1高級定時器),

FRE1連接X11,FRE2連接X17。


發現2K以下頻率時,捕獲較爲準確,偶爾1HZ跳動。但是超過2K之後偶爾10HZ跳動,5K則有幾十HZ跳動。

這是因爲當前定時器濾波係數爲0x0F,改爲0,實測10K下跳動幾個Hz。

#define  TIM_ICFIT        0x0f               //定時器捕獲濾波係數


NOTE:  此程序捕獲得出頻率較爲穩定,但是頻率偶爾會出現很大的跳動




發佈了31 篇原創文章 · 獲贊 35 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章