改了ARR,PWM频率为何要到下一周期才变?
改了ARR,PWM频率为何要到下一周期才变?

程序刚把TIMx_ARR从999改成1999,调试器里也能读到1999,示波器上的PWM却还按旧频率跑完一个周期。很多人以为写寄存器失败,其实是定时器故意把新周期先放在预装载寄存器里,等更新事件再交给真正参与计数比较的影子寄存器。这个延迟不是Bug,而是防止运行中的周期被突然截断。关键是你想要“立刻变”,还是“无毛刺地变”。
软件写到的,不一定是计数器正在用的
定时器时基包含CNT、PSC和ARR。启用自动重装载预装载后,CPU对ARR的写入先进入预装载寄存器;计数器到达的终点由影子寄存器里的旧ARR决定。调试器读到新值,只能证明总线写入成功,不能证明影子值已经更新。等到更新事件发生,预装载值才被搬过去。把“可读写寄存器”和“当前生效寄存器”分开理解,延迟一周期就很自然。

图1 定时器捕获比较主电路展示预装载与影子寄存器位于输出比较链路中的位置。
ARPE开启,是为了守住完整周期
若ARR在当前计数过程中立即变小,而CNT已经超过新值,下一次溢出行为可能变得难以预期;立即变大,又会把当前周期突然拉长。ARPE=1让新ARR在统一的更新边界生效,当前周期按旧参数完整结束,下一周期再使用新参数。做电机控制、功率变换或音频PWM时,这种原子化更新能避免异常短脉冲。代价就是软件写入与引脚变化之间存在明确延迟。

图2 ARPE开启与关闭的计数时序图,用边界周期对比立即更新和更新事件加载。
UEV决定新值什么时候搬过去
计数器溢出或下溢会产生更新事件;软件写TIMx_EGR的UG位也可以主动产生更新。UG常用于启动前把PSC、ARR等预装载值一次性装入影子寄存器,但它也可能设置更新标志、触发中断或DMA,具体行为还受URS、UDIS等位影响。若代码在运行中随手发UG,可能让计数器重初始化并改变相位。成组更新前应先明确哪些寄存器有缓冲、哪些请求会被触发。

图3 控制寄存器中的ARPE、UDIS、URS与CEN说明更新事件既影响数据装载,也影响状态标志。
改频率时,占空比寄存器也要一起考虑
PWM占空比由CCR与ARR的关系决定。只把ARR翻倍而CCR不变,占空比会随之改变;如果CCR也启用了预装载,就应让两者在同一个更新事件生效。更改PSC还会影响计数时钟,并且PSC本身也通过更新事件装载。稳妥流程通常是计算新PSC、ARR、CCR,按芯片手册要求写入,再选择自然等待下一个UEV或在安全时机发UG。对互补PWM,还要同时评估死区和输出使能。

图4 寄存器更新时间线把PSC、ARR、CCR的预装载写入与同一次UEV对齐。
用逻辑分析仪看边界那一拍
验证动态改频不能只量改完后的稳定频率,应触发在软件写寄存器或控制GPIO上,观察变化前一周期、边界周期和变化后一周期。记录CNT方向、ARPE与OCxPE状态,以及是否主动写UG。若要求相位连续,让自然更新事件加载通常更合适;若模块停机后重新配置,可以在输出关闭时发UG并清理更新标志。中断服务里修改多个寄存器时,还要避免新的更新事件在写到一半时到来。把这套时序保存下来,后续换定时器实例、中心对齐模式或不同STM32系列时,就能快速核对差异,而不是凭“寄存器已经写了”猜测。中心对齐模式还要格外留意更新事件出现在哪个计数边界,不能把边沿对齐模式的一周期经验直接套过来。若使用DMA连续更新CCR或ARR,缓冲区切换也要与UEV对齐,否则一组参数可能跨两个周期生效。调试器暂停内核时,定时器是否继续计数取决于冻结配置,单步观察寄存器很可能改变现场。更可靠的办法是用额外GPIO标记写入和UG时刻,再把GPIO与PWM同时采集,重建真实时间关系。
ARR写入后晚一周期生效,是预装载机制在保护波形完整性。真正要设计的是更新边界:哪些参数一起换、由哪个UEV触发、是否允许改变相位。若频率和占空比要同时改变,应把PSC、ARR与CCR的新值成组准备,并在同一安全边界加载。用GPIO标记软件写入与UG时刻,再和PWM一起采样,能够区分总线写入延迟、影子寄存器更新和引脚真正变化这三个时刻。
你们动态改PWM频率时,会等待自然更新,还是在关闭输出后主动发UG?
声明:
本文由凡亿教育整理,转载请注明来源!
投稿/招聘/广告/课程合作/资源置换 请加微信:13237418207






哔哩哔哩
微信公众号
小红书
抖音
知乎
西瓜视频
头条
微信视频号
