1. 中断基础概念:中断的定义、中断向量表、中断优先级与嵌套

1.1 中断的定义与核心机制

中断(Interrupt)是嵌入式系统中一种硬件机制,允许外设或软件事件暂停当前CPU正在执行的主程序流,转而执行一个预先定义好的特殊服务程序(中断服务程序,ISR),处理完成后自动返回原程序断点继续执行。中断机制是实时响应外部事件的基础,也是GPIO边沿/电平触发调试的前提。

中断的本质: 中断是一种异步事件处理机制。CPU在每执行完一条指令后,都会检查是否有中断请求(IRQ)挂起。若有,则自动保存当前上下文(PC、PSR、寄存器等),跳转到中断向量表中对应的入口地址执行ISR。
关键术语: 中断源(Interrupt Source)、中断请求(IRQ)、中断服务程序(ISR)、中断向量表(IVT)、中断优先级、中断嵌套、临界区(Critical Section)。

1.2 中断向量表(Interrupt Vector Table, IVT)

中断向量表是一张存储在固定内存地址的表格,表中每一项(向量)存放着对应中断服务程序的入口地址。当CPU响应某个中断时,硬件自动根据中断号从向量表中取出地址并跳转执行。

中断向量号 向量地址偏移 典型用途 优先级(默认)
0 0x0000_0000 复位向量(Reset) 最高(-3,不可屏蔽)
1 0x0000_0004 NMI(不可屏蔽中断) -2
2 0x0000_0008 硬错误(Hard Fault) -1
16 0x0000_0040 SysTick定时器 可配置
32 0x0000_0080 GPIO Port A(典型) 可配置
33 0x0000_0084 GPIO Port B(典型) 可配置
调试注意: 在GPIO中断调试中,若中断未触发,首先检查中断向量表是否已正确映射到对应的GPIO中断号。常见错误:未在启动文件中定义ISR函数名,或ISR函数名与向量表符号不匹配。

以下SVG图展示了ARM Cortex-M内核的中断向量表布局与GPIO中断映射关系:

ARM Cortex-M 中断向量表结构(GPIO中断映射) 中断向量表 向量0:复位 (0x0000) 向量1:NMI (0x0004) 向量2:HardFault (0x0008) ... 向量16:SysTick ... 向量32:GPIO Port A 向量33:GPIO Port B 硬件索引 NVIC 中断控制器 中断使能寄存器 挂起/清除寄存器 优先级寄存器 中断屏蔽寄存器 优先级分组配置 ... 中断请求 CPU Core 保存上下文 取向量地址 跳转ISR执行 恢复上下文 返回主程序 GPIO中断向量号 = 外部中断线号 + 16(Cortex-M3/M4典型架构)

1.3 中断优先级与嵌套

中断优先级决定了当多个中断同时发生时,CPU优先响应哪一个。优先级数值越小,优先级越高(在ARM Cortex-M系列中)。中断嵌套(Interrupt Nesting)是指一个高优先级中断可以打断正在执行的低优先级ISR。

优先级分组模型(ARM Cortex-M)

ARM Cortex-M3/M4支持可编程的优先级分组,将优先级寄存器分为抢占优先级(Preemption Priority)和子优先级(Subpriority)两部分:

分组编号 抢占优先级位数 子优先级位数 抢占优先级数量 子优先级数量
0 0 4 1 16
1 1 3 2 8
2 2 2 4 4
3 3 1 8 2
4 4 0 16 1
调试建议: GPIO中断通常配置为中等优先级(如5~10),避免与系统定时器(SysTick,通常优先级较高)冲突。若出现中断丢失或响应延迟,优先检查优先级分组设置是否一致。

以下SVG图展示了中断嵌套的执行流程:

中断嵌套执行流程示意图 t0 t1 t2 t3 t4 主程序(Main Loop) ISR_Low(优先级=5) ISR_High(优先级=1) GPIO中断请求 高优先级中断抢占 返回低优先级ISR ISR返回 嵌套规则:高优先级中断(数值小)可以打断低优先级中断(数值大),同级中断不能互相嵌套

1.4 中断响应流程(硬件自动完成)

  1. 中断采样: CPU在每条指令结束时采样中断输入引脚或NVIC挂起标志。
  2. 优先级裁决: NVIC比较所有挂起中断的优先级,选择最高优先级中断。
  3. 入栈(Stacking): 硬件自动将PC、PSR、R0-R3、R12、LR压入当前栈(MSP或PSP)。
  4. 取向量: 从向量表中读取对应中断号的ISR入口地址。
  5. 更新寄存器: 更新PC为ISR入口地址,更新LR为特殊返回地址(EXC_RETURN)。
  6. 执行ISR: CPU开始执行中断服务程序。
  7. 出栈(Unstacking): ISR执行完毕后,硬件自动恢复寄存器,返回主程序。
GPIO中断调试要点:
  • 确认GPIO中断在NVIC中已使能(NVIC_EnableIRQ)。
  • 确认中断优先级分组一致(NVIC_SetPriorityGrouping)。
  • 确认ISR函数名与中断向量表符号完全匹配(如 EXTI0_IRQHandler)。
  • 确认中断标志位在ISR中被清除(否则会反复触发)。

1.5 中断优先级配置示例代码

/* 设置优先级分组:3位抢占优先级 + 1位子优先级 */
NVIC_SetPriorityGrouping(5);  // 分组3:3位抢占,1位子优先级

/* 配置GPIO中断优先级 */
NVIC_SetPriority(EXTI0_IRQn, 5);   // 抢占优先级=2(高3位),子优先级=1(低1位)
NVIC_SetPriority(EXTI1_IRQn, 9);   // 抢占优先级=4,子优先级=1

/* 使能中断 */
NVIC_EnableIRQ(EXTI0_IRQn);
NVIC_EnableIRQ(EXTI1_IRQn);

/* ISR实现 */
void EXTI0_IRQHandler(void)
{
    // 检查中断标志
    if (EXTI->PR & (1 << 0))
    {
        // 处理GPIO中断事件
        // ...

        // 清除中断标志位(必须)
        EXTI->PR = (1 << 0);
    }
}
常见陷阱: 在ISR中执行耗时操作(如printf、长循环)会导致低优先级中断被长时间阻塞,甚至触发看门狗复位。ISR应遵循“快进快出”原则,仅设置标志位或传递数据,具体处理放在主循环中。