上一篇文章《领悟最强 PWM 捕获功能,1 MHz 》鱼鹰介绍了最强 PWM 一些基本特性,今天鱼鹰从原理上介绍如何实现该功能。
介绍之前,首先介绍一下 STM32F103 TIM 的一些相关特性:
- 无法使用外部引脚中断触发 DMA (有些型号可以)无法使用 TIM 同时捕获上升沿和下降沿。你在库里面看到的宏其实在使用时受到了限制,高级定时器1、8,通用定时器2、3、4、5都不行,而一般103 就只带这些定时器。
3、高频信号输入时,中断进入很频繁,如果是 100 K 频率,你需要 5 us 进入一次(高低电平各一次,还是在占空比为 50 % 情况下,其它占空比条件更为苛刻),如果采用中断处理方式,你必须在中断中完成很多操作(清标志、计算、翻转极性等),同时你需要保证这两次中断不能被全局中断禁止,或者被高优先级中断打断,否则,你得到的可能就不是一次脉冲的高电平了,这样你的占空比、频率都将计算出错。正因为有如上问题,而捕获 PWM 脉冲又是比较常见的功能,所以需要一个高效的捕获程序完成该工作。而鱼鹰今天介绍的实现原理我认为就是最高效的。100K 频率误差 0%,占空比误差1%!在嵌入式中,100 K 频率已经算比较高的了,当然是在关注占空比情况下,如果只关注频率,那么可测量的频率将更高。可能有些人会抬杠,说,干嘛不使用 FPGA。鱼鹰当然知道有比单片机更有效的捕获器件,因为我自己买的逻辑分析仪(想买这个的可以找鱼鹰预定,可以给一定的优惠,预定人数需要10个以上)就可以捕获很高的频率、精度,但问题在于成本,在于有必要吗?这个逻辑分析仪可是几百大洋啊。闲话不多说,鱼鹰首先介绍一下该捕获方法的基本原理。很简单,就是利用二进制溢出特性实现的。(2038问题-动图)
这个特性鱼鹰在笔记中也多次介绍了其中的应用,比如无锁队列、扩展定时器、编码器、延时等,今天就再加一个应用,PWM 捕获(本篇笔记不介绍这个特性原理,可以看历史相关笔记)。可以说理解了这个特性,在各种整型数据处理中如虎添翼,再也不担心数据溢出的问题,反而要利用该特性完成一些骚操作,比如今天 PWM 捕获就是如此。另一个绝技就是使用 DMA 了,这是它高效可靠的原因。首先我们看看定时器的构成框图:
上面标注部分就是为什么 PWM 输入模式只能使用通道 1 或通道 2 的原因。这里我们以TI1作为PWM输入,两个捕获通道同时捕获 TI1 为例说明。基本配置如下:
- 捕获通道 1 触发 DMA,同时设置捕获上升沿,这样,只要上升沿触发了,可以自动完成捕获并DMA传输至用户缓存。通道 2 下降沿捕获,不触发 DMA。配置DMA,传输外设地址不是某一个寄存器,而是 DMAR,同时设置传输数量,这一定是 2 的倍数,因为一次需要传输两次,32 位宽度。因为需要传输两次 CCRx,所以需要正确设置 DCR 寄存器。
以上配置就是整个功能最为关键的部分。如果你理解了下面介绍的捕获原理,你自然知道为什么需要这么设置了。我们首先看看 PWM 捕获时基本工作过程:
另外还需要了解 TIM 一个很重要的DMA 传输特性:通过配置寄存器,可以一次触发,多次DMA连续传输,这个特性在这个功能中也被用上了。
如何利用这个功能呢?一般我们配置 DMA 传输时,比如串口,一般外设地址就是 DR 寄存器。而如果我们想传输 TIM 的捕获值,我们可以设置成 CCR1 寄存器的地址。这样也可以正常传输,但是只能在触发时传输一个寄存器的值,如果需要把两次捕获值都传输,那么就需要配置两个 DMA 通道完成,但这里又涉及到了两个 DMA 通道同步的问题,因为你肯定希望每次采集的两个数据都属于同一个脉冲。所以 TIM 用了这两个寄存器解决这个问题,通过 DMAR 中转,就可以完成一次触发,连续传输两个 CCR 的值。想必看到这里,你应该大概知道该捕获的原理是什么了。
这里鱼鹰再结合上图描述一下。初始化(定时器、DMA、GPIO)完成后,定时器就准备好工作了,一旦有一个脉冲输入,上升沿触发,此时因为设置了 DMA 触发,同时设置了连续传输两个寄存器,所以它会把当前的 CCR1 和上一次捕获的 CCR2(下降沿触发)传输到用户缓存,这是两次 DMA 传输,所以DMA的计数器会递减两次。并且 CCR1 的值比 CCR2 的值大(不考虑溢出情况下,并且差值情况下,大小没有意义)。这样,上面的三次触发,我们可以得到三组捕获数据。
通过 (uint16_t)(CCR1 – CCR2),我们可以得到低电平,而通过两次CCR1 或者 CCR2 的差值,我们可以得到周期。这样计算频率和占空比就不是什么难事了。特别需要注意的是,三次上升沿捕获期间,定时器不可以产生溢出现象,这可以通过定时器分频实现。分频系数越小,分辨率越高,但越容易溢出。
这里要注意的是,如果频率比较高,建议多测量几组数据,然后取后面几组数据进行简单平均或中值计算(具体根据捕获值来确定),这样准确度更高一些,因为刚开始可能因为初始化的缘故,导致意外捕获,这是可能的(刚开始不确定可以测个 64 组再说)。另外如果输入 PWM 频率或占空比会不断变化,也需要根据情况多测几组(或定时测),并进行简单处理,这样不容易刚好捕获到变化的脉冲,保证脉冲计算的可靠性。
总之,怎么去让你的程序更加可靠就是各位道友的事情了,鱼鹰只是提供一个解决思路。另外鱼鹰不准备提供源码给各位道友,自由发挥吧。如果确实有需要的话,在本篇文章更新前的时间里,道友有过赞赏或者留言被置顶或转发支持的情况,那么也可以主动联系鱼鹰,鱼鹰可以给一份参考程序,仅供参考。
来源:公众号【鱼鹰谈单片机】
作者:鱼鹰Osprey(emOsprey)