3. 中断优先级概念:抢占优先级与子优先级的定义、优先级分组的概念
在 ARM Cortex-M 系列 MCU 中,NVIC(嵌套向量中断控制器)支持多级中断优先级管理。理解“抢占优先级”与“子优先级”的区别,以及“优先级分组”的配置机制,是正确设计中断嵌套逻辑的基础。本节将系统阐述这两个核心概念及其在 NVIC 中的实现方式。
3.1 抢占优先级(Preempt Priority)
抢占优先级决定了中断是否能够打断当前正在执行的中断服务程序(ISR)。当两个中断同时发生时,抢占优先级更高的中断会优先执行;如果高抢占优先级的中断在低优先级中断执行期间触发,则会发生中断嵌套——当前 ISR 被暂停,高优先级 ISR 开始执行,待其完成后恢复被暂停的 ISR。
- 数值越小,优先级越高:在 NVIC 中,优先级数值与优先级等级成反比。例如,抢占优先级数值为 0 的中断优先级最高,数值为 3 的中断优先级最低。
- 嵌套触发条件:只有抢占优先级更高的中断才能打断当前 ISR。相同抢占优先级的中断之间不会发生嵌套。
- 应用场景:实时性要求极高的任务(如定时器溢出、外部紧急事件)应分配较高的抢占优先级。
3.2 子优先级(Subpriority)
子优先级用于在同一抢占优先级组内,进一步区分中断的响应顺序。当两个中断具有相同的抢占优先级时,子优先级数值较小的中断会优先执行。但子优先级不会触发中断嵌套——即相同抢占优先级的中断之间不会相互打断。
- 仅用于仲裁:子优先级只在多个同抢占优先级中断同时挂起时,决定哪个先被响应。
- 无嵌套能力:即使子优先级不同,只要抢占优先级相同,当前 ISR 不会被另一个同组中断打断。
- 典型用途:在多个外设中断共享同一抢占优先级时,通过子优先级区分处理的紧急程度。
3.3 优先级分组(Priority Grouping)
优先级分组是 NVIC 提供的一种灵活机制,允许开发者将中断优先级寄存器中的位域划分为抢占优先级位和子优先级位。Cortex-M3/M4/M7 等内核使用 8 位优先级寄存器(实际有效位数由芯片厂商决定),通过 SCB->AIRCR 寄存器的 PRIGROUP 字段配置分组方式。
下表列出了常见的优先级分组配置(以 8 位寄存器为例,实际有效位数为 4 位时同理):
| PRIGROUP 值 | 抢占优先级位数 | 子优先级位数 | 抢占优先级等级数 | 子优先级等级数 | 总优先级等级数 |
|---|---|---|---|---|---|
| 0 | 8 | 0 | 256 | 1 | 256 |
| 1 | 7 | 1 | 128 | 2 | 256 |
| 2 | 6 | 2 | 64 | 4 | 256 |
| 3 | 5 | 3 | 32 | 8 | 256 |
| 4 | 4 | 4 | 16 | 16 | 256 |
| 5 | 3 | 5 | 8 | 32 | 256 |
| 6 | 2 | 6 | 4 | 64 | 256 |
| 7 | 1 | 7 | 2 | 128 | 256 |
3.4 优先级分组与中断嵌套的关系
优先级分组直接决定了系统中中断嵌套的深度和灵活性。以下 SVG 图展示了不同分组配置下,中断嵌套的层级结构:
3.5 优先级分组配置示例(STM32)
在 STM32 标准库或 HAL 库中,优先级分组通过 NVIC_PriorityGroupConfig() 函数配置。以下代码展示了如何设置分组并初始化中断优先级:
/* 配置优先级分组:抢占优先级 4 位,子优先级 0 位(即 16 级抢占,无子优先级) */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/* 配置 USART1 中断:抢占优先级 2,子优先级 0 */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 配置 TIM2 中断:抢占优先级 1,子优先级 0(优先级高于 USART1) */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
3.6 优先级分组选择策略
在实际项目中,选择优先级分组需要权衡嵌套深度与同组仲裁粒度。以下表格总结了不同场景下的推荐分组:
| 应用场景 | 推荐分组 | 抢占优先级等级数 | 子优先级等级数 | 理由 |
|---|---|---|---|---|
| 强实时控制(如电机驱动) | PRIGROUP=3(4 位有效) | 8 | 2 | 需要多层嵌套,同时保留子优先级区分同组外设 |
| 大量外设中断(如传感器阵列) | PRIGROUP=5(4 位有效) | 2 | 8 | 抢占层级少,但同组内可精细仲裁多个外设 |
| 简单系统(如 LED 控制) | PRIGROUP=7(4 位有效) | 1 | 16 | 无嵌套需求,所有中断同优先级,仅靠子优先级排序 |
| 混合实时系统(如工业通信) | PRIGROUP=4(4 位有效) | 4 | 4 | 平衡嵌套深度与仲裁粒度,适用性最广 |
3.7 中断优先级配置流程图
以下 SVG 流程图总结了中断优先级配置的完整步骤:
3.8 常见问题与避坑指南
- 分组配置后不可更改:一旦调用分组配置函数,所有中断优先级的位域解释方式即固定。中途更改会导致已配置的优先级数值含义错乱。
- 有效位数因芯片而异:STM32F0 使用 2 位有效优先级(4 级),STM32F1/F4 使用 4 位(16 级),STM32H7 使用 8 位(256 级)。务必查阅芯片参考手册。
- 子优先级不产生嵌套:即使子优先级不同,相同抢占优先级的中断之间不会打断。如果需要嵌套,必须分配不同的抢占优先级。
- 优先级数值不要超过有效范围:例如在 4 位有效系统中,抢占优先级最大值为 15(0~15),子优先级最大值为 15。超出部分会被硬件截断。
“抢占定嵌套,子优先定顺序;数值越小越优先,分组一次定终身。”