由於項目需要利用一個定時器捕獲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: 此程序捕獲得出頻率較爲穩定,但是頻率偶爾會出現很大的跳動