一、中断基础概念:什么是中断、中断向量、中断优先级、中断嵌套
大家好,我是你们的老朋友。今天咱们来聊聊中断——这个嵌入式世界里最基础、也最容易被忽视的概念。
说实话,我刚开始做嵌入式那会儿,对中断的理解就是「有个事情来了,CPU 停下手里的活去处理」。嗯,这个说法没错,但太粗糙了。你想想看,如果中断只是这么简单,那为什么还会有中断向量、优先级、嵌套这些乱七八糟的东西?
咱们一个一个来拆。
1.1 什么是中断
中断,说白了就是 CPU 在执行主程序的时候,突然被一个外部或内部的事件打断了。CPU 得先把手头的工作保存好,然后跳去处理这个突发事件,处理完了再回来接着干。
我习惯把中断比作你正在写代码,突然有人敲门——你得先保存当前编辑的文件(保存现场),然后去开门(处理中断),处理完再回来继续写(恢复现场)。
中断的来源有很多:
- 外部中断:比如按键按下、GPIO 电平变化
- 内部中断:比如定时器溢出、DMA 传输完成
- 软件中断:程序自己触发的,比如系统调用
1.2 中断向量
中断向量是什么?其实就是一张表,里面存着每个中断对应的处理函数的地址。
CPU 收到中断信号后,会去查这张表,找到对应的入口地址,然后跳过去执行。这张表就叫「中断向量表」。
举个例子,ARM Cortex-M 系列的中断向量表长这样:
; 中断向量表示例(简化版)
0x00000000: 栈顶指针
0x00000004: Reset_Handler ; 复位中断
0x00000008: NMI_Handler ; 不可屏蔽中断
0x0000000C: HardFault_Handler ; 硬件错误中断
0x00000010: MemManage_Handler ; 内存管理中断
0x00000014: BusFault_Handler ; 总线错误中断
0x00000018: UsageFault_Handler ; 用法错误中断
...
0x00000040: TIM2_IRQHandler ; 定时器2中断
0x00000044: TIM3_IRQHandler ; 定时器3中断
每个中断都有一个固定的向量号,CPU 根据这个号去查表。比如定时器2中断来了,CPU 就去查向量号对应的位置,拿到 TIM2_IRQHandler 的地址,然后跳过去。
1.3 中断优先级
如果两个中断同时来了怎么办?谁先处理?这就涉及到中断优先级了。
优先级高的中断会先被处理。优先级低的?等着吧。
不同芯片的优先级管理方式不一样:
| 芯片架构 | 优先级位数 | 优先级范围 | 特点 |
|---|---|---|---|
| ARM Cortex-M0/M0+ | 2位 | 0-3 | 数值越小优先级越高 |
| ARM Cortex-M3/M4 | 8位(实际使用高4位) | 0-15 | 支持抢占优先级和子优先级 |
| RISC-V | 可配置 | 取决于实现 | 通常支持抢占式优先级 |
| x86 APIC | 8位 | 0-255 | 数值越大优先级越高 |
这里有个容易搞混的地方:有些芯片是数值越小优先级越高(比如 ARM),有些是数值越大优先级越高(比如 x86)。我刚开始做 ARM 开发时,就因为这个搞反过,导致高优先级中断一直抢不过低优先级的,排查了半天。
1.4 中断嵌套
中断嵌套,就是中断里面又来了中断。
比如你在处理定时器中断的时候,突然来了一个更高优先级的串口中断。这时候 CPU 会怎么做?
答案是:如果新来的中断优先级更高,CPU 会暂停当前的中断处理,先去处理更高优先级的那个。等处理完了,再回来继续处理原来的中断。
这个过程就叫「中断嵌套」。
但要注意,不是所有中断都能嵌套。能不能嵌套取决于:
- 优先级设置:只有更高优先级的中断才能抢占当前中断
- 中断屏蔽位:有些中断处理函数里会关全局中断,这时候任何中断都进不来
- 硬件设计:有些老旧的 CPU 不支持中断嵌套,处理中断时会自动关中断
我举个例子,假设有三个中断:
中断A:优先级 1(最高)
中断B:优先级 2
中断C:优先级 3(最低)
时间轴:
1. CPU 正在执行主程序
2. 中断C 来了 → CPU 去处理中断C
3. 处理中断C 的过程中,中断B 来了(优先级更高)
→ CPU 暂停中断C,保存现场,去处理中断B
4. 处理中断B 的过程中,中断A 来了(优先级最高)
→ CPU 暂停中断B,保存现场,去处理中断A
5. 中断A 处理完 → 恢复中断B 的现场,继续处理中断B
6. 中断B 处理完 → 恢复中断C 的现场,继续处理中断C
7. 中断C 处理完 → 回到主程序
这就是典型的三层嵌套。你想想看,如果嵌套层数太多,栈空间会急剧增加。我见过一个项目,中断嵌套了 5 层,结果栈溢出导致系统崩溃。嗯,从那以后我设计中断时都会严格控制嵌套深度。
1.5 小结
好了,咱们把中断的基础概念捋了一遍:
- 中断:CPU 被突发事件打断,处理完再回来
- 中断向量:一张表,存着每个中断的处理函数地址
- 中断优先级:决定哪个中断先被处理
- 中断嵌套:高优先级中断可以打断低优先级中断
这些概念看着简单,但实际项目中踩坑的不少。我建议你动手写个简单的中断程序,比如用定时器中断点个灯,再试试嵌套的效果。纸上得来终觉浅,绝知此事要躬行嘛。
下一章咱们聊聊 USB 的中断处理机制,那又是另一番天地了。