zoukankan      html  css  js  c++  java
  • STM32F4 TIM输入捕获(测频)【使用库函数】

    在输入捕获模式下,当检测到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);
    }

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

    IMAG2208

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

    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被编译器优化掉
           }
        }
    }

  • 相关阅读:
    普通的patch 和使用git 打patch
    c语言中的原子操作
    读写锁的简单说明
    source Insight 的常用设置
    git 一些常用的场景
    gdb 脚本 简单理解
    linux 中的errno 和 strerror(errno)
    C++中内存对齐原理详解
    如何安装windbg调试助手
    Windows中如何读写INI文件
  • 原文地址:https://www.cnblogs.com/zyqgold/p/3117586.html
Copyright © 2011-2022 走看看