首先明确:
抢占优先级决定"能不能打断";响应优先级决定"同时等待时谁先执行"。
1. NVIC 是什么
NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)负责:
- 开启、关闭中断
- 保存中断的挂起状态
- 判断多个中断的执行顺序
- 实现中断嵌套
- 根据中断号找到对应的中断服务函数
所谓"嵌套",就是 CPU 正在执行一个中断服务函数时,可以被更高抢占优先级的中断打断。
2. STM32 的优先级数字越小,等级越高
优先级数值 0 > 优先级数值 1 > 优先级数值 2 ...
这里的 > 表示"实际优先级更高"。
例如:
c
中断A:抢占优先级 = 0
中断B:抢占优先级 = 2
A 的优先级高于 B。B 执行过程中,A 可以打断 B。
3. NVIC的 4 位优先级
很多 STM32 芯片实际实现了 4 个优先级位,因此一共有:2\^4=16
个编码值,也就是 0~15。
这 4 位可以切分成两部分:
text
4个优先级位 = 抢占优先级位 + 响应优先级位
分成五种模式:
| 分组 | 抢占优先级位数 | 抢占值范围 | 响应优先级位数 | 响应值范围 |
|---|---|---|---|---|
| 分组0 | 0位 | 只能为0 | 4位 | 0~15 |
| 分组1 | 1位 | 0~1 | 3位 | 0~7 |
| 分组2 | 2位 | 0~3 | 2位 | 0~3 |
| 分组3 | 3位 | 0~7 | 1位 | 0~1 |
| 分组4 | 4位 | 0~15 | 0位 | 只能为0 |
这里的 4 位不是说每个中断都有两个独立的 4 位字段,而是说:
总共只有 4 位,需要在抢占优先级和响应优先级之间分配。
4. 抢占优先级:决定能否发生中断嵌套
假设:
text
中断A:抢占优先级 1
中断B:抢占优先级 2
由于数值越小优先级越高,因此 A 的抢占优先级高于 B。
如果 CPU 正在执行 B,此时 A 到来:
text
执行B → A到来 → 暂停B → 执行A → A结束 → 继续执行B
这就是中断嵌套。
反过来,如果正在执行 A,B 到来,B 不能打断 A,只能进入挂起状态,等 A 执行完再处理。
重要规则
只有抢占优先级不同,才可能发生嵌套。
响应优先级再高,也不能打断正在执行的中断。
5. 响应优先级:决定挂起中断的先后顺序
响应优先级也常被称为:
- 子优先级
- SubPriority
- 次优先级
假设两个中断的抢占优先级相同:
text
中断A:抢占优先级 1,响应优先级 0
中断B:抢占优先级 1,响应优先级 2
如果 CPU 正在执行主程序,并且 A、B 几乎同时进入挂起状态,那么响应优先级更高的 A 先执行。
text
A先执行 → A结束 → B执行
但如果 B 已经开始执行,这时 A 才到来,A通常不能打断 B,因为二者抢占优先级相同。
也就是说:
响应优先级只负责"排队",不负责"抢占"。
6. 如果抢占优先级和响应优先级都相同
抢占优先级和响应优先级均相同的,按中断号排队。
此时由异常号/IRQ 编号进行最终裁决,通常中断号较小者优先。
例如两个中断的配置完全相同:
text
EXTI0_IRQn = 6
TIM2_IRQn = 28
如果二者同时挂起,一般 EXTI0_IRQn 对应的异常编号更小,因此会先得到响应。
不过实际程序不应过度依赖这一条,最好通过合理设置优先级明确执行次序。
7. 五种分组分别适合什么情况
分组0:没有中断嵌套
text
抢占优先级:无
响应优先级:0~15
所有外部中断的抢占等级都相同,因此外部中断之间不能相互抢占,只能排队执行。
适合:
- 不希望出现中断嵌套
- 系统结构简单
- 通过响应优先级安排执行次序
分组1
text
抢占优先级:0~1
响应优先级:0~7
只有两个抢占等级,但每个等级内部可以进行较细的排序。
适合嵌套层数较少、同级中断较多的系统。
分组2
text
抢占优先级:0~3
响应优先级:0~3
抢占能力和排队能力比较均衡,是常见选择之一。
分组3
text
抢占优先级:0~7
响应优先级:0~1
可以划分较多抢占等级,但同一抢占等级下只有两个响应等级。
分组4:全部用于抢占
text
抢占优先级:0~15
响应优先级:无
可以设置很多抢占层级,但没有可配置的响应优先级。
适合更强调中断嵌套层次的系统。
8. 分组2实例
假设系统采用分组2:
c
NVIC_PRIORITYGROUP_2
此时:
text
抢占优先级范围:0~3
响应优先级范围:0~3
配置三个中断:
| 中断 | 抢占优先级 | 响应优先级 |
|---|---|---|
| USART1 | 1 | 2 |
| TIM2 | 2 | 0 |
| EXTI0 | 1 | 0 |
可以得出:
USART1能打断TIM2,因为1 < 2。EXTI0也能打断TIM2。USART1与EXTI0抢占优先级相同,不能互相打断。- 当二者同时等待时,
EXTI0的响应优先级为 0,因此先于USART1执行。 - 如果
USART1已经进入中断服务函数,随后EXTI0到来,EXTI0不能仅凭响应优先级打断 USART1。
一句话记忆
抢占优先级不同:看谁能打断谁。
抢占优先级相同:不能互相打断。
同时处于等待状态:再比较响应优先级。
两者都相同:通常由中断号较小者先响应。
所有优先级都是数值越小越高。