4. 启动与停止PWM:HAL_TIM_PWM_Start、HAL_TIM_PWM_Stop、多通道控制
配置好定时器、设置好占空比,PWM 就能自己跑了?没那么简单。你想想看,初始化只是把硬件状态准备好,真正让引脚输出波形,还得靠一个「启动」动作。反过来,想关掉输出,也得有个干净的停止流程。
这一节,我们就专门聊 HAL_TIM_PWM_Start 和 HAL_TIM_PWM_Stop 这两个函数,以及怎么同时控制多个通道。我敢说,很多新手甚至老手,都在多通道启动的顺序上踩过坑。
4.1 启动单通道PWM输出
启动一个通道的 PWM,代码极其简单:
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
第一个参数是定时器句柄指针,第二个参数是通道宏定义。调用之后,对应引脚就会按照你设定的频率和占空比开始输出波形。
但这里有个细节——启动的时机。我个人习惯是在所有外设初始化完成之后,再统一启动 PWM。为什么?因为如果初始化一半就启动,此时 GPIO 可能还没配好,或者 DMA 还没准备好,波形会有一段不确定状态。
4.2 停止PWM输出
停止函数是对称的:
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
调用之后,引脚会变成什么状态?这取决于定时器的配置。默认情况下,停止后引脚会保持当前电平——可能是高、可能是低,取决于停止瞬间的计数值。
我曾经在一个电机驱动项目里,就因为停止后引脚电平不确定,导致 MOS 管短暂导通,差点烧了驱动板。后来我学乖了:停止之前,先把占空比设为 0,等一个周期再调用 Stop。
HAL_TIM_PWM_Stop 再调用 HAL_TIM_PWM_Start,不要连续两次 Start。否则定时器状态机可能混乱。
4.3 多通道控制:同时启动与独立控制
一个定时器有多个通道,比如 TIM2 有 CH1~CH4。你可以单独启动每个通道:
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
但这里有个性能问题:每个 Start 调用都会操作一次定时器的寄存器,如果四个通道依次启动,它们之间会有微小的时序差。对于要求严格同步的应用(比如三相电机控制),这个差异不可接受。
怎么办?HAL 库提供了一个批量启动的宏:
__HAL_TIM_ENABLE(&htim2);
这个宏直接操作定时器的 CR1 寄存器,一次性使能整个定时器。所有已配置的通道会同时开始输出。我个人在同步要求高的场合,都是先配置好所有通道,最后统一用这个宏启动。
| 启动方式 | 特点 | 适用场景 |
|---|---|---|
HAL_TIM_PWM_Start 逐个启动 |
每个通道独立使能,有微小延迟 | 普通 LED 调光、蜂鸣器控制 |
__HAL_TIM_ENABLE 统一启动 |
所有通道同时使能,同步性好 | 电机控制、多相电源 |
4.4 停止多通道的注意事项
停止也有类似的问题。逐个调用 HAL_TIM_PWM_Stop 会依次关闭每个通道,最后一个通道关闭后,定时器主计数器可能还在跑。如果你希望彻底停止所有输出,可以调用:
__HAL_TIM_DISABLE(&htim2);
这个宏会关闭定时器的主计数器,所有通道同时停止。但要注意:关闭后,定时器的配置会被保留,下次启动不需要重新初始化。
__HAL_TIM_ENABLE 保证同步,停止用 __HAL_TIM_DISABLE 保证干净。逐个 Start/Stop 留给需要独立控制的通道。
4.5 知识结构图:PWM启动与停止的完整流程
下面这张图,把整个启动/停止的路径画清楚了。你可以对照着理解每个步骤的作用。
4.6 实际项目中的经验总结
最后,分享几个我在项目中积累的实用经验:
- 启动前检查状态: 调用 Start 之前,最好用
HAL_TIM_PWM_GetState确认定时器处于就绪状态,避免重复启动导致死锁。 - 停止后清空比较寄存器: 如果下次启动要用不同的占空比,建议在 Stop 之后把 CCR 寄存器清零,防止残留值影响下次输出。
- 多通道的优先级: 同一个定时器的多个通道,输出优先级由硬件决定(CH1 > CH2 > CH3 > CH4)。如果两个通道配置了互补输出,启动顺序会影响死区插入的初始状态。
- 调试时用示波器: 我每次调试 PWM 启动/停止逻辑,都会在引脚上挂示波器。看一眼波形,比读一百遍代码都管用。
HAL_TIM_PWM_Start 和 HAL_TIM_PWM_Stop 不是线程安全的。如果多个任务同时操作同一个定时器,必须加互斥锁保护。
嗯,启动与停止这部分,说白了就是「怎么让波形出来」和「怎么让波形消失」。掌握了这两个动作,再加上多通道的同步控制,你就能灵活地管理任意数量的 PWM 输出了。