1. 中断基础概念:什么是中断、中断向量表、中断服务函数(ISR)的执行流程

中断机制是嵌入式系统响应外部或内部异步事件的基石。理解中断的底层原理,是后续配置中断优先级、提升外设驱动稳定性的前提。本节将从三个核心维度展开:中断的本质、中断向量表的组织方式、以及中断服务函数(ISR)的完整执行流程。

1.1 什么是中断

中断(Interrupt)是一种硬件机制,允许外设或内核内部事件暂停当前正在执行的程序,转而执行一段预先定义好的特殊函数(ISR),处理完后再恢复原程序的执行。它解决了CPU轮询(Polling)方式下的低效问题——CPU无需一直检查外设状态,只有在事件发生时才会被“通知”。

核心要点:中断是CPU与外设之间的“事件驱动”通信方式,而非“查询驱动”。
对比维度 轮询方式 中断方式
CPU利用率 低(大量时间浪费在查询) 高(无事时执行主任务)
实时性 差(响应延迟取决于查询周期) 强(事件触发立即响应)
代码复杂度 简单(循环+条件判断) 中等(需配置中断向量、ISR)
功耗 高(CPU持续运行) 低(可进入休眠,中断唤醒)
实战提示:在低功耗IoT设备中,中断是必选方案。例如,UART接收中断可以让CPU在无数据时进入睡眠模式,数据到达时自动唤醒。

1.2 中断向量表

中断向量表(Interrupt Vector Table, IVT)是MCU内部一张地址映射表,表中每一项(向量)存放着对应中断服务函数(ISR)的入口地址。当某个中断被触发时,CPU硬件自动从向量表中取出对应的地址,跳转执行。

  • 固定基址:大多数ARM Cortex-M系列MCU的向量表默认位于Flash起始地址(如0x00000000),但可通过VTOR寄存器重定位到SRAM或Flash的其他位置。
  • 向量编号:每个中断源对应一个唯一的向量编号(IRQn),编号越小优先级越高(部分架构相反)。
  • 异常与中断:复位、NMI、HardFault等系统异常也占用向量表的前几个位置,与外部中断统一管理。
中断向量表结构(ARM Cortex-M 示例) 向量偏移 中断源 ISR 入口地址 0x0000 Reset_Handler 0x08000004 0x0004 NMI_Handler 0x08000008 0x0008 HardFault_Handler 0x0800000C 0x000C SVCall_Handler 0x08000010 0x0010 PendSV_Handler 0x08000014 0x0014 SysTick_Handler 0x08000018 0x0018 EXTI0_IRQHandler 0x0800001C 0x001C EXTI1_IRQHandler 0x08000020 ...... 向量表基址可通过 VTOR 寄存器重定位,支持运行时切换中断映射
常见陷阱:向量表地址必须按4字节对齐(Cortex-M要求)。如果使用IAP(在应用编程)升级固件,务必在跳转前重新设置VTOR,否则中断将指向旧向量表,导致程序跑飞。

1.3 中断服务函数(ISR)的执行流程

一个完整的中断响应过程分为三个阶段:中断请求 → 硬件自动压栈与向量查找 → ISR执行与出栈返回。以ARM Cortex-M为例,具体步骤如下:

  1. 中断请求:外设(如UART、定时器)产生中断信号,NVIC(嵌套向量中断控制器)检测到挂起的中断。
  2. 优先级裁决:NVIC比较当前中断与正在执行的中断优先级,若新中断优先级更高,则触发抢占。
  3. 硬件自动压栈:CPU自动将R0-R3、R12、LR、PC、xPSR等8个寄存器压入当前栈(MSP或PSP)。
  4. 向量表查找:CPU根据中断编号从向量表中取出ISR入口地址,加载到PC寄存器。
  5. ISR执行:CPU跳转到ISR函数,执行用户编写的处理代码(如读取数据、清除中断标志)。
  6. 出栈与返回:ISR执行完毕后,执行BX LR指令(LR在进入ISR时被硬件更新为EXC_RETURN),CPU自动出栈恢复现场,继续执行被中断的程序。
中断服务函数(ISR)完整执行流程 ① 外设产生中断请求 ② NVIC 优先级裁决 ③ 硬件自动压栈 (8寄存器) ④ 向量表查找 → 加载PC ⑤ ISR 执行 (用户代码) ISR 必须短小精悍,避免阻塞;退出时硬件自动出栈恢复现场

1.4 ISR 编写规范与注意事项

  • 快速执行:ISR中不应包含延时、轮询、复杂计算等阻塞操作,应尽快清除中断标志并退出。
  • 避免重入:同一中断在ISR执行期间再次触发,可能导致栈溢出或数据竞争。通常通过硬件屏蔽或软件标志防止重入。
  • 使用 volatile:ISR与主程序共享的全局变量必须声明为 volatile,防止编译器优化导致数据不一致。
  • 中断嵌套:高优先级中断可以抢占低优先级ISR,但嵌套深度应受控,避免栈溢出。
// 典型 UART 接收中断 ISR 示例 (STM32 HAL 风格)
volatile uint8_t rx_buffer[256];
volatile uint16_t rx_index = 0;

void USART1_IRQHandler(void)
{
    // 1. 检查中断标志
    if (USART1->SR & USART_SR_RXNE)
    {
        // 2. 读取数据
        uint8_t data = USART1->DR;

        // 3. 存入缓冲区(非阻塞)
        if (rx_index < 256)
        {
            rx_buffer[rx_index++] = data;
        }

        // 4. 清除标志(读DR自动清除RXNE)
        // 某些外设需手动写标志位清除
    }
}
进阶思考:在RTOS环境下,ISR通常只做“标记-通知”工作(如发送信号量或消息队列),实际数据处理交给任务上下文,以缩短关中断时间。

1.5 本章小结