STM32定时器立即进入更新中断服务程序问题

STM32定时器立即进入更新中断服务程序问题,第1张

 

 

我们在基于ST的标准库或基于CubeMx建立工程,当用到定时器并启用其更新中断时,可能会遇到一使能定时器中断且计算器还未开始计数就立即进入更新中断服务程序的情况。

 

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

 

STM32定时器立即进入更新中断服务程序问题,fa98d594-0d42-11ed-ba43-dac502259ad0.png,第2张

 

我们会发现,刚一使能更新中断还未启动计数器,结果就跑到更新中断服务程序里。

 

看看下面截图,右边TIMER控制寄存器CEN还未置1SR寄存器里的UIF【更新事件标志】已经置1了。

 

STM32定时器立即进入更新中断服务程序问题,fac6e970-0d42-11ed-ba43-dac502259ad0.png,第3张

 

也就是说,计数器还没开始启动就先进了一次更新中断。

 

这种情况很多时候对我们应用可能并无妨碍,但有时也可能带来些问题或麻烦。比方:

 

1、误动作。本来打算基于定时器运作延时特定时间后再在更新中断里完成的动作,这样一来就会出现计数器还未开始工作就进中断执行当前本不该执行的动作了。

2、误计算。当我们基于定时器捕获功能进行信号周期、占空比测量过程中,如果需要统计更新事件时,就有可能因为统计这个不该统计的更新事件而带来误差。

 

该问题怎么产生的呢?

问题是由于我们的TIMER初始化函数里,在对ARR/PSC时基参数做好初始赋值后,软件做了个手动产生更新事件的 *** 作,目的就是让刚才设置的那些时基参数立即生效,并让定时器基于这些新设置的参数开始运行

 

代码大致是下面的层次结构及内容:

 

MX_TIM_Inxit(); ==

HAL_TIM_Base_Init(&htim)==

TIM_Base_SetConfig()

 

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;

}

 

其中,  TIMx->EGR = TIM_EGR_UG;这行代码就是用来手动产生更新事件的。

 

我们知道,STM32定时器中有几个由预装寄存器和影子寄存器组成的寄存器组,他们分别是TIMx_PSC,TIMx_ARR,TIMx_CCR,TIMx_RCR. 【注:基本定时器或通用定时器没有RCR寄存器】

STM32定时器立即进入更新中断服务程序问题,fb0833ee-0d42-11ed-ba43-dac502259ad0.png,第4张

那么如何消除这个问题呢? *** 作很简单,TIMER初始化完成之后,使能定时器更新中断之前加一句清除更新中断请求位的代码即可。比方类似下面 *** 作。

STM32定时器立即进入更新中断服务程序问题,fb2baea0-0d42-11ed-ba43-dac502259ad0.png,第5张

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

 

STM32定时器立即进入更新中断服务程序问题,fb610f28-0d42-11ed-ba43-dac502259ad0.png,第6张

 

的确,没有这句产生更新事件的代码定时器也能跑。

 

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

 

我们以向上计数模式为例,更新事件基于当前用户给定的ARR值计数一个周期后发生溢出而产生,随之新的PSCRCR值才会生效。即二者的生效时间要延后一个周期。 【注:基本定时器或通用定时器没有RCR寄存器】

 

如果说有人自行组织代码,ARR的预装控制位使能打开,然后才给ARR赋值,同样不手动产生更新事件,那又会怎么样呢?抛砖引玉,可以自行结合手册琢磨和测试下。

 

 

ST的库函数的写法是合理的,当然,如果紧跟着做个更新事件标志的清零就更佳了,或许未来这个地方可以再改善下。

 

顺便提下,当你自己尝试在代码里适时而巧妙地使用手动定时器更新 *** 作时,或许会发现这还是个不可多得的一个小技巧。

 

 

好,这个话题就聊到这里。其实,多年前也在这里分享过该话题,只是没有单列出来。这次单列出来再分享下,以资提醒。

 

 

  审核编辑:汤梓红

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/dianzi/2711621.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存