NXP MXRT1062定时器溢出中断未触发问题求助
定时器溢出中断未触发问题排查与修复
我使用定时器捕获外部信号上升沿的时间间隔,边沿中断工作正常,但当外部信号频率过低时,定时器溢出中断并未触发。以下是我的相关代码:
定时器初始化代码
const qtmr_config_t TMR1_Channel_0_config = { .primarySource = kQTMR_ClockDivide_128, .secondarySource = kQTMR_Counter0InputPin, .enableMasterMode = false, .enableExternalForce = false, .faultFilterCount = 0, .faultFilterPeriod = 0, .debugMode = kQTMR_HaltCounter }; static void TMR1_init(void) { /* Quad timer channel Channel_0 peripheral initialization */ QTMR_Init(TMR1_PERIPHERAL, TMR1_CHANNEL_0_CHANNEL, &TMR1_Channel_0_config); /* Setup the Input capture mode of the timer channel */ QTMR_SetupInputCapture(TMR1_PERIPHERAL, TMR1_CHANNEL_0_CHANNEL, kQTMR_Counter0InputPin, false, true, kQTMR_RisingEdge); /* Enable interrupt requests of the timer channel */ QTMR_EnableInterrupts(TMR1_PERIPHERAL, TMR1_CHANNEL_0_CHANNEL, kQTMR_EdgeInterruptEnable | kQTMR_OverflowInterruptEnable); NVIC_SetPriority(TMR1_IRQN, TMR1_IRQ_PRIORITY); /* Enable interrupt TMR1_IRQn request in the NVIC. */ EnableIRQ(TMR1_IRQN); /* Start the timer - select the timer counting mode */ QTMR_StartTimer(TMR1_PERIPHERAL, TMR1_CHANNEL_0_CHANNEL, kQTMR_PriSrcRiseEdge); }
中断服务程序代码
void TMR1_IRQHANDLER(void) { uint8_t TimerChannelIndex; volatile uint32_t CAP_periodus; volatile uint32_t CAP_counter2; portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE; for( TimerChannelIndex = 0; TimerChannelIndex < TIMER_CHANNEL_NUM; TimerChannelIndex++ ) { if (QTMR_GetStatus( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ] ) & kQTMR_OverflowFlag) //Eliot added to detect overflow { QTMR_ClearStatusFlags( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ], kQTMR_OverflowFlag ); TimerOverflowCount[TimerChannelIndex]++; } else{ if ( QTMR_GetStatus( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ] ) & kQTMR_EdgeFlag ) { QTMR_ClearStatusFlags( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ], kQTMR_EdgeFlag ); CAP_counter = TMR1_PERIPHERAL->CHANNEL[ TimerChannel[ TimerChannelIndex ] ].CAPT; CAP_periodus = COUNT_TO_USEC( CAP_counter, TimerChannelClockSource[ TimerChannelIndex ] ); CAP_periodwheel[ TimerChannelIndex ] = TimerOverflowCount[TimerChannelIndex]*COUNT_TO_USEC( 0xFFFF, TimerChannelClockSource[ TimerChannelIndex ] ) + CAP_periodus; wheelteeth[TimerChannelIndex]++; TimerOverflowCount[TimerChannelIndex] = 0; } } } }
问题原因及修复方案
1. 定时器计数模式错误
当前使用kQTMR_PriSrcRiseEdge启动定时器,该模式下计数器仅在主时钟源的边沿触发时递增,若外部信号频率极低,计数器无法持续运行,导致溢出中断无法触发。
修复:
将定时器启动模式改为kQTMR_CounterIncrement,让定时器基于主时钟(分频128后的内部时钟)持续递增计数,确保溢出事件能正常产生:
QTMR_StartTimer(TMR1_PERIPHERAL, TMR1_CHANNEL_0_CHANNEL, kQTMR_CounterIncrement);
2. 中断标志处理逻辑缺陷
当前ISR中使用else分支,若同时出现溢出和边沿捕获事件,只会处理其中一个,可能遗漏溢出中断的处理。
修复:
移除else分支,并行判断两个中断标志,确保两种事件都能被处理:
for( TimerChannelIndex = 0; TimerChannelIndex < TIMER_CHANNEL_NUM; TimerChannelIndex++ ) { // 处理溢出中断 if (QTMR_GetStatus( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ] ) & kQTMR_OverflowFlag) { QTMR_ClearStatusFlags( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ], kQTMR_OverflowFlag ); TimerOverflowCount[TimerChannelIndex]++; } // 处理边沿捕获中断 if ( QTMR_GetStatus( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ] ) & kQTMR_EdgeFlag ) { QTMR_ClearStatusFlags( TMR1_PERIPHERAL, TimerChannel[ TimerChannelIndex ], kQTMR_EdgeFlag ); CAP_counter = TMR1_PERIPHERAL->CHANNEL[ TimerChannel[ TimerChannelIndex ] ].CAPT; CAP_periodus = COUNT_TO_USEC( CAP_counter, TimerChannelClockSource[ TimerChannelIndex ] ); CAP_periodwheel[ TimerChannelIndex ] = TimerOverflowCount[TimerChannelIndex]*COUNT_TO_USEC( 0xFFFF, TimerChannelClockSource[ TimerChannelIndex ] ) + CAP_periodus; wheelteeth[TimerChannelIndex]++; TimerOverflowCount[TimerChannelIndex] = 0; } }
3. 额外验证点
- 确认
COUNT_TO_USEC宏的时间换算逻辑正确,保证溢出时间计算无误 - 检查NVIC优先级配置,避免溢出中断被高优先级任务抢占无法响应
内容的提问来源于stack exchange,提问作者Eliot Todo
相关产品推荐
相关产品推荐

