NVIC (中断控制器)
它是 STM32 中断系统的灵魂。如果说 CPU 是皇帝,NVIC 就是拥有最高权力的总管太监。
核心概念 :
- 嵌套 (Nested) :NVIC 可以处理多个中断,每个中断可以嵌套在另一个中断中。
- 向量 (Vectored) :每个中断都有一个唯一的向量地址,CPU 可以根据向量地址跳转到中断服务程序。
- 中断 (Interrupt) :外部设备触发的事件,需要 CPU 立即响应。
- 控制器 (Controller) :NVIC 负责管理中断,包括使能、失能、优先级设置等。
1. N - Nested (嵌套):能不能插队?
这是 NVIC 最强大的功能。
- 场景: 皇帝 (CPU) 正在批阅奏折(执行主程序)。
- 普通中断: 突然太监来报:“有人送水果来了(串口接收中断)”。皇帝停下笔,去吃水果。
- 嵌套中断: 就在皇帝吃水果的时候,太监又冲进来了:“不好啦!失火啦(看门狗/系统故障中断)!”
- 如果不支持嵌套: 皇帝会说:“没看见我在吃水果吗?等我吃完!” -> 结果:宫殿烧没了。
- NVIC 的做法: 皇帝立刻扔掉水果(保存当前中断现场),先去救火。救完火回来接着吃水果,吃完水果回去继续批奏折。
这就是嵌套: 高优先级的中断,可以打断正在执行的低优先级中断。
2. V - Vectored (向量):去哪办事?
为什么叫“向量”?这其实是一个数学/计算机术语,在这里你可以理解为**“精准的地址列表”**。
- 非向量中断 (老式单片机):
- 不管谁来了,CPU 都跳到同一个地方(比如
0x0004)。 - CPU 到了那里还得自己查:“是谁叫我?是定时器吗?还是串口?” -> 效率低。
- 不管谁来了,CPU 都跳到同一个地方(比如
- 向量中断 (NVIC):
- NVIC 手里有一张巨大的表格(中断向量表)。
- 表格里写得清清楚楚:
- EXTI0 来了 -> 请直接跳到
0x0000_0058(找EXTI0_IRQHandler)。 - TIM2 来了 -> 请直接跳到
0x0000_00B0(找TIM2_IRQHandler)。
- EXTI0 来了 -> 请直接跳到
- 结果: 速度极快,无需查询,直接瞬移到位。
3. I & C - Interrupt Controller (中断控制器)
这说明了它的身份。它不是外设(Peripheral),它是内核外设 (Core Peripheral)。
- 它长在 Cortex-M3 内核 里面,是 ARM 公司设计的,不是 ST 公司设计的。
- 所以你在配置 NVIC 时,引用的头文件通常是
misc.h或者core_cm3.h,而不是stm32f10x_gpio.h这种。
4. 核心难点:优先级 (Priority)
这是面试和实际开发中必定会问的问题。NVIC 把优先级分成了两类:抢占优先级 (Preemption) 和 响应优先级 (Sub)。
我们需要用一个**“医院急诊室”**的模型来理解:
A. 抢占优先级 (Preemption Priority) —— “决定能不能插队”
- 比喻: 这是一个病人病情的危急程度。
- 规则:
- 值越小,优先级越高。(0级最高,15级最低)。
- 高抢占的病人来了,医生必须立刻丢下正在看的低抢占病人,先救这个。这就是中断嵌套发生的唯一条件。
B. 响应优先级 (Sub Priority) —— “决定排队顺序”
- 比喻: 这是挂号的早晚(但在 NVIC 里,这也是个数字)。
- 规则:
- 只有当抢占优先级相同,且两个病人同时到达时,这个参数才有用。
- 高响应的病人排在前面,低响应的病人排在后面。
- 关键点: 高响应优先级的人,不能插队!如果医生正在看一个“低响应”的病人,你也得等着。
C. 举个栗子
| 角色 | 抢占优先级 (Preemption) | 响应优先级 (Sub) | 结果 |
|---|---|---|---|
| 病人 A | 1 | 0 | 正在就诊中... |
| 病人 B | 0(更高) | 3 | 直接把 A 推开,插队先看 B |
| 病人 C | 1(相同) | 0(相同) | 乖乖排队,等 A 看完 |
| 病人 D | 1(相同) | 0(但是比 C 晚来) | 排在 C 后面 |
5. 优先级分组 (Priority Grouping)
STM32 有一个很变态的设计:它只给了 4个 bit (二进制位) 的空间来存这两个优先级。
你需要配置 NVIC_PriorityGroupConfig 来决定这 4 个 bit 怎么分:
- Group_0: 0 bit 给抢占,4 bit 给响应。(此时没有任何中断能插队,大家全是按顺序来)。
- Group_2 (最常用): 2 bit 给抢占 (0~3),2 bit 给响应 (0~3)。
- Group_4: 4 bit 给抢占,0 bit 给响应。(此时全是插队狂魔,谁等级高谁就直接打断别人)。
总结
NVIC 就是 CPU 的贴身大管家。
- 它手里拿着一张地图(向量表),指引 CPU 该去执行哪个函数。
- 它手里拿着一本VIP名单(优先级):
- 抢占优先级高的人可以推门而入(中断嵌套)。
- 响应优先级高的人可以优先排队。
写代码时的建议:
整个工程中,最好只选择一种优先级分组方式(比如 NVIC_PriorityGroup_2),然后在 main 函数的最开头配置一次,之后就别改了,否则整个系统的中断逻辑会乱套。