核心概念:当多个中断同时发生,或者一个中断正在处理时又来了一个新中断,CPU 该听谁的?
在 ARM Cortex-M 内核中,管理这一切的大管家叫 NVIC (Nested Vectored Interrupt Controller) ,中文直译为"嵌套向量中断控制器"。它的逻辑非常像医院的急诊室分诊台。
1. 法则:抢占 vs 响应
这是新手最容易晕的地方。STM32/Cortex-M 把优先级分成了两个维度:抢占优先级 (Preemption Priority) 和 响应优先级 (Sub Priority)。
我们要死死记住这两条法则:
-
法则一(抢占):只有"抢占优先级"高的人,才能打断正在干活的人。
- 比喻 :医生正在给普通病人(抢占低)包扎,突然送来一个心脏停跳的病人(抢占高)。医生必须立马停下手中的活,先救心脏停跳的。这就叫中断嵌套。
-
法则二(响应):如果"抢占优先级"相同,不管后面那个多急,都不能打断。
-
比喻 :医生正在抢救一个心脏停跳的(抢占高),这时候送来一个大出血的(抢占也高,且相等)。虽然大出血也很急,但既然已经在救心脏了,大出血的只能在门口排队,等医生救完心脏这个再进来。
-
那"响应优先级"有啥用? 它只决定排队的顺序。如果门口同时送来了两个病人,医生做完手头的事出门一看,谁的"响应优先级"高,就先救谁。
-
2. 这里的"高"其实是"低"
这是一个反直觉的设定:数字越小,优先级越高。
-
0是最高优先级(皇上)。 -
15是低优先级(平民)。
新手大坑 :很多开发者忘记配置优先级,默认全是
0。这意味着所有中断都是最高级,且谁也打断不了谁(因为级别一样),完全退化成了单任务排队系统。
3. 优先级分组 (Priority Grouping)
CPU 里的优先级寄存器通常只有 4 个 bit (不同型号略有差异)。我们需要把这 4 个 bit 切分成两部分,一部分给"抢占",一部分给"响应"。
这就是 NVIC_PriorityGroupConfig 的作用。常见的 5 种分组(以 STM32 为例):
| 分组 (Group) | 抢占位 (Preemption) | 响应位 (Sub) | 描述 | 适用场景 |
|---|---|---|---|---|
| NVIC_PriorityGroup_0 | 0 bit (0级) | 4 bit (16级) | 无嵌套。所有中断按顺序排队。 | 简单逻辑,不想处理复杂的嵌套并发问题。 |
| NVIC_PriorityGroup_1 | 1 bit (2级) | 3 bit (8级) | 只有 2 层嵌套关系。 | |
| NVIC_PriorityGroup_2 | 2 bit (4级) | 2 bit (4级) | 推荐平衡配置。4 层嵌套,同级内 4 个排队位。 | 大多数通用工程。 |
| NVIC_PriorityGroup_3 | 3 bit (8级) | 1 bit (2级) | ||
| NVIC_PriorityGroup_4 | 4 bit (16级) | 0 bit (0级) | 全抢占。只要级别高 1 级就能打断。 | 实时性要求极高的系统 (如电机控制)。 |
工程建议 :在一个项目中,只在初始化时设定一次分组,千万不要在程序运行中途改来改去,否则整个中断逻辑会瞬间崩塌。
4. 真实场景推演
假设我们将系统配置为 Group 2(2位抢占,2位响应)。
-
中断 A:抢占 2,响应 0
-
中断 B:抢占 2,响应 1
-
中断 C:抢占 1,响应 0 (它是最急的,数字最小)
场景一:B 正在运行,A 来了。
-
结果:B 继续运行,A 等待。
-
原因 :虽然 A 的响应优先级 (0) 比 B (1) 高,但通过法则二 ,他们的抢占优先级都是 2。平级不可打断。
场景二:B 正在运行,C 来了。
-
结果:B 暂停(压栈保护现场),C 立即执行。C 执行完后,B 恢复运行。
-
原因 :C 的抢占优先级 (1) 小于 B (2),也就是 C 级别更高。符合法则一,发生嵌套。
场景三:A 和 B 同时到来。
-
结果:CPU 先执行 A。
-
原因:抢占一样,这时看响应优先级。A (0) < B (1),A 胜出。
5. 为什么要尽量避免复杂的嵌套?
初学者可能会觉得:"嵌套好啊,反应快!"
但老手都知道,中断嵌套是 Bug 的温床。
-
堆栈溢出 (Stack Overflow):每嵌套一层,就要多压一次栈(32字节以上)。如果嵌套层数太多,MSP 堆栈可能瞬间被打爆,导致程序跑飞。
-
临界区竞争:如果低优先级中断正在改一个全局变量,高优先级中断插进来也改这个变量,数据就坏了。(这就是下一期的主题)。
总结下关键点:
-
抢占 (Preemption) 决定能不能打断别人。
-
响应 (Sub) 决定能不能插队。
-
数字越小 ,优先级越高。
-
工程开始时选定一个优先级分组,然后别动它。