
我们在基于ST的标准库或基于CubeMx建立工程,当用到定时器并启用其更新中断时,可能会遇到一使能定时器中断且计算器还未开始计数就立即进入更新中断服务程序的情况。 可能出现该现象的场合大概像下面样子,即先使能定时器更新中断,然后才去启动计数器。 ![]() 我们会发现,刚一使能更新中断还未启动计数器,结果就跑到更新中断服务程序里。 看看下面截图,右边TIMER控制寄存器CEN还未置1,SR寄存器里的UIF【更新事件标志】已经置1了。 ![]() 也就是说,计数器还没开始启动就先进了一次更新中断。 这种情况很多时候对我们应用可能并无妨碍,但有时也可能带来些问题或麻烦。比方: 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寄存器】 ![]() 那么如何消除这个问题呢?操作很简单,TIMER初始化完成之后,使能定时器更新中断之前加一句清除更新中断请求位的代码即可。比方类似下面操作。 ![]() 或许有人问,我在TIMER初始化过程中自己组织代码时没有手动产生更新事件似乎也没啥问题?定时器跑得好好的?即没有类似下面打叉的语句。 ![]() 的确,没有这句产生更新事件的代码定时器也能跑。 芯片复位后,ARR的预装功能默认关闭,此时改写ARR预装寄存器相当于同时也更新了其影子寄存器【即实际起作用的寄存器】,但PSC和RCR预装寄存器的内容只能借助溢出产生更新事件更新到其影子寄存器而起作用。 我们以向上计数模式为例,更新事件基于当前用户给定的ARR值计数一个周期后发生溢出而产生,随之新的PSC和RCR值才会生效。即二者的生效时间要延后一个周期。 【注:基本定时器或通用定时器没有RCR寄存器】 如果说有人自行组织代码,先将ARR的预装控制位使能打开,然后才给ARR赋值,同样不手动产生更新事件,那又会怎么样呢?抛砖引玉,可以自行结合手册琢磨和测试下。 ST的库函数的写法是合理的,当然,如果紧跟着做个更新事件标志的清零就更佳了,或许未来这个地方可以再改善下。 顺便提下,当你自己尝试在代码里适时而巧妙地使用手动定时器更新操作时,或许会发现这还是个不可多得的一个小技巧。 |
基于定时器捕获测量脉宽的应用示例
狂欢三】STM32C031使用TIM定时器DMA方式实现WS2812彩灯输出(三)
【狂欢三】STM32C031使用TIM定时器DMA方式实现PWM输出(二)
【狂欢三】STM32C031使用TIM定时器PWM输出
stm32使用定时器触发dma传输,启动dma没反应的几种情况的解决方法
定时器剩余通道是否可以做PWM输出呢?
基于STM32双定时器+ADC+DMA实战经验分享
基于STM32的定时器触发ADC时可能遇到的情形
【NUCLEO-U545RE-Q评测】5. 基本计时器
基于STM32的定时器不按设定超时产生中断