这篇文章是对 Cortex-M3 内核中断系统 和 STM32F1 系列 NVIC(嵌套向量中断控制器) 的解析说明。我将从结构清晰、层次分明的角度,对 NVIC 中断优先级分组的概念和 STM32F103 的实际情况做一个系统性的总结与叙述。
参考资料:
STM32F1xx官方资料:《STM32中文参考手册V10》---- 第9章 中断和事件
附图:
为什么一定需要中断?
中断的本质是打破“顺序执行”的限制,使 CPU 能在关键事件发生时立即响应,从而实现多任务、高实时性和高效率运行。
如果没有中断会发生什么?
假设没有中断,CPU 想要获取外设状态(比如按键、串口、传感器数据),怎么办?
那我们只能使用轮询(Polling):
while (1) {if (UART_GetFlag() == 1) {// 接收到数据}
}
使用这种方式的缺点:
CPU效率低 一直忙等,浪费资源
实时性差 响应时间取决于轮询频率
多任务困难 轮询一个设备时,其他任务无法执行
数据易丢失 如果轮询间隔太长,可能错过事件而中断则具备解决这些问题的优势:
高实时性 外设事件立即响应
高效率 CPU 空闲时间可执行主任务
多任务协作 支持 RTOS、任务调度
异步处理 外设与主程序解耦
可靠性提升 不易丢数据、不依赖轮询频率
引入中断的优势: 中断机制允许 CPU “只在需要时被打断”,避免无效等待。
中断触发后:
- CPU 自动跳转到中断服务函数(ISR)
- ISR 执行完毕后自动返回原来任务
- 响应迅速,处理高效
几乎所有操作皆离不开中断:
按键响应 用户按键瞬间触发 EXTI 外部中断
串口通信 接收到数据立即处理 USART 中断
定时任务 每秒触发一次事件 TIM 定时器中断
CAN 总线 收到帧立即解析 CAN 中断
操作系统调度 多任务切换 SysTick 定时器中断
没有中断 | 有中断 |
---|---|
一切顺序执行 | 支持事件驱动 |
必须轮询外设 | 被动等待变主动响应 |
单任务运行 | 支持多任务调度 |
类比 | 你每分钟看一次手机有没有来电(轮询) 手机响了你立刻接听(中断) |
效率 | 浪费精力,不及时 高效、及时响应 |
中断机制是从串行思维 → 并发思维的转变,是现代计算系统的基石。
中断是嵌入式系统中不可或缺的机制,它让 CPU 不再“苦等”,而是“即来即办”,极大提升了系统的实时性、效率与响应能力。
一、Cortex-M3 内核支持的中断资源(理论上限)
项目 | 数量 |
---|---|
核心中断(系统异常) | 16 个(含 HardFault、SysTick、PendSV 等) |
外部中断(可屏蔽) | 最多 240 个 |
可编程中断优先级级别 | 256(8位) |
这表示 Cortex-M3 可以 支持 256 级中断优先级(理论),但 MCU 厂商会根据芯片实际资源进行裁剪。
二、STM32F103 实际中断资源(裁剪后)
项目 | STM32F103xx | STM32F107xx |
---|---|---|
内核中断 | 16 个 | 16 个 |
外部中断(可屏蔽) | 60 个 | 68 个 |
可用中断优先级位数 | 4 位(即 16 级) | 同上 |
总中断源数 | 16(系统) + 60(外部) = 76 | 84 |
STM32 只是用了 Cortex-M3 的一部分功能,比如只用了
4位中断优先级
而不是 8 位。
NVIC 优先级的两个概念
那么有几十个中断,怎么管理这么多的中断呢?于是,我们需要对NVIC中断优先级分组。
中断管理方法:首先,对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级值。
分组配置是在寄存器
SCB->AIRCR
中配置:
综上↓:
CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。
STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。
STM32有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级。
STM32F103系列上面,又只有60个可屏蔽中断(在107系列才有68个)
NVIC 中断优先级的两个维度:抢占优先级 & 响应优先级
- 抢占优先级(Preemption Priority)
- 控制中断是否能“打断”其他中断
- 数字越小,优先级越高
- 响应优先级 / 子优先级(Sub Priority)
- 控制多个中断“同时触发”时谁先执行
- 不影响中断嵌套
中断优先级比较规则总结:
1.高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
2.抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
3.抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
4.如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
中断优先级分组(Priority Group)
STM32 使用 AIRCR
寄存器 配置优先级分组,分组如下:
分组 | 抢占优先级位数 | 子优先级位数 | 描述 |
---|---|---|---|
Group 0 | 0 bit | 4 bit | 全子优先级,无嵌套 |
Group 1 | 1 bit | 3 bit | 最多两级嵌套 |
Group 2 | 2 bit | 2 bit | 推荐使用,嵌套+排序 |
Group 3 | 3 bit | 1 bit | 高嵌套,低排序 |
Group 4 | 4 bit | 0 bit | 全抢占优先级,满嵌套 |
设置方式:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 2位抢占 + 2位子优先级
这是中断优先级分组函数: void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}应用:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
举例分析强化理解
假定设置中断优先级组为2,然后设置中断3(RTC中断)的抢占优先级为2,响应优先级为1。 中断6(外部中断0)的抢占优先级为3,响应优先级为0。中断7(外部中断1)的抢占优先级为2,响应优先级为0。
- 设置分组2(2位抢占 + 2位响应)
- 中断配置如下:
中断号 | 中断类型 | 抢占优先级 | 响应优先级 |
---|---|---|---|
中断3 | RTC中断 | 2 | 1 |
中断6 | 外部中断0(EXTI0 |