4. PIC32中断系统与实时响应

在实时系统中,中断是连接外部事件与CPU处理逻辑的核心机制。PIC32系列MCU基于MIPS M4K/M14K内核,其中断控制器提供了多源、多优先级、可嵌套的向量中断体系。理解中断源分类、优先级仲裁、向量表偏移、延迟构成以及嵌套配置方法,是构建确定性实时响应的基础。本节以PIC32MX系列(如PIC32MX795F512L)为参考对象,围绕外部中断与定时器中断的实战配置展开。

中断源与优先级体系

PIC32的中断源分为两类:外部中断(INT0~INT4,对应引脚电平或边沿触发)和内部外设中断(定时器、UART、SPI、ADC、DMA、比较器等)。每个中断源在中断控制器中拥有固定的自然优先级(IRQ编号),编号越小优先级越高。例如INT0为IRQ0,定时器1为IRQ4,UART1为IRQ24。但实际运行时的仲裁优先级由IPCx寄存器中的IPL字段(3位)和子优先级字段(3位)共同决定,形成7级主优先级(IPL1~IPL7)和每级4个子优先级(SPL0~SPL3)。

仲裁规则为:先比较主优先级IPL,高者胜出;主优先级相同时比较子优先级SPL,高者胜出;两者均相同则比较自然优先级IRQ编号,编号小者胜出。这一规则决定了多中断同时挂起时的响应顺序。当前CPU运行的中断优先级由IPL<2:0>状态位记录,只有优先级高于当前IPL的中断才能抢占,否则保持挂起。

PIC32中断优先级仲裁与嵌套响应示意 中断源(示例) INT0 外部按键 IRQ0 · IPL6 · SPL2 Timer1 周期中断 IRQ4 · IPL5 · SPL1 UART1 接收中断 IRQ24 · IPL3 · SPL0 ADC 转换完成 IRQ27 · IPL2 · SPL3 SPI1 传输完成 IRQ20 · IPL4 · SPL0 优先级仲裁器 ① 比较 IPL ② 比较 SPL ③ 比较 IRQ 编号 当前 IPL 屏蔽 低优先级中断 CPU 内核 当前 IPL 状态 中断使能 IE=1 异常级别 EXL=0 最高优先级 向量表 OFFx 偏移寄存器 EBASE + OFFx 跳转至 ISR 嵌套条件 新中断 IPL > 当前 IPL 且 IE=1 且 EXL=0 满足则抢占 否则挂起 ISR 中可写 IPL 提升屏蔽

向量表与中断延迟构成

PIC32采用向量中断模式,每个中断源可拥有独立的入口地址。向量表基址由EBASE寄存器指定,各中断的偏移量由OFFx寄存器配置。典型做法是将向量表放在0x9D000000(KSEG0程序空间)或0x80000000(KSEG0缓存区),每个向量间隔通常为32字节,足够放置一条跳转指令。中断发生时,硬件自动完成:保存PC到EPC、设置EXL=1、跳转到对应向量地址。向量入口处通常放置跳转指令,指向实际的C语言ISR函数。

中断延迟是指从事件发生到ISR第一条指令执行的时间,主要由四部分构成:①同步延迟(外部信号经同步器采样,约2~3个SYSCLK周期);②仲裁延迟(优先级比较与屏蔽判断,约1~2周期);③流水线冲刷(MIPS内核需清空已取指流水线,约3~5周期);④向量跳转与现场保存(跳转至ISR并执行上下文保存,取决于编译器生成的prologue,通常10~30周期)。以80MHz SYSCLK为例,若总延迟约40周期,则对应约0.5μs。实际测量时,可在ISR入口翻转一个GPIO引脚,用示波器观察事件边沿到引脚翻转的时间差,即可获得包含上述全部环节的端到端延迟。

嵌套中断配置与外部事件响应实战

嵌套中断允许高优先级ISR抢占正在执行的低优先级ISR。配置要点:在低优先级ISR中,需将当前IPL提升至该中断的优先级(通过SET_IPL()或写CP0 Status寄存器),以屏蔽同级和低级中断;同时保持IE=1、EXL=0。高优先级中断到来时,硬件自动保存当前上下文并跳转。返回时使用eret指令恢复。

以下示例配置INT0(按键,IPL6)和Timer1(IPL5),Timer1中断中允许被INT0抢占:

// 配置INT0:下降沿触发,IPL6,子优先级2
INT0bits.INTEDGE = 0;      // 下降沿
IPC0bits.INT0IP = 6;       // 主优先级6
IPC0bits.INT0IS = 2;       // 子优先级2
IEC0bits.INT0IE = 1;       // 使能INT0

// 配置Timer1:周期中断,IPL5,子优先级1
IPC1bits.T1IP = 5;
IPC1bits.T1IS = 1;
IEC0bits.T1IE = 1;

// 全局使能
INTEnableSystemMultiVectoredInt();

// Timer1 ISR中允许嵌套
void __ISR(_TIMER_1_VECTOR, IPL5SOFT) Timer1Handler(void) {
    SET_IPL(5);            // 提升当前IPL至5,屏蔽≤5的中断
    // ... 处理逻辑
    IFS0bits.T1IF = 0;     // 清标志
}

// INT0 ISR(高优先级,可抢占Timer1)
void __ISR(_EXTERNAL_0_VECTOR, IPL6SOFT) Int0Handler(void) {
    // 紧急响应:记录时间戳、置位事件标志
    IFS0bits.INT0IF = 0;
}

测量嵌套响应时,可在Timer1 ISR中翻转RA0,在INT0 ISR中翻转RA1。当按键事件在Timer1处理期间到达,示波器上RA1的翻转应出现在RA0高电平期间,且RA0恢复后继续执行,证明嵌套成功。若RA1始终等待RA0结束后才翻转,则说明嵌套未生效,需检查IPL提升和EXL状态。

调试嵌套中断时,优先确认三个条件:新中断IPL严格大于当前IPL、全局IE=1、EXL=0。任何一条不满足,中断都会挂起而非抢占。

中断延迟测量与结果判读

精确测量中断延迟需要区分硬件延迟和软件延迟。硬件延迟由同步器、仲裁器和流水线冲刷决定,通常固定;软件延迟取决于ISR入口的上下文保存和编译器优化等级。使用GPIO翻转法时,建议在ISR最开头(prologue之前)用内联汇编直接操作端口寄存器,减少测量误差。例如:

void __ISR(_EXTERNAL_0_VECTOR, IPL6SOFT) Int0Handler(void) {
    LATAINV = 0x0001;      // 立即翻转RA0,不等待编译器保存上下文
    // ... 后续处理
    IFS0bits.INT0IF = 0;
}

若测得延迟为0.6μs(80MHz下约48周期),其中硬件部分约0.15μs,软件部分约0.45μs。若软件部分明显偏大,可检查是否开启了中断现场保护、是否使用了浮点运算或函数调用层级过深。优化方向包括:将ISR标记为__attribute__((interrupt))、减少局部变量、避免在ISR中调用非内联函数。

外部事件响应的确定性不仅取决于单次延迟,还取决于最坏情况延迟。当多个中断同时挂起时,低优先级中断必须等待所有高优先级ISR执行完毕。因此,在实时系统设计中,应为关键外部事件分配足够高的IPL,并控制高优先级ISR的执行时间,避免长任务阻塞紧急响应。通过合理配置优先级和嵌套,PIC32可以在微秒级实现确定性的外部事件响应。