2. MCU 中断系统基础

中断系统是嵌入式实时操作系统的核心硬件机制,它允许 MCU 在响应外部或内部事件时,暂停当前正在执行的主程序,转而执行一个特定的处理程序,处理完成后再返回主程序断点处继续执行。理解中断概念、中断向量表、中断服务函数以及中断嵌套与抢占,是配置定时器中断优先级和优化实时响应的前提。

2.1 中断概念与触发机制

中断(Interrupt)是一种硬件或软件驱动的异步事件处理机制。当某个事件发生时(例如定时器计数溢出、GPIO 引脚电平变化、CAN 总线接收到报文),MCU 的硬件逻辑会自动保存当前 CPU 状态(PC、PSW 等寄存器),并跳转到与该事件对应的中断服务函数入口地址执行。

关键特性:
  • 异步性:中断的发生与主程序执行流无关,可在任意时刻触发。
  • 硬件自动响应:CPU 在每条指令执行结束后检查中断标志,无需软件轮询。
  • 可屏蔽性:大部分中断可通过 CPU 的中断使能位(如 ARM Cortex-M 的 PRIMASK)或外设的中断使能寄存器进行全局或局部屏蔽。

中断源通常分为两类:

类型 触发方式 典型示例
外部中断 由 MCU 外部引脚电平变化触发 按键输入、传感器信号、外部故障信号
内部中断 由 MCU 内部外设或软件触发 定时器溢出、ADC 转换完成、DMA 传输完成、软件中断(SWI)

2.2 中断向量表

中断向量表(Interrupt Vector Table, IVT)是 MCU 内存中一张固定的地址映射表,表中每个条目存储着对应中断服务函数的入口地址。当 MCU 响应某个中断时,硬件会自动根据中断号从向量表中取出地址并跳转执行。

在 ARM Cortex-M 系列(如 Infineon TC3xx、NXP S32K、ST SPC5)中,向量表通常位于 Flash 或 RAM 的起始地址(如 0x00000000),且支持重定位(通过 VTOR 寄存器)。

车载 MCU 注意点: 在 Bootloader 与应用程序切换时,必须正确重定位中断向量表,否则中断响应会跳转到错误地址,导致系统崩溃。

典型中断向量表结构(以 32 位 MCU 为例):

// 中断向量表示例(伪代码)
typedef void (*ISR_Func)(void);

const ISR_Func __attribute__((section(".isr_vector"))) VectorTable[] = {
    &Reset_Handler,          // 0x0000: 复位向量
    &NMI_Handler,            // 0x0004: 不可屏蔽中断
    &HardFault_Handler,      // 0x0008: 硬件错误
    &MemManage_Handler,      // 0x000C: 内存管理错误
    &BusFault_Handler,       // 0x0010: 总线错误
    &UsageFault_Handler,     // 0x0014: 使用错误
    // ... 系统异常 ...
    &TIM0_IRQHandler,        // 0x0040: 定时器0中断
    &TIM1_IRQHandler,        // 0x0044: 定时器1中断
    &CAN0_IRQHandler,        // 0x0048: CAN0 中断
    // ... 外设中断 ...
};
中断向量表映射与跳转流程 中断向量表映射与跳转流程 定时器溢出 CAN 接收 GPIO 边沿 ADC 转换完成 NVIC 中断优先级仲裁 中断使能/挂起 向量号生成 向量号 中断向量表 (IVT) 0x0000: Reset_Handler 0x0004: NMI_Handler 0x0040: TIM0_IRQHandler 0x0044: TIM1_IRQHandler 0x0048: CAN0_IRQHandler 0x004C: ADC_IRQHandler 跳转 CPU 执行中断服务函数 (ISR) → 完成后返回主程序断点

2.3 中断服务函数 (ISR)

中断服务函数(Interrupt Service Routine, ISR)是中断响应时 CPU 执行的特定代码段。ISR 必须短小精悍,避免阻塞其他中断或影响实时性。

