STM32 中的嵌套向量中断控制器(NVIC)详解

首先明确:

抢占优先级决定"能不能打断";响应优先级决定"同时等待时谁先执行"。

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

可以得出:

  1. USART1 能打断 TIM2,因为 1 < 2
  2. EXTI0 也能打断 TIM2
  3. USART1EXTI0 抢占优先级相同,不能互相打断。
  4. 当二者同时等待时,EXTI0 的响应优先级为 0,因此先于 USART1 执行。
  5. 如果 USART1 已经进入中断服务函数,随后 EXTI0 到来,EXTI0 不能仅凭响应优先级打断 USART1。

一句话记忆

抢占优先级不同:看谁能打断谁。

抢占优先级相同:不能互相打断。

同时处于等待状态:再比较响应优先级。

两者都相同:通常由中断号较小者先响应。

所有优先级都是数值越小越高。