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

PIC32MK1024MCM064定时器2中断服务程序(ISR)卡死求助

PIC32MK定时器ISR卡住无法返回主循环的问题解决

问题根源分析

你的代码首次触发Timer2中断后卡在ISR中,主要由以下几个错误导致:

  1. 32位定时器未清除高16位计数器
    启用32位定时器模式(T2CONbits.T32=1)时,Timer2和Timer3组成32位计数器,TMR2是低16位,TMR3是高16位。你仅清除了TMR2,TMR3保留了中断触发时的高值,重新开启定时器后,TMR3:TMR2会快速达到PR3:PR2(PR3默认0),立即再次触发中断,导致ISR反复执行无法返回主循环。

  2. PB2DIV寄存器配置错误

    • PB2DIVbits.PBDIVRDY是只读状态位,手动赋值会导致配置失效;
    • 你想要128分频,但PB2DIVbits.PBDIV=0b0000000实际是1分频,导致定时器时钟远快于预期。
  3. 中断标志清除时机不当
    你在ISR末尾清除中断标志,若处理过程中意外触发中断(即使概率低),会导致重复进入ISR。

  4. ISR中不必要的定时器启停
    自触发定时器无需在ISR中关闭再开启,此操作不仅冗余,还可能引入时序问题。

  5. ISR中调用阻塞式延迟
    中断服务程序应尽量简洁,长时间阻塞会破坏系统实时性,甚至引发其他异常。

修正后的代码

定时器配置函数修正

void Timer2_setup(void){
  PB2DIVbits.ON = 0b0;            // 关闭PB2CLK以修改分频
  PB2DIVbits.PBDIV = 0b00001000;   // 设置PB2CLK为SYSCLK/128
  PB2DIVbits.ON = 0b1;            // 重新开启PB2CLK 
  //---------------------------------------------------- 
  T2CONbits.ON = 0b0;             // 关闭Timer2
  T2CONbits.TCS = 0b0;            // 使用内部外设时钟
  T2CONbits.T32 = 0b1;            // 启用32位定时器模式(Timer2+Timer3)
  T2CONbits.TCKPS = 0b101;        // 1:256预分频
  T2CONbits.SIDL = 0b1;           // 空闲模式下停止定时器
  TMR2 = 0x0;                     // 清除低16位计数器
  TMR3 = 0x0;                     // 清除高16位计数器
  PR2 = 124999U;                  // 低16位周期值(8MHz SYSCLK下约1秒)
  PR3 = 0x0;                      // 高16位周期值
  //---------------------------------------------------- 
  // 中断配置
  IFS0bits.T2IF = 0b0;            // 预先清除中断标志
  IEC0bits.T2IE = 0b1;            // 启用Timer2中断
  IPC2bits.T2IP = 0b001;          // 设置中断优先级为1
}

中断服务程序修正(简洁版,推荐)

// 全局标志位,用于在主循环中处理中断任务
volatile bool timer_triggered = false;

void __ISR( _TIMER_2_VECTOR, IPL1SRS) Timer2_Handler (void){
    IFS0bits.T2IF = 0b0;           // 立即清除中断标志,避免重复触发
    timer_triggered = true;        // 设置中断触发标志
    TMR2 = 0x0;                     // 清除低16位计数器
    TMR3 = 0x0;                     // 清除高16位计数器
}

主循环修正

int main ( void )
{ 
    TRISAbits.TRISA7 = 0; 
    LATAbits.LATA7 = 0;
    
    TRISBbits.TRISB14 = 0; 
    LATBbits.LATB14 = 0;
    
    TRISBbits.TRISB15 = 0; 
    LATBbits.LATB15 = 0;
  
    Timer2_setup();
    __builtin_enable_interrupts();  // 全局启用中断
  
    T2CONbits.ON = 0b1;             // 启动Timer2 
    
    while (1)
    {                
        LATBbits.LATB14 = 1;
        delay_ms(300);
        LATBbits.LATB14 = 0;
        LATBbits.LATB15 = 1;
        delay_ms(300);
        LATBbits.LATB15 = 0;
        
        // 在主循环中处理中断触发的任务
        if(timer_triggered){
            timer_triggered = false;
            LATAbits.LATA7 = 1;
            delay_ms(300);
            LATAbits.LATA7 = 0;
        }
    } 
    return (EXIT_FAILURE); 
}

关键注意事项

  • 32位定时器模式下,必须同时操作TMR2和TMR3、PR2和PR3;
  • 中断标志应在ISR开头清除,避免重复触发;
  • ISR应保持极简,仅处理必要的硬件操作(如清标志、清计数器),耗时任务放在主循环中通过标志位触发;
  • 外设时钟分频寄存器的只读位不要手动赋值,严格按照数据手册的配置流程操作。

内容的提问来源于stack exchange,提问作者Vilius Žalėnas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 15:09:14