STM32常规定时器主要包括基本定时器、通用定时器和高级定时器。不论哪一类定时器,都有个共同的计数定时单元,我们把它称之为时基单元。 ! \$ d3 J, N* D 该单元主要由三部分组成: 分频模块、计数模块、自动重装载模块。 % C$ k) _8 V& @ ? n8 V( w - E9 l/ j$ d" j, P+ `& [4 P9 h 分频模块用来对外来的计数时钟进行分频,这里有个分频计数器,通过它来实现对时钟的分频功能。与之对应的有个分频器寄存器TIMx_PSC,用来配置和存放分频比、分频系数。+ N* M1 _4 t5 g9 J 计数模块用来对来自分频器输出的计数脉冲进行计数。相应的这里有个寄存器—计数器寄存器TIMx_CNT,为了把该计数器跟别的计数器区别开来,不妨称它为核心计数器。4 H8 H1 t: p3 w6 I& U* h 1 g8 R7 i# T& Y( l$ Y8 L 自动重装载模块用来配合计数器溢出,当计数器溢出时为之赋予初始计数值的功能单元。与之相应的有个自动重装载寄存器TIMx_ARR.当自动重装载寄存器TIMx_ARR修改生效后就可以自动地作为计数器的计数边界或重装值。 ! s( f9 s( @; _7 s, q3 |' V0 g L/ f1 T" W1 U: Z 关于自动重装及自动重装载寄存器TIMx_ARR是个相对比较难理解的地方,尤其关于ARR寄存器数据的含义。我们在看STM32参考手册时,很难一下子理解得很到位,往往需要结合上下文内容反复阅读后去领会。关于计数器的溢出与重装,在手册里只有些零散且并不算清晰的介绍,这里尽力跟大家做些交流,以供参考。 # M2 F: q5 r9 U+ w1 d 当计数器溢出时,自动重装载器为计数器重装计数初始值。自动重装寄存器【ARR】为计数器设置计数边界或初始值,决定计数脉冲的多少或计时周期长短。比如:计数器向上计数时,计到多少发生溢出;向下计数时从多少开始往下计数。平常我们泛泛地说ARR寄存器为计数器提供计数边界或重装值,但它的具体含义及使用需要结合计数器的计数模式才能确定。 ( p- M% |/ g$ j/ j' ^3 G 那一起看看STM32定时器所支持的三种计数模式及计数过程。 0 ?0 `! {9 _+ ]5 n+ ? 0 P! @0 B( e# A" w0 z! o$ n 1 [9 Z$ o* ?/ E! F3 E ) i5 d0 o/ o' j* F; }, e( C 从上面三种计数模式下的计数动作来看,不同模式下计数器的溢出点并不一样,溢出后重装值也不一样。显然,ARR寄存器里的数据扮演的角色也因不同的计数模式而有所不同。我这里特地就三种计数模式下的溢出与重装汇总成一个表格,以便观察和比较。不难看出,重装值并不一定等于ARR,有时重装值就是0. 1 @7 o, T5 b0 a1 P g0 Q: \. R$ g. N ; A( B( X4 v! m( \ 根据上面的介绍和分析,我们要弄清楚几点: 8 m2 v, I- i E9 I& h- s 1、对时钟脉冲进行计数以及溢出是计数器的事; * w/ g: h; u; V9 \: F1 ]4 Z 2、当计数器发生溢出时对计数器重装初始值是自动重装载器的事; * R2 L7 E. g6 L( U5 B" c R3 j1 X 7 }, Q5 L# T5 g 3、ARR寄存器里数据的含义会因计数模式的不同而有所不同; 我们弄个实例来看看,以加深对这个溢出与重装的理解。; ]) D2 u: J( A6 m+ f2 H0 t$ v 我们来看一个通过高级定时器使用比较输出功能输出指定个数脉冲的实例。假设使用PWM输出的单脉冲模式,借助高级定时器的RCR【重复计数器寄存器】来输出指定个数的PWM脉冲。& B/ x9 T D/ f! B* S" w : M# e4 C, N( V. R/ R 0 [8 M" \" |& o- U 单脉冲模式:计数器启动后,对于高级定时器,发生第RCR+1次溢出时触发更新事件,同时计数器停止计数。对于通用定时器,没有RCR寄存器,即每次溢出都可以产生更新事件,然后停止计数。" Q0 ?- H9 c- ?* i" w% M6 ~) \ O C+ ^/ l" g* \" R- ? 首先,我们需选择合适的计数模式与PWM输出模式来完成该任务。+ V9 E1 a3 y; R# q; e& \8 B2 }) A3 i ) q7 Y5 I2 `( t; h, D; F 条件1:向上计数模式 + PWM1模式;RCR=2; 极性选择高有效。 : \$ E, u3 i; I; ~- J4 Q r f* U 基于这个条件,当CCR大于计数器CNT时,OCx端输出高电平,反之输出低电平。 7 E+ }' f1 H# ?% g. n ) x4 t2 o: a& K& _8 {. @* E# U& l RCR=2,意味着计数器在发生第3次溢出时产生更新事件。 ' c. V- N/ _; T) {. C$ z" }& R) _ 经验证测试,基于上面条件的输出波形是下面的样子。 . k# z/ ^; w2 @8 u1 R5 Z% j 8 Z" ~) e- j; |+ `0 A, [7 W" @9 I! Y 【图一、向上计数模式 + PWM1模式RCR=2; 极性选择高有效】! e5 I) |* ~! o( Z( w G5 M# x0 W ^ 6 }: z$ R$ J8 T | 一眼就可以看出,输出波形后面多了高电平尾巴,如果是自己期望的倒还好。如果希望最后电平停在低电平,显然就不合适了。' Q3 y4 \2 [: ]/ W$ J: h$ z 我们先不管合不合适,看看为什么会这样。最后发生溢出时计数器的值不等于ARR吗?结合上面图形,不难看出ARR的值显然比CCR要大得多,即最后时刻计数器的值比CCR要大,那根据上面PWM1模式和极性选择条件,不是该输出低电平吗?怎么会输出高电平呢?奇怪!哪里不对劲呢? * a6 `* A: m x, F+ `% { ( @ z4 \7 [* N3 x 那我们换个PWM输出模式,保持其它条件不变,看看使用PWM2模式结果如何?* c7 r3 p* ~+ b/ K0 s8 q! T / E& K* _+ x7 |5 t1 b! I 8 d6 n/ n) L+ F6 _0 Y1 x7 _ 条件2:向上计数模式 + PWM2模式;RCR=2; 极性选择高有效。 基于上面条件,当CCR大于计数器CNT时,OCx端输出低电平,反之输出高电平【即跟PWM1模式时的输出是相反的】。 RCR=2,同样意味着计数器在发生第3次溢出时产生更新事件。- |& A0 Z9 ^. }$ P: j7 t+ X2 H ' q6 b: E& c# M, e; c3 m* M! ` 经验证测试,基于上述条件输出波形变成了下面的样子。 ) e! B6 L, s# P# u8 m 4 _+ n9 U( a7 {( C8 H ; {: H2 h; y# g9 b- Q 【图二、向上计数模式 + PWM2模式RCR=2; 极性选择高有效】 $ Y/ Q* V/ Y$ F1 @6 Z9 Z 3个脉冲输出倒是漂亮。细心的人是否还是发现了最后结尾那个地方有点不对劲呢?第三次发生溢出【CNT==ARR】产生更新事件后,计数器停止计数了,如果此时计数器的值等于ARR的值,根据刚才PWM2模式和极性选择的条件,那输出应该保持为高电平才合理怎么这又变成低了呢? / v. Y. z* P' @5 D( _ 那问题出在哪里呢?似乎哪一副图都存在着原理上说不过去的地方。结合前面的溢出与重装的的介绍与分析,或许有人看出端倪了。 , k+ d9 z4 Y! {+ _' a5 I7 U 5 s8 S; y( ]. U9 ^8 ?; H0 ]' P9 t7 C 其实,这两副图中,最后发生溢出的时刻都是在CNT等于ARR的时候,溢出的同时触发了更新事件。加上定时器工作在单脉冲PWM输出模式,计数器被停止计数。但计数器停止计数,并不妨碍计数器溢出时自动重装载器对其做初始值的重装。那么这个重装值是多少呢?结合这里的计数模式,这个重装值正好是0,即计数器的值变为0了,并停在这个位置。既然溢出后计数器值变为0了,对于PWM1模式+高有效极性选择的话,相应的比较输出结果就是高电平;对于PWM2模式+高有效极性选择的话,相应的比较输出结果就是低电平。经这样分析所得结论,正好跟我们的实测结果一致。6 X N6 O6 X8 Y" ^4 b J: l |