问题
两个中断同时触发,谁先执行?高优先级中断在执行中,来了个低优先级中断,会打断吗?
这些问题取决于NVIC 优先级分组。
优先级分组
Cortex-M4 架构最多支持 8 位(256 级)优先级,STM32F407 厂商实现裁剪为 4 位(16 级)。这 4 bit 可以拆分成抢占优先级和子优先级两部分:
// HAL 库函数 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); // 常用
| 分组 | 抢占位数 | 子优先级位数 | 抢占级数 | 子优先级级数 |
|---|---|---|---|---|
| GROUP_0 | 0 | 4 | 1 | 16 |
| GROUP_1 | 1 | 3 | 2 | 8 |
| GROUP_2 | 2 | 2 | 4 | 4 |
| GROUP_3 | 3 | 1 | 8 | 2 |
| GROUP_4 | 4 | 0 | 16 | 1 |
GROUP_4 = 4 bit 全是抢占优先级,没有子优先级——这是最常用的。
设置中断优先级
// 在 main 初始化中设置 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); // 设置 USART1 优先级 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); // 最高优先级 // 设置 TIM2 优先级 HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0); // 次高 // 设置 EXTI0 优先级 HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0); // 第三 // 使能中断 HAL_NVIC_EnableIRQ(USART1_IRQn); HAL_NVIC_EnableIRQ(TIM2_IRQn); HAL_NVIC_EnableIRQ(EXTI0_IRQn);
数字越小优先级越高。
打断规则
| 场景 | 会打断吗 |
|---|---|
| USART1(优先级 0)来了,CPU 在执行 main | ✅ 立即响应 |
| USART1(优先级 0)执行中,TIM2(优先级 1)来了 | ❌ 不会打断,等 USART1 处理完 |
| TIM2(优先级 1)执行中,USART1(优先级 0)来了 | ✅ USART1 优先级更高,会打断 TIM2 |
| USART1(优先级 0)执行中,EXTI0(优先级 2)来了 | ❌ 不会,EXTI0 优先级更低 |
| TIM2 和 EXTI0 同时触发 | TIM2(优先级 1 vs 2)先执行,完了再执行 EXTI0 |
SysTick 的优先级
SysTick 的中断优先级不在 NVIC_SetPriority 管理,需要单独设:
HAL_InitTick(TICK_INT_PRIORITY); // TICK_INT_PRIORITY 由 CubeMX 在 main.h 中自动生成;默认是 15(最低)
默认 SysTick 优先级是 15(最低),所以任何中断都能打断它——这也是为什么中断里调 HAL_Delay 会死锁(参考另一篇文章)。
常见配置建议
| 中断 | 建议优先级 | 理由 |
|---|---|---|
| SysTick | 15(最低) | 默认值,Tick 被延迟一会无所谓 |
| USART(接收) | 0~1 | 接收不能丢,优先级高点 |
| SPI/DMA | 1~2 | 传数据不能被打断太久 |
| TIM 定时器 | 2~3 | 一般任务 |
| EXTI(按键) | 3~4 | 消抖就不急着处理 |
| I2C | 0~1 | I2C 有超时,容易被时序问题卡死 |
常见错误
// ❌ CubeMX 里改了分组但代码没调 HAL_NVIC_SetPriorityGrouping // MX_NVIC_Init() 中的分组值取决于 CubeMX NVIC 配置界面的 Priority Group 下拉选择,非硬编码 // 如果你手动改了 CubeMX 的分组,确认代码里同步 // ❌ 设了优先级忘了 EnableIRQ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); // 忘了这一行 ↓ HAL_NVIC_EnableIRQ(USART1_IRQn);
总结
99% 的情况用GROUP_4(4 bit 全给抢占优先级)
数字越小越优先
高优先级可以打断低优先级
SysTick 最末位(优先级 15)