ISR 编写规范:

  • 快速执行:ISR 内不应包含延时、轮询等待或复杂计算,仅做必要的数据保存、标志置位和寄存器清除。
  • 避免调用不可重入函数:如 printf()、malloc() 等,可能导致死锁或堆栈损坏。
  • 正确清除中断标志:在 ISR 返回前必须清除外设的中断挂起位,否则会重复触发中断。
  • 使用 __attribute__((interrupt)) 或编译器专用关键字:确保编译器生成正确的入栈/出栈指令。
// 定时器中断服务函数示例 (ARM Cortex-M)
void TIM0_IRQHandler(void) __attribute__((interrupt));
void TIM0_IRQHandler(void)
{
    // 1. 清除定时器中断标志
    TIM0->SR &= ~TIM_SR_UIF;

    // 2. 读取或处理数据(极简操作)
    g_uiTickCount++;

    // 3. 触发任务调度(RTOS 中)
    // OS_TaskResume(Task_Control);
}
常见错误: 在 ISR 内使用 HAL_Delay() 或 while() 等待硬件标志,会导致中断响应时间不可控,严重时造成系统看门狗复位。

2.4 中断嵌套与抢占

中断嵌套(Interrupt Nesting)是指一个中断服务函数正在执行时,另一个更高优先级的中断发生,CPU 暂停当前 ISR 转而执行更高优先级的 ISR,处理完后再返回被暂停的 ISR 继续执行。抢占(Preemption)是中断嵌套的核心机制。

在车载 MCU 中,中断优先级通常由硬件寄存器(如 ARM Cortex-M 的 NVIC IPR 寄存器)配置,数值越小优先级越高。中断嵌套规则如下:

场景 当前 ISR 优先级 新中断优先级 行为
无嵌套 低(数值大) 更低(数值更大) 新中断等待当前 ISR 完成
抢占 低(数值大) 高(数值小) 立即暂停当前 ISR,执行高优先级 ISR
同优先级 相同 相同 取决于硬件实现,通常不嵌套,等待当前 ISR 完成
车载实时性要求: 定时器中断通常配置为高优先级(如优先级 0 或 1),以确保周期任务(如 1ms 控制循环、CAN 报文发送)不被其他外设中断阻塞。但需注意,过高优先级的中断会延迟低优先级中断的响应,需平衡系统整体实时性。
中断嵌套与抢占时序图 中断嵌套与抢占时序图 时间 → 主程序 (Main) ISR_Low (TIM1) ISR_High (TIM0) ISR_Low 恢复 Main 抢占 返回 t0 t1 t2 t3 t4 t5 中断嵌套时序说明 t0~t1: 主程序执行;t1: 低优先级中断触发,CPU 进入 ISR_Low; t2: 高优先级中断触发,ISR_Low 被抢占,CPU 执行 ISR_High; t3: ISR_High 完成,返回 ISR_Low 继续执行;t4: ISR_Low 完成,返回主程序。

2.5 中断优先级配置原则

在车载 MCU 实时系统中,中断优先级配置直接影响任务响应时间和系统稳定性。以下是核心配置原则:

  1. 时间关键型中断配置最高优先级:如 1ms 定时器中断、发动机曲轴位置传感器中断,应分配最高优先级(数值最小)。
  2. 数据流中断配置中等优先级:如 CAN 接收中断、SPI DMA 完成中断,确保数据不丢失但允许被时间关键中断抢占。
  3. 非关键中断配置最低优先级:如调试 UART 中断、按键扫描中断,避免影响实时控制环路。
  4. 避免优先级反转:当低优先级中断持有共享资源时,高优先级中断可能被阻塞,需通过中断优先级分组或资源锁机制解决。
实践建议: 在项目初期,使用 MCU 的优先级分组寄存器(如 ARM Cortex-M 的 AIRCR.PRIGROUP)将优先级分为抢占优先级和子优先级,抢占优先级用于中断嵌套控制,子优先级用于同抢占优先级下的仲裁。推荐配置为 4 位抢占优先级 + 0 位子优先级,简化嵌套逻辑。