×
单片机 > 单片机程序设计 > 详情

STM32定时器----多通道PWM捕获

发布时间:2020-06-18 发布时间:
|

由于项目需要利用一个定时器捕获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:  此程序捕获得出频率较为稳定,但是频率偶尔会出现很大的跳动

关键字:STM32  定时器  PWM捕获 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式