一般来讲,一个STM32定时器输出基于同一频率的各路信号比较方便。但经常也会有人问使用STM32一个定时器是否可以实现多路不同频率的输出。从实现这个功能角度来讲,答案是肯定的,并可以满足相应的应用需求。
这里利用STM32G4的Nucleo开发板进行一个简单的实现示例,顺便交流和分享些思路,以拓宽STM32定时器的应用场景。示例中使用STM32定时器输出模式中的比较切换模式,即Toggle模式,结合定时器的比较事件及DMA传输来完成。
我使用STM32G431RB片内TIM1,通过它实现4路不同频率的PWM输出,分别是20KHz,50KHz,70KHz,80KHz,让TIM1运行在10Khz的循环计数状态。TIMER的计数时钟源为170Mhz,没有对时钟进行分频。
基于上述条件,TIM1的10KHz更新频率所对应的计数脉冲个数则为17000,那么,20KHz、50KHz、70KHz、80KHz所对应的计数脉冲个数分别是8500、3400、2428、2125,分别对应着TIM1四个通道CH1/CH2/CH3/CH4的PWM输出。【可参考下面表格】
现在开始使用STM32CubeMx进行初始化配置。TIM1的时基配置如下:
将TIM1的CH1/CH2/CH3/CH4的比较输出模式配置为匹配切换模式。这里关闭了CCR寄存器的预装功能。
上图中绿色圆圈里的用于比较的初始数据,依据不同通道的占空比来拟定,不是很重要,只会影响到第一个脉冲的占空比。当然,也不能乱写。【为什么呢,请自行思考下】
再来看看有关DMA的配置,4个通道都开启了基于比较事件的DMA触发请求,并使用循环传输模式。
基于CubeMx配置完成后,生成初始化工程代码。
下面进行用户代码的添加和整理。假设四个通道输出的占空比分别为70%,70%,40%,40%。为了实现4路不同输出频率及占空比的波形,需拟定一些用于比较切换的数据,借助各个通道的比较事件触发DMA,让DMA适时修改相应通道的比较寄存器的值,即修改CCRx的值。【这个地方的实现原理很难一两句完全写清楚,有兴趣的请先了解STM32定时器的比较切换模式,再结合DMA传输琢磨琢磨。下面表格是实现上面输出需要用到的一些数据。】
结合上述表格的数据,定义一些宏参数和内存数组。内存数组用来存放各个通道不同时刻的比较值。【本想放源码文本上来的,因为可能有人需要验证测试。但这里实在不好排版,只能贴图了。抱歉!】
上面的四个数组分别对应四个通道做比较切换输出时需用到的比较值。这些数据的拟定需好好琢磨下。我刚开始在代码里都是放的具体数据,但考虑到不太好理解各个数据的含义。我这里特意将它们改成宏替换,旨在以宏替换的形式顺便做个比较直观的注释,希望帮到有需要或感兴趣的工程师。
接下来添加具体的功能实现代码。代码不多,很简单,都是基于HAL库的。看到函数名就大致知道什么意思了。下面的代码就是本示例中用到功能代码。它们的功能分别是使能相关定时器通道的比较输出事件;开启基于定时器比较事件的DMA传输并完成相关配置;使能各个定时器通道比较事件的DMA请求;使能TIM1的主输出功能并开启计数器的工作。
编译调试整理后,运行程序查看结果.
从上面示波器测得结果来看,输出波形满足前面提到的设计要求。频率、占空比跟我们设计要求的一致。【注:手机模式下可点击图片放大查看】
在上面代码的基础上,我保持4个通道输出的脉冲频率不变,对各自占空比做下调整,分别调整为30%,30%,60%,60%【在上面代码里只需调整那几个Dutyn值】,显然也能很好地实现各自的输出。波形图如下:
在上面示例中,我将TIM1的10Khz更新频率做为配置CH1~CH4四个通道输出的一个参考或基准。既然一个定时器可以实现4路不同频率,那么多个定时器实现更多不同频率的PWM输出也就不难了。
关于使用1个定时器实现多路不同频率输出的示例就介绍到这里。本质上它是基于定时器比较输出功能的比较切换模式与DMA的灵活运用,抛砖引玉似地给大家提供些方法或思路。当我们将STM32各种定时器事件、定时器比较输出切换模式以及DMA传输灵活而巧妙加以运用时,往往可以实现很多客制化的东西。