你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

一使能定时器中断就立即进入中断程序?

[复制链接]
STMCU小助手 发布时间:2022-8-14 15:47
我们在基于ST的标准库或基于CubeMx建立工程,当用到定时器并启用其更新中断时,可能会遇到一使能定时器中断且计算器还未开始计数就立即进入更新中断服务程序的情况。

( ]& ^4 F0 B5 |
可能出现该现象的场合大概像下面样子,即先使能定时器更新中断,然后才去启动计数器。

) B( K1 c/ K8 a
微信图片_20220814154714.png
7 S3 z6 }3 O$ z, E; h
我们会发现,刚一使能更新中断还未启动计数器,结果就跑到更新中断服务程序里。% j3 J% q2 {7 _& T4 j0 _
: W2 m, `" E8 x7 I3 f) x+ {
看看下面截图,右边TIMER控制寄存器CEN还未置1,SR寄存器里的UIF【更新事件标志】已经置1了。

3 K: [, Y  Y6 W& q  r0 U
微信图片_20220814154711.png

2 X1 b9 N3 S  ^. T
也就是说,计数器还没开始启动就先进了一次更新中断。

7 `% O) }9 n6 N- U
这种情况很多时候对我们应用可能并无妨碍,但有时也可能带来些问题或麻烦。比方:
% p; Q4 T) a4 o7 K
1、误动作。本来打算基于定时器运作延时特定时间后再在更新中断里完成的动作,这样一来就会出现计数器还未开始工作就进中断执行当前本不该执行的动作了。
2、误计算。当我们基于定时器捕获功能进行信号周期、占空比测量过程中,如果需要统计更新事件时,就有可能因为统计这个不该统计的更新事件而带来误差。
- G) y# k/ m8 n  V1 u2 D$ m
该问题怎么产生的呢?
问题是由于我们的TIMER初始化函数里,在对ARR/PSC等时基参数做好初始赋值后,软件做了个手动产生更新事件的操作,目的就是让刚才设置的那些时基参数立即生效,并让定时器基于这些新设置的参数开始运行。
. [5 ~/ x3 G, C
代码大致是下面的层次结构及内容:

& P* a$ y: j2 r9 S
MX_TIM_Inxit(); ==》
HAL_TIM_Base_Init(&htim)==》
TIM_Base_SetConfig()

! Y6 A1 ~6 N: s  [& X- F5 h
void TIM_Base_SetConfig(TIM_TypeDef *TIMx, TIM_Base_InitTypeDef *Structure)
{
…..
/* Set the auto-reload preload */
MODIFY_REG(tmpcr1, TIM_CR1_ARPE, Structure->AutoReloadPreload);
TIMx->CR1 = tmpcr1;
/* Set the Autoreload value */
TIMx->ARR = (uint32_t)Structure->Period ;
/* Set the Prescaler value */
TIMx->PSC = Structure->Prescaler;
if (IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx))
{
/* Set the Repetition Counter value */
TIMx->RCR = Structure->RepetitionCounter;
}
/* Generate an update event to reload the Prescaler
and the repetition counter (only for advanced timer) value immediately */
TIMx->EGR = TIM_EGR_UG;
}

, K, z0 ?9 n7 t! |# d+ x8 D8 [
其中,  TIMx->EGR = TIM_EGR_UG;这行代码就是用来手动产生更新事件的。

( |7 I0 }  k& T' C( b0 a8 |
我们知道,STM32定时器中有几个由预装寄存器和影子寄存器组成的寄存器组,他们分别是TIMx_PSC,TIMx_ARR,TIMx_CCR,TIMx_RCR. 【注:基本定时器或通用定时器没有RCR寄存器】
% ]( Z" v; `4 v. O9 O  i
微信图片_20220814154704.png

, V' t, _9 T$ _4 n
那么如何消除这个问题呢?操作很简单,TIMER初始化完成之后,使能定时器更新中断之前加一句清除更新中断请求位的代码即可。比方类似下面操作。
- H: e6 U: D5 F6 ^& W
微信图片_20220814154701.png

, J2 S& K5 j7 E8 q. Z4 I9 G
或许有人问,我在TIMER初始化过程中自己组织代码时没有手动产生更新事件似乎也没啥问题?定时器跑得好好的?即没有类似下面打叉的语句。

1 u; F$ i! y: A% j/ }
微信图片_20220814154658.png
8 c5 y/ J8 }2 r$ |" Q
的确,没有这句产生更新事件的代码定时器也能跑。

1 Q3 R6 N, A: k( d
芯片复位后,ARR的预装功能默认关闭,此时改写ARR预装寄存器相当于同时也更新了其影子寄存器【即实际起作用的寄存器】,但PSC和RCR预装寄存器的内容只能借助溢出产生更新事件更新到其影子寄存器而起作用。

( F& |& }0 y1 }6 ^' u3 F0 Q
我们以向上计数模式为例,更新事件基于当前用户给定的ARR值计数一个周期后发生溢出而产生,随之新的PSC和RCR值才会生效。即二者的生效时间要延后一个周期。 【注:基本定时器或通用定时器没有RCR寄存器】
8 f/ K( z& T4 g+ X4 l
如果说有人自行组织代码,先将ARR的预装控制位使能打开,然后才给ARR赋值,同样不手动产生更新事件,那又会怎么样呢?抛砖引玉,可以自行结合手册琢磨和测试下。
/ K+ \- g3 }- B8 Y3 C6 J6 K) n7 J
7 q  {: h' h  t& t2 Q% R
ST的库函数的写法是合理的,当然,如果紧跟着做个更新事件标志的清零就更佳了,或许未来这个地方可以再改善下。
$ M1 o& J, P- ^  V
顺便提下,当你自己尝试在代码里适时而巧妙地使用手动定时器更新操作时,或许会发现这还是个不可多得的一个小技巧。
$ c* n* i2 Z5 H8 l) P: n
# U% l$ J. y9 i  b; |7 j

9 B' x5 j5 c9 V, D! q- t; \2 X
赞 收藏 评论0 发布时间:2022-8-14 15:47

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版