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

STM32F4 TIM输入捕获(测频)

发布时间:2020-07-08 发布时间:
|

在输入捕获模式下,当检测到ICx信号上升/下降边沿时,计数器的当前值被存储在捕获比较寄存器TIMx_CCRx中。

当捕获事件发生时,相应的CCxIF 标志(TIMx_SR 寄存器) 被置1。如果中断或者DMA功能被使能,就会产生中断或者DMA请求。如果捕获发生时,CCxIF标志已经被置位,这时过采样标志CCxOF就会被置位。向CCxIF写0或者读去TIM_CCRx中的数据,将清除捕获标志。CCxOF位只能通过手动写入0进行清除。

假如我设置为上升沿捕获,那么当一个上升沿到来的时候,定时器当前的计数值(TIMx_CNT)就会写入TIMx_CCRx中。我们读取这个数据。等到下一个上升沿到了时,就会有另一个计数器值TIMx_CNT记录。根据这两个数据值差,我们能算出来输入数据的周期。当然,我们还有处理定时器溢出这个问题,定时器溢出了就不准了。

如果要测占空比,就需要同时捕获上升沿和下降沿。相邻两个上升沿之间的计数是输入的周期,相邻两次捕获(一个上升沿一个下降沿)之间的时间是占或者空的时间。根据这个可以计算占空比或者PPM之类的东西。

【实验内容】

本次实验,使用TIM4产生一个1K的频率输出,用TIM1进行捕获。并测出频率计算

TIM1 的时基单元配置:关于TIM1的时基设置问题前文已经讨论过了。这里只有一点需要明确的,就是为了尽量减少更新事件,将TIM_Period设置到最大即0xFFFF。定时器时钟设置成2M,这样定时器的更新频率就是30Hz,不会造成两次捕获之间产生多次更新。

TIM1的完整配置代码如下:

void TIM1_ICConfig(void)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
//   //时基初始化
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //死区控制用。
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //计数器方向
  TIM_TimeBaseInitStructure.TIM_Prescaler = 84-1;   //Timer clock = sysclock /(TIM_Prescaler+1) = 2M
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF;    //Period = (TIM counter clock / TIM output clock) - 1 = 40Hz  
  TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  TIM_ICInitStructure.TIM_ICFilter = 0;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

  TIM_ICInit(TIM1,&TIM_ICInitStructure);
  TIM_Cmd(TIM1,ENABLE);
}

TIM4的配置就是基本的输出配置,没什么可说的。代码如下:

void TIM4_OCConfig(void)
{
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInitStructure.TIM_Prescaler =  0;
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter =0;
  TIM_TimeBaseInitStructure.TIM_Period = 42000-1;   //周期:42M/(42000)= 1K
  
  TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
  
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 10000;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  
  TIM_OC1Init(TIM4,&TIM_OCInitStructure);
  TIM_Cmd(TIM4,ENABLE);
}

这个输出频率,在示波器上可以看到的:

之后就是在主函数里边进行测量了:

CaptureNumber = 0;
 
while(1)
{
    if(TIM_GetFlagStatus(TIM1,TIM_FLAG_CC1)==SET)
    {
       TIM_ClearFlag(TIM1,TIM_FLAG_CC1);
       if(CaptureNumber == 0)
       {
         counter = TIM_GetCapture1(TIM1);  //第一次捕获
         CaptureNumber = 1;
         
       }
       else if(CaptureNumber == 1)  //处理第二次捕获
       {
         if(TIM_GetFlagStatus(TIM1,TIM_FLAG_Update) != SET)//两次捕获间没有发生溢出的处理
         {
           Time = TIM_GetCapture1(TIM1);
           Time = Time - counter;
         }
         else
         {
           TIM_ClearFlag(TIM1,TIM_FLAG_Update);   //产生了更新事件
           Time = 0xFFFF - counter + TIM_GetCapture1(TIM1)+1;  //如果有更新事件产生时候的计算方式
         }
         CaptureNumber = 0;
         if(Time!=0)
         {
           freq= 2000000/Time;  //计算频率
         }
         freq = freq;  //避免变量freq被编译器优化掉
       }
    }
}



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

热门文章 更多
如何为单片机选择合适的负载电容