
核心要点速览
两级优先级:抢占优先级(可嵌套)+ 响应优先级(同级别排序)
数值越小优先级越高:这是最容易记反的地方
5种分组:分组0到分组4,分配抢占位和响应位的比例不同
全局唯一:整个系统只能设一种分组,不能不同外设用不同分组
优先级范围:STM32F1系列使用4位优先级,数值0到15
面试题
STM32的中断优先级你了解吗?讲一讲抢占优先级和响应优先级的区别,以及优先级分组怎么配置。
面试官考察点
这道题考察的是你对STM32中断系统的理解深度。很多人用了很久STM32也没搞清楚抢占优先级和响应优先级到底有什么区别,只是照着例程配置。面试官想知道你是否真的理解NVIC的工作机制,以及你在实际项目中是怎么规划中断优先级的。
回答思路
STM32的每个外部中断都有4位优先级寄存器,这4位被分成两部分:
抢占优先级(Preempt Priority):决定能不能打断正在执行的中断。高抢占优先级的中断可以打断低抢占优先级的中断,形成中断嵌套。这是最核心的一级。
响应优先级(Sub Priority / 子优先级):决定同抢占优先级下的响应顺序。如果两个中断的抢占优先级相同,它们之间不能互相嵌套,但同时触发时响应优先级高的先执行。
关键原则:优先级的数值越小,优先级越高。比如抢占优先级0比抢占优先级1更高。这一点很多人容易说反,一定要记清楚。
4位优先级怎么分配给抢占和响应,是由优先级分组决定的。分组通过SCB->AIRCR寄存器的PRIGROUP位来设置。STM32一共有5种分组方式:
| 优先级分组 | 抢占优先级位数 | 响应优先级位数 | 抢占优先级范围 | 响应优先级范围 |
|---|---|---|---|---|
| 分组0 | 0位 | 4位 | 0级(无嵌套) | 0到15 |
| 分组1 | 1位 | 3位 | 0到1 | 0到7 |
| 分组2 | 2位 | 2位 | 0到3 | 0到3 |
| 分组3 | 3位 | 1位 | 0到7 | 0到1 |
| 分组4 | 4位 | 0位 | 0到15 | 0级(无响应级) |
最常用的是分组2和分组4。分组2有4级抢占+4级响应,兼顾嵌套和排序;分组4有16级抢占但没有响应优先级,适合需要精细控制中断嵌套的场景。
配置中断优先级的步骤:
系统初始化时调用NVIC_PriorityGroupConfig()设置优先级分组,整个系统只能设置一次
对每个外设中断,调用NVIC_Init()或直接写寄存器设置抢占优先级和响应优先级
使能对应的中断通道
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置EXTI0中断:抢占优先级1,响应优先级2
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
重要注意:优先级分组是全局的,所有中断共用同一个分组设置。不能说串口用分组2,定时器用分组4,这是不行的。所以在项目设计阶段就要规划好用哪个分组。
在实际项目中规划中断优先级,可以参考这些原则:
系统滴答定时器(SysTick)通常设为较低的抢占优先级,不影响实时性更高的中断
通信接口(USB、CAN)根据实时性要求设为中高优先级
定时器中断用于精确采样或控制时,设为较高优先级
外部按键中断可以设为较低优先级,避免频繁打断关键任务
特别重要的紧急中断(如过流保护、故障检测)设为最高抢占优先级
举个例子:我之前做的一个电机控制项目,用的是分组2。电流采样中断设为抢占优先级0(最高),保证采样时序准确;PWM中断和编码器中断设为抢占优先级1;串口通信设为抢占优先级2;按键和一些状态检测设为抢占优先级3。这样既保证了控制环路的实时性,又不会让通信和按键打断核心控制逻辑。
面试官追问
追问1:中断优先级分组为什么只能设一次?设错了会怎么样?
因为优先级分组是通过SCB->AIRCR寄存器的PRIGROUP位来配置的,这个寄存器是全局的,所有中断通道共用同一个分组设置。如果你在不同地方设置了不同的分组,后设置的会覆盖先设置的,导致前面配置的中断优先级不符合预期。比如你先设了分组4配置了一堆中断,后来某个驱动又设成了分组2,那么之前中断的抢占优先级和响应优先级的位分配就全变了,优先级关系会乱掉。所以规范做法是在系统初始化最开始的时候设置一次,后面就不要再动了。
追问2:同优先级的两个中断同时触发,会怎么处理?
分两种情况。第一种是抢占优先级相同但响应优先级不同,同时触发时响应优先级高的先执行,执行完了再执行响应优先级低的,它们之间不会互相嵌套。第二种是抢占优先级和响应优先级都相同,同时触发时,按照中断向量表中的排序来决定先后,编号小的中断先执行。比如EXTI0_IRQn和EXTI1_IRQn如果优先级完全相同,EXTI0的编号小,会先响应。
追问3:中断服务函数里能做哪些事,不能做哪些事?
中断服务函数的原则是越短越好,快进快出。可以做的事情包括:读取标志位、清除中断标志、读写寄存器、给全局变量赋值、触发信号量或消息队列等轻量操作。不适合做的事情包括:长时间的计算、延时函数(尤其是操作系统的延时)、调用不可重入的函数、使用printf等耗时的串口输出、动态内存分配。中断服务函数里如果处理事情太多,会影响其他中断的响应,严重的还会导致系统卡死。
追问4:你遇到过中断优先级相关的bug吗?怎么解决的?
可以说一个真实或典型的案例:有一次我做的项目里,串口接收中断和定时器中断都是同一个抢占优先级,串口接收数据量大的时候,串口中断处理时间变长,导致定时器中断被推迟,PWM输出的周期抖动变大。后来我把定时器中断的抢占优先级调高一级,让它可以打断串口中断,问题就解决了。这个经历让我认识到中断优先级规划不是随便设的,要根据实时性需求认真排优先级。
失分表达
常见失分回答
"优先级数值越大越高" —— 说反了,这是最基础的概念错误
"抢占优先级和响应优先级差不多吧" —— 差不多就是没搞懂,直接减分
"分组随便选一个就行" —— 说明你没有根据项目需求做规划
"我都是从库函数里直接复制的,没太关注这个" —— 等于告诉面试官你只会调库不会思考
准备动作
找一份STM32参考手册的NVIC章节,系统看一遍优先级相关的寄存器描述
亲手写代码验证:两个不同优先级的中断,高优先级能不能打断低优先级
整理你做过的项目里中断优先级的分配表,讲清楚为什么这么分配
了解一下Cortex-M内核异常优先级的概念(Reset、NMI、HardFault等不可屏蔽的异常)
了解中断优先级和FreeRTOS任务优先级的区别,这两个是不同的东西,不要混淆
核心关键词
STM32、NVIC、中断优先级、抢占优先级、响应优先级、优先级分组、中断嵌套、AIRCR寄存器、嵌入式面试

扫码关注




























