; y" w2 ~2 Y# j3 i) e. W! Y: h 有人使用STM32定时器的PWM功能,遇到点小疑问,这里一起看看。4 t5 a# y) S$ q/ J他先将STM32某定时器计数周期设为0xff,单向递增计数模式,OC比较值设为0x7F。在某时刻将新的计数周期0x7F与比较值0x3F加载到影子寄存器。当正在进行的一个周期结束后,经示波器测量确实可以看到其下一个周期发生变化,但其周期明显与预设值对应不上!再次经过一个周期,定时器才会按照预设值稳定输出。9 q% A! D* i! R8 a8 k& ` 1 I4 v- k7 t- ^- s4 A' J 8 W2 K! F( K# _$ ?1 q 以上是咨询者不算很清晰的描述【其实咨询TIMER问题最好配上时序图】,但可以了解到他要做的事情就是在ARR=0xff,ccr=0x7F的PWM输出状态下,于某时刻赋予ARR和CCR新值以改变输出波形。1 Q; t8 U& P% f: b2 s 0 C' y3 J+ e- I2 v. b4 v' m; I
4 {2 D8 C# h G4 | 事情不算复杂,疑点就是为什么需要2个周期延时后才能有基于新配置的稳定输出。【他这里说的2个周期显然不清楚到底指的前后哪个周期值】 这个问题主要涉及到定时器寄存器的预装功能。有些时候我们需要保证输出波形完整性、连续性,开启ARR及CCR的预装功能就比较合适,使用CubeMx配置时做些勾选即可。开启预装后,修改ARR及CCR的值,生效时间点最长可能延后1个旧计数周期。不过这里要注意,我们修改ARR及CCR的值若不是特别需求,建议在一个计数周期内完成修改,不要一个值在更新事件之前完成赋值,另一个则发生在该更新事件之后。 f; r: c, z) R. b$ o+ t 我也将上面提醒告知咨询者,他反馈问题依然没能解决,准确说是疑惑依然没能解除。他这里的确只是提出疑惑,并未提出具体需求。另外,他还将问题的复现过程做了如下补充: . [3 \1 v; ?& H1 U+ d 第一步:: }1 W! m- Z/ `/ Q# { 1 - 关闭预装载(ARR/CCR)! O3 K2 y/ G- n$ c. z9 ^ 2 - 设定ARR=CCR=0xFF 3 - 开启输出比较功能(连接到示波器查看波形) d2 d& T; m3 H+ C% h4 L, u 第二步:0 Q- E; L! P8 C( O 1 - 设置示波器触发(延迟一段时间拉高某个IO引脚以触发示波器采集) 2 - 立即清空CNT7 y+ Q/ x1 g- E$ @8 ^4 \& C 3 - 使能预装载' e3 P2 [ L u5 j 4 - 设定ARR=0X7F,CCR=0X3F1 i" W- D8 h. C& X3 m 现象:本周期结束后其计数周期确实会相应改变,但改变之后的前两个周期明显与设定值不符,即经过2个周期后才可稳定输出。, C7 Z& O! M' E/ k* g . f* H6 f8 E& x+ x) J3 `7 h- z, P F5 F4 ]% t3 L# |8 x 复现过程表述得比较清晰了,他也再次明确了疑惑点。同时还强调说网上很多人碰到类似问题或疑惑。他在STM32L4系列和STM32H7系列上都遇到了同样问题。既然这样,现在我们使用STM32L4系列的TIM1来进行验证,参照他的操作步骤来组织代码,看看来龙去脉。 : e# A. M2 H' F# \* p4 a- f, C 我是这样测试验证的。 在关闭ARR/CCR的预装前提下给二者分别赋值0xff和0x7f,启动CH1的PWM输出并使能该通道的输出比较中断。在第一个脉冲的比较中断里按照咨询者的做法修改ARR/CCR值。为了便于观察效果,我也开启了更新中断,通过更新中断记录脉冲个数,输出几个脉冲后就将定时器及输出都关闭掉。【选择PWM模式1,极性为高有效】1 f) T# |1 `" ^) [ 编写代码、编译除错后,运行得到如下结果:【黄色波形结尾的4个脉冲是基于新参数的输出。绿色波形的上升沿指示修改数据的时间点,这里辅助显示下,重点在黄色波形。】 1 S" e6 y& y; Q/ j) K" M / ?" r, F) P0 [0 Z5 O3 C
上面输出波形应该说跟客户反馈的是一致的。我们来一起看看。在第一个脉冲的比较中断处,也是第一个脉冲的正中央【红色箭头所指位置】处做参数修改。修改步骤按照咨询者提供的来实现。. d, U# d! s+ ]- E( A3 h( N % A$ z7 j% {. H+ \/ H6 y
?5 ?8 M$ J/ P$ s 即按照上面的3小步操作【第1小步是咨询者设置示波器的动作,不用理它】。, s5 u/ N; g1 u. f; y' L ) @" w+ [: Y- ~3 C K$ m , S' ?4 |4 d# b8 Q$ W5 t, C 这里是开启预装功能后才修改ARR/CCR值,这两个新值目前只能暂居预装寄存器,实际起作用的ARR/CCR值仍是之前的0xff和0x7f。而且,还在此处对计数器做了清零,即从此刻起PWM输出脉冲重头来。这样从上图红色箭头到蓝色箭头之间的波形依然是基于ARR=0xff,CCR=0x7f参数运行的。定时器于蓝色箭头所指位置处发生更新事件,新数据【0x7f,0x3f】生效起作用。/ a- d* E7 m6 L * M+ [! }$ a$ L9 G1 \; H% M 4 s ^9 a: H' S" m 显然从修改时刻算起到数据生效 刚好延时1个旧周期,结合到这里,恰好是新周期的2倍。修改数据后整整花了2个周期的时间才生效就是这么来的。3 a. W1 o, D% y9 z+ X2 x : v2 f0 B) F$ @2 w3 L 如果在上面操作步骤的基础上拿掉对计数器清零操作,其它不变,输出结果又不一样了。见下面截图: - c% z& W$ l6 ^4 y
( ^, f+ D! F7 ] 同样,红色箭头所指位置为修改数据的时刻。由于此时没有对计数器清零,计数器按部就班计数,PWM输出按预定配置输出,继续运行半个旧周期后计数器溢出产生更新事件于蓝色箭头所指位置。蓝色箭头所指位置以后PWM输出按新参数运行。不难看出,这次新数据的生效从修改时刻算起仅延时半个旧周期,相当于后续的1个新周期。9 x' J& f- p7 p7 Q- D 5 T1 e) O! e) F1 a1 q* M 9 N3 T( B" o& t) E! c. | 这里强调下,我这里测试时选择的刚好是旧周期的中间点,所以延时生效为半个旧周期。具体应用时的延时跟我们修改参数所选的时间点有关,一般来讲,它最长不会超过1个旧周期,最短极限为0。 ( U2 b2 g+ b4 l1 m* H 当然,如果说我们不关心修改数据前后波形的完整性,直接关闭预装功能也行,或者手动产生更新事件也可以。总之,我们根据实际应用需求来定。 ; m% h5 Q2 o0 ^% \ 聊到这里,关于咨询者的疑惑基本解释得差不多了。 1 M( R! f$ W* @0 B4 C4 h2 B " n# `/ E# S4 ]* @" `. R+ D 或许眼尖的人看到上面第一种操作输出的PWM波形里面有个非常细窄的尖脉冲,它是怎么回事呢?示波器问题?非也!【见下图椭圆形框住的细长线】7 F$ r( R; H$ q; b0 O: U2 @ / a2 q: ]7 x( s& y7 R x! j / P5 M+ X) B5 M8 P8 A
7 V+ y9 D8 z, t& E. T 此处尖脉冲产生的原因是------当发生比较中断时我们才去做修改参数动作,在做计数器清零操作前,计数器的值已经大于设置的CCR值【0x7f】,按照当前PWM输出模式及极性选择,输出则变为低电平了。但是,在中断里我们很快又将计数器值做了个清零,此时计数器值又小于CCR值【0x7f】了。同样,按照当前PWM配置,输出又变回高电平,最终就产生了这么个一下一上的尖脉冲。 1 ~0 U( K7 u- Z( u* z) l 转载自: [color=var(--weui-FG-2)]Miler 如有侵权请联系删除+ a+ ~2 s, F4 i0 l3 m0 [ |
经验分享 | 利用TIMER定时和捕获功能实现编解码演示
STM32 LSE 不起振排查指南:五大核心原因与快速解决方案
我心中的ST中文论坛
经验分享 | 利用STM32 TIMER实现同频跟随输出示例
2025软件工具兔哥知道
经验分享 | 利用STM32 TIMER实现同频跟随输出示例
经验分享 | 一个基于TIMER事件的中断响应话题_续
经验分享 | 一个基于TIMER事件的中断响应话题
11张图学会STM32定时器!
经验分享 | STM32U5系列TIMER+DMA+DAC应用演示
微信公众号
手机版