You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 19:35:04