zoukankan      html  css  js  c++  java
  • SiliconLabs EFR32BG 定时器输入捕获和脉宽调制

    输入捕获

    在输入捕获模式下,定时器的计数值(TIMERn_CNT)可以被比较/捕获寄存器(TIMERn_CCx_CCV)获得。

    在TIMERn_STATUS寄存器中CCPOL位指示了触发TIMERn_CCx_CCV寄存器(比较/捕获寄存器)捕获动作的边沿的极性。

    上图中,TIMERn_CNT表示了定时器的计数,其中m和y分别记录了input脉冲的头两个上升沿的时间。

    TIMERn_CCx_CCVB表示了TIMERn_CCx_CCV寄存器中的Buffer缓冲寄存器。

    TIMERn_CCx_CCV表示捕获/比较寄存器。

    由于缓冲寄存器的存在,可以在读出前记录两次捕获事件。

    第一次捕获的时间总是可以从TIMERn_CCx_CCV中读出。读过该地址之后,该寄存器将从TIMERn_CCx_CCVB寄存器中载入下一个捕获时间值(如果缓冲寄存器中存在有效计数值)。

    捕获计数值可以通过读TIMERn_CCx_CCVP寄存器获得,而不改变FIFO的内容。TIMERn_CCx_CCVB也可以不改变FIFO内容的情况下读出数值。

    TIMERn_STATUS中ICV_flag指示了TIMERn_CCx_CCV中是否存在有效但是没有读出的捕获计数。

    在输入捕获模式下,TIMERn_CCx_CCV是只读的。

    如果在TIMERn_CCx_CCV和TIMER_CCx_CCVB都含有没有读出的捕获值时,一个新的捕获被触发,那么缓存溢出标志(位于TIMERn_IF中ICBOF)将被置位。

    发生溢出后,新的捕获值将被写入TIMERn_CCx_CCVB,并覆盖原值。而TIMERn_CCx_CCV中的值将保持不变。

    因此,TIMERn_CCx_CCV中总是保存了最早产生的一个未读出值,而TIMERn_CCx_CCVB中总是保存了最新读到的值。

    注意:在输入捕获模式,定时器将在它运行时只触发中断。

    周期/脉宽 捕获

    周期和脉宽的捕获只能在通道0中使用,因为只有该通道能够开始和停止定时器。

    开始和停止定时器通过设置TIMERn_CTRL寄存器中RISEA为Clear&Start

    对于周期捕获,比较/捕获通道应该被设置为捕获相同输入信号的上升沿。

    为了捕获高脉冲的宽度,比较/捕获通道应该被设置为捕获输入信号的下降沿。(这里为什么呢?如何理解高脉冲?

    为了测量信号的脉宽,应该选择对立的极性。

    脉宽调制

    PWM模式,TIMERn_CCx_CCV被缓冲,以避免输出中的小故障。

    比较输出动作配置位在PWM模式下被忽略。

    PWM输出只支持向上计数和向上/向下计数两种模式。

    向上计数(单斜坡)PWM

    如果计数器被设置为向上计数并且比较/捕获通道处于PWM模式,那么可以产生单斜坡的PWM输出。

    向上计数模式里,PWM周期是TOP+1次循环。PWM输出为高的次数等于TIMERn_CCx_CCV中的值。这意味着一个连续的高输出通过设置TIMERn_CCx_CCV为TOP+1或者更大来实现。(其实就是定时器计数和CCV中值做比较,大于CCV输出低,小于CCV输出高)

    PWM分辨率如下计算:

    Rpwm_up = log(TOP + 1) / log(2)

    PWM频率如下计算:

    fpwm_up = fHFPERCLK / (2 ^ PRESC * (TOP + 1))

    高状态占空比如下计算:

    DSup = CCVx / (TOP +1)

    上下计数(双斜坡)PWM

    如果设置为上下计数,比较/捕获通道以PWM方式输出,将产生双斜坡的PWM波形。

    PWM分辨率如下计算:

    Rpwm_up_down = log(TOP + 1) / log(2)

    PWM频率如下计算:

    fpwm_up_down = fHFPERCLK / (2 ^ PRESC * TOP)

    高状态占空比如下计算:

    DSup_down = CCVx / (TOP)

    关键代码:

    参考代码来自 https://github.com/SiliconLabs/peripheral_examples

    PWM输出

    对于PWM功能的实现,有以下几个关键点:

    设置TOP寄存器:

    TIMER_TopSet(TIMER0, CMU_ClockFreqGet(cmuClock_TIMER0) / PWM_FREQ);

     这里在设置TOP寄存器是,用到了定时器自身的频率。这里的关系应该怎么理解呢?

    设置CCV寄存器:

    TIMER_CompareSet(TIMER0, 0, (TIMER_TopGet(TIMER0) * duty_cycle_percent) / 100);

    对于Silabs的EFRBG还需要设置IO管脚的路由位置。这里原理还没有搞清楚,但不像早期接触的ST的芯片,每个IO有固定的功能复用。在silabs上对于同一个功能,可以通过IO路由映射到不同的管脚上。

    上图中TIM0_CC0功能,可以分表route到不同的线上,同时对应了不同的管脚。测试代码里面选择了IO_PC10,所以需要路由到15号线。

      TIMER0->ROUTELOC0 |=  TIMER_ROUTELOC0_CC0LOC_LOC15;
      TIMER0->ROUTEPEN |= TIMER_ROUTEPEN_CC0PEN;

    在中断处理函数中,重新修改CCV寄存器的值,即可输出特定占空比的波形。手册上没有明确写,个人上图理解中断事件是由于TOP的溢出产生的。TIMER_IF_CC0是中断标识寄存器。

    void TIMER0_IRQHandler(void)
    {
      // Get pending flags and clear
      TIMER_IntClear(TIMER0, TIMER_IF_CC0);
    
      // Update CCVB to alter duty cycle starting next period
      TIMER_CompareBufSet(TIMER0, 0, (TIMER_TopGet(TIMER0) * duty_cycle_percent) / 100);
    }

    PWM一般用于电机的控制和呼吸灯的实现。我这里只是需要一个简单的脉冲输出,然后再通过输入捕获功能将其频率捕获回来即可。

    下图是例程中输出的脉冲波形(频率1000,即周期1ms,占空比50%):

    输入捕获

    下面还需要通过输入捕获,采集到上面生成的波形的频率。

  • 相关阅读:
    Mysql的row_format(fixed与dynamic)
    no-referrer-when-downgrade什么意思
    a标签属性 rel=noopener noreferrer
    深入理解ob_flush和flush的区别
    win7下php7.1运行getenv('REMOTE_ADDR')fastcgi停止运行
    学会了这项技能,你就能获得任何想要的信息!
    原来游戏技术行业最大的秘密竟然是...
    王亮:游戏AI探索之旅——从alphago到moba游戏
    入门系列之在Ubuntu 14.04上备份,还原和迁移MongoDB数据库
    入门系列之在Ubuntu上安装Drone持续集成环境
  • 原文地址:https://www.cnblogs.com/minnowbin/p/9829117.html
Copyright © 2011-2022 走看看