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

d6db41d6366ef26a304b99d18fcb0e66.jpeg

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

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

ac54c3b4d6e2e1ab95bedbd9dd3d302e.png

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

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

449bd9d73fc4d1d03d6e7ee29c8302a1.png

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

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

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寄存器】

e32381f0d474844fa9c72c76fd6f006a.png

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

4d01a675025f2fdd705313929112ca26.png

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

05774121e9bac36fc7819350841a2a9c.png

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

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

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

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

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

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

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

124303113dea2d08fb1a5f1b4b27e90d.png

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值