PWM 脉冲输出方式千奇百怪,这边主要是要求两点:

  • 输出指定个数的 PWM 脉冲
  • 让指定个数的 PWM 脉冲,尽可能均匀的分布在一定的时间内。

首先假设 1s 内需要输出 n 个脉冲(n < 100,且 n 是个变量),需要在 1s 内让这 n 个脉冲尽可能均匀的分布,这边提供 3 种解决方法,供参考。

方法1

不需要提前计算好下 1s 需要输出的脉冲个数,而是每个 PWM 中断都进行一次判断,判断是否需在下个中断时间内输出脉冲。优点是反应迅速,方法简单,且能够输出均匀的脉冲;缺点是,仅脉冲输出就会占用 CPU 较多的资源。

方法2

上一个时间 1s 计算好在下一个时间 1s 需要打出的脉冲个数,然后在下一个时间 1s 内,让 n 个脉冲,不断的改变脉冲的周期,但是保持占空比 50% 且始终均匀分布。每次需要发送脉冲时,重新设定 PWM 的参数,这边占空比可以固定为 50%,但周期需要更改,如脉冲变为 20, 则周期就设定为 50ms,这样的好处是操作起来简单灵活,每次需要发送脉冲时,直接修改 PWM 占空比,然后重启开启定时器,但存在问题是 PWM 设置和开启需要一定的时间,无法确保 1s 内一定能够把脉冲输出完毕。当然我们可以通过进一步缩短周期时间,如需要产生 20 个脉冲,我们可以将周期设置为 45ms,这样在 900ms 内一定可以将脉冲输出完毕。这样缺失算是基本上解决这类问题了,但如果你的系统对时间进度要求较高的话,你的 PWM 定时器和程序执行的定时器很难做到同步。

这边提供另外一种思路,我们采用 PWM 定时器,来完成整个程序周期的调度,例如,我们设定 PWM 周期为 10ms ,然后通过 PWM 定时 100 个周期,进行一次主程序的扫描(1s),这样的话,主程序和脉冲输出就可以做到完全的同步了。以下两种方法,都是基于这种时钟基础做的操作。

方法3

上一个时间 1s 计算好在下一个时间 1s 需要打出的脉冲个数,在下一个时间 1s 内,打出固定频率的脉冲,为了保持均匀,将脉冲分为几段输出。首先我们确定了 PWM 周期是 10ms,我们可以将 1s 这个时间片进一步划分,分成 20 个 50ms,在这 50ms 中,让每次打出一定数量的脉冲个数,例如,80个脉冲,则每个 50ms 需要输出 4 个脉冲,因为 PWM 周期是 10ms,所以这边输出的 4 个脉冲会占据 50ms 的前 40ms,这样看起来也基本算是分散的比较均匀了。进行这种处理时,需要注意的是余数,如 99 这个的余数,我们需要认为的通过算法,讲余数均匀的插入到,每个点后面。这种方法,同样是存在某些缺点的,缺点是需要把时间片分的比较细,如果你将 1s 分成 5 份的话,在输出 10 个波形时,会发现虽然整体上看 PWM 波还算是均匀,但每个时间片中,PWM 波是紧挨着的,具体如下:110000000000000000001100000000000000000011... 显而易见, 1 的分配在大时间 1s 中是均匀的,但小时间 200ms 中是紧挨着的。但如果分配的比较细致,如上面所示分成 20 个时间片的话,无疑又会增加主程序扫描和判定的次数。

方法4

上一个时间 1s 计算好在下一个时间 1s 需要打出的脉冲个数,在下一个时间 1s 内,打出固定频率的脉冲,但为了让脉冲更加均匀均匀,采用查表的方式,将脉冲均匀的分布在各个时间段。采用查表的方式,有时看似最简单的方式,往往说不定是最有效的,由于这边需要输出的脉冲情况数并不是太多(100种情况),我们可以将这 100 种情况下的每个 PWM 周期(也是 100 个状态)全部列出来,用 100*100bit 来保存你的数据,100bit 可以用 13kbyte 保存,这样差不多占用 1.3k 的代码段。然后我们每次进入 PWM 中断,判断下一个 PWM 周期是否需要开启 PWM 信号。这样可以更加精准地控制 PWM 输出,且减少计算量,但相应的,我们至少额外的 13kbyte 的 flash 空间来存储我们的数据,这也算是一种典型的时间换空间的方法。如果通过查表的方法来输出 PWM ,我们需要手动写一个计算程序来生成这样的表格。这边提供一个思路:如果输出 12 个 PWM 波,我们可以通过计算 (100-12)/12 得出每个 1 后面需要加入的 0 个数,然后通过 (100-12)%12 得到余数,从前往后,每个 1 后面再补 1 个 0 ,值到没有余数全部补完。

方法5

提供另一种思路,如果 1s 内的 n 个脉冲可以通过其他方式获取的话,也就是说不是一次性获取 1s n 个脉冲,而是可以在 1/100 s 内每次判断是否有一个脉冲。将 1s 分为 100 份,判断下一个 10ms 是否需要发射脉冲,每 10ms 采用一个中断进行判断该次是否需要发射脉冲。这种方式灵活的更高方法更简单,但同时需要在中断中执行大量的判定和功能,很可能会影响其他功能的执行。

以上几种方法各有利弊,具体看你系统的需要而定。