
首先就是影子寄存器 影子寄存器是在比较的时候真正起作用的,目的是为了当预装载寄存器中的值更新后,影子寄存器仍然保持原来的值(这是在ARPE=1的情况下),参与比较操作的是影子寄存器,所以这样不会影响到计数器的工作误差。在ARPE=1的情况下,它在更新事件发生之后影子寄存器的值才从预装载寄存器那里获得更新。 而当ARPE为0时,影子寄存器是立即更新的,不等待更新事件 的发生。 ![]() 定时器框图中:预分频器寄存器、自动重载寄存器、捕捉/比较寄存器下面有一个阴影! 这表示物理上这个寄存器对应2个寄存器:一个是我们可以可以写入或读出的寄存器,称为预装载寄存器,另一个是我们看不见的、无法真正对其读写操作的,但在使用中真正起作用的寄存器,称为影子寄存器.1 [- J+ o7 R3 _. z N 设计预装载寄存器和影子寄存器的好处是,所有真正需要起作用的寄存器(影子寄存器)可以在同一个时间(发生更新事件时)被更新为所对应的预装载寄存器的内容,这样可以保证多个通道的操作能够准确地同步。如果没有影子寄存器,软件更新预装载寄存器时,则同时更新了真正操作的寄存器,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上例如中断等其它因素,多个通道的时序关系有可能会混乱,造成是不可预知的结果。 这是我找到的两个关于这方面的解释,基本上解释清楚了。记住: 预分频器寄存器PSC、自动重载寄存器ARR、捕捉/比较寄存器CCR, y: r" q, [; N: U 这三种寄存器在物理上是分为两个寄存器的即可。$ }/ a( E6 r6 A# z( A- ]$ K & T w7 J6 u% q3 S" e - M" G* S/ S1 s* E# o 之后是6 E/ L0 p7 N6 G& e \ % w1 {0 Q {# p三个库函数,3.5版2 l' w0 j+ p0 q' L: I' N/ [" f TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode) @arg TIM_PSCReloadMode_Update: The Prescaler is loaded at the update event.(更新事件到来时更新), m/ o9 O4 P+ M' L1 D7 F; t4 S @arg TIM_PSCReloadMode_Immediate: The Prescaler is loaded immediately(随时、立即更新). TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState) @arg Enable || Disable TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload) @arg TIM_OCPreload_Enable || TIM_OCPreload_Disable0 Q% c3 Z& p& E0 S3 s* W 1 b2 d0 d* _9 p8 O 读一下函数名就知道,这三个函数就是针对预装载开启与否的!如果不开启,修改的就是实际用于比较的影子寄存器了!!!9 E( q. j2 S: x 开启的话,只在更新事件到来时(即计数器=重装载寄存器时的溢出、定时器初始化时触发的事件),更新实际用于比较的影子寄存器。 由于原子和野火的开发手册里只针对PWM输出这一种模式进行了介绍。其实定时器输出有好几种模式。后边说。 6 |# w1 K- N3 Z$ h% F原子的例程中:在PWM实验的代码中,只开启了捕获比较寄存器的预装载功能/ O5 F/ g/ |6 S TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);3 Z' d6 ?( o* H! _ 而在输入捕获实验的代码中,同时开启了捕获比较寄存器的预装载功能;和自动重装载寄存器的预装载功能% R" B. W1 [7 b2 W7 q TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);8 P5 g0 r: S: Q* c* u7 y7 ` TIM_ARRPreloadConfig(TIM3, ENABLE); / R% t- |0 k6 q7 Q1 u) x- ]# R " Y2 J, y6 p, Q G" V" O 搞的我顿时懵逼了。。。不知道这些个函数到底起什么作用。 不懂机制的话,即使翻到函数实体处看具体操作了什么寄存器,也看不懂的!!!9 [% n6 y1 K3 @0 }7 Z( \ 这里,重点来了,我找了几个程序看了看,又试着调试了一下,符合我的判断。。。 【大家看我总结的对不哈,讨论一下】& t/ o Z2 ^- d1 W& D; Q6 i6 ~# X ) Z; `! J* y. B6 }, M' Y 在《STM32自学笔记》中,仅仅对于输出模式,他就列举了三种: <推荐大家去看看> 计数模式Timing、比较触发模式Toggle、PWM模式,其实还有几个其他的模式,我也不知道咋用 ![]() 比较Toggle和PWM模式,发现,Toggle模式禁止了OC2Preload!!!7 ?( z+ w5 N$ J* P6 w" G 目的:引脚电平间隔固定时间翻转。假设定时器时钟为100us。1 n0 u0 i0 v& M$ c$ z1 H1 g 思想是:CNT计数到比较寄存器CCR(CCR可随意定一个起始值N)的值,触发中断TIM_IT_CC。 在中断服务函数中获取CCR值,并将CCR值加上固定值(比如4000的话,就是固定间隔时间为0.4s)(N+4000),清中断标志后继续。% N1 P! d9 h- u5 E( H Z5 M 再次进入中断再次加上固定值,此时CCR值为(N+4000+4000),肯定超了CCR最大值65535(16bits)。8 y' r! B- w3 v3 |! v 所以应该对65535取模再赋给CCR,即(N+4000+4000)%65535【他书里没取模 ![]() 这样定时器某个通道的引脚电平就会以固定时间间隔翻转了。 f5 i& u3 U9 n! w) U6 e- D 附上书的内容截图: ![]() : q, c- ^! X _9 h" j7 m8 K 这里为什么禁止了预装载。他的解释,我又没看懂。于是又懵逼了,我擦。。。。 . G$ e& W, P" T" W8 |9 L% b9 @6 X$ J3 H, N* h 后来我推理了一下,应该是这样的:<开启柯南模式> 假如开启了比较捕获寄存器的预装载功能,则比较捕获寄存器真正起作用的影子寄存器只能在计数器溢出的时候才能更新。7 M3 o* H7 t1 e0 W 然而他的机制是每次固定间隔的CCR值是不同的,需要实时、立即更新到影子寄存器中起作用。并以之用于和计数器的值进行比较。不能总是等到更新事件来才修改CCR的影子寄存器。 ![]() 说到这里,估计大家都明白我的意思了吧。。。 ( d2 ^% z# G1 D1 a其他的两个ARR和PSC的预装载都是这个意思,就是修改生效的时刻。。。 7 C# W4 G7 b8 n/ e 而只要你的程序里不修改PSC、ARR、CCR,那么就不用管开启不开启预装载了! |
努力挣金币。 |
https://www.stmcu.org.cn/module/forum/thread-533911-1-1.html |
/STM32入门篇之通用定时器彻底研究.doc |
http://github.com/lennartclaasse ... /master/MPU9250_ROS |
谢谢楼主解决了我的困惑,还有就是CCR好像不用取模吧,貌似是自动溢出取余的?还有那本书我也看过,感觉不咋地,还是手册最好哇![]() |