STM32正交编码器模式下如何配置定时器每次计数增减触发中断
STM32 TIM编码器模式每次计数变化触发中断的实现方案
问题本质说明
你之前的方案无法实现的核心原因:
STM32定时器的更新中断仅在CNT寄存器上溢(从ARR值跳转到0)或下溢(从0跳转到ARR值)时触发。你设置ARR=1时,CNT每2次变化才会触发1次更新中断,对应100次计数仅产生50次中断符合该逻辑。另外STM32定时器ARR寄存器的合法配置最小值为1,设置为0属于无效配置,因此该路径无法满足需求。
方案1:使用定时器捕获比较(CC)中断实现(推荐)
该方案无需修改原有编码器计数逻辑,性能更稳定,不会出现外部中断可能的抖动问题:
- 保持TIM4原有编码器模式
Encoder Mode TI1 and TI2配置不变,设置TIM4->PSC = 0,TIM4->ARR = 99,刚好匹配你单圈0~99的计数范围 - 配置TIM4的捕获比较通道1为比较匹配模式,设置初始比较值
TIM4->CCR1 = TIM4->CNT,开启通道1比较中断:TIM4->DIER |= TIM_DIER_CC1IE - 在NVIC中开启TIM4的中断通道,配置合适的优先级
- 中断服务函数中每次处理完业务逻辑后,更新比较值为当前CNT的值,下次CNT变化时会自动触发新的比较匹配中断
代码示例
初始化配置
// TIM4时钟、GPIO、编码器模式已配置完成的前提下 TIM4->PSC = 0; TIM4->ARR = 99; TIM4->CCR1 = TIM4->CNT; // 初始比较值匹配当前计数器值 TIM4->DIER |= TIM_DIER_CC1IE; // 开启CC1比较中断 // NVIC配置 NVIC_EnableIRQ(TIM4_IRQn); NVIC_SetPriority(TIM4_IRQn, 2, 0); // 优先级按需调整 // 启动定时器 TIM4->CR1 |= TIM_CR1_CEN;
中断服务函数
void TIM4_IRQHandler(void) { // 判断为CC1比较匹配中断 if (TIM4->SR & TIM_SR_CC1IF) { TIM4->SR = ~TIM_SR_CC1IF; // 清除中断标志 // 此处添加你每次计数变化需要执行的业务逻辑 // 更新比较值为当前CNT,下次计数变化自动触发中断 TIM4->CCR1 = TIM4->CNT; } // 如需保留原有更新中断逻辑,可在此处添加对应判断处理 }
方案2:使用GPIO双边沿外部中断实现
如果不需要占用定时器捕获比较通道,可使用该方案实现:
- 将TIM4_CH1、TIM4_CH2对应的两个GPIO引脚配置为双边沿触发的外部中断
- 两个外部中断共用同一个服务函数,每次触发时直接读取
TIM4->CNT的值执行业务逻辑即可 - 注意配置外部中断优先级高于其他低优先级任务,避免丢中断
内容的提问来源于stack exchange,提问作者MHBagh
相关产品推荐
相关产品推荐

