什么是 NVIC?
NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器) 适用于 Cortex-M0、M3、M4、M7 等 ARM 处理器,广泛用于 STM32、ESP32、GD32、NXP 等 MCU 中,它用于管理和控制中断,是 ARM Cortex-M 系列微控制器 的核心外设之一。NVIC 负责中断优先级管理、嵌套中断处理和中断向量跳转,使 Cortex-M 处理器能够高效地响应中断请求。
NVIC 主要功能1. 支持多个中断源(STM32F103 系列最多支持 60 个)2. 支持中断优先级管理(可配置 8~256 级优先级)3. 支持中断嵌套(高优先级中断可打断低优先级中断)4. 支持向量表偏移(Vector Table Offset Register, VTOR)5. 支持低功耗中断唤醒(Wake-up Interrupt Controller, WIC)6. 支持中断屏蔽、清除、挂起和使能
NVIC 与 Cortex-M 处理器紧密集成,能够 `直接与 CPU 交互`,实现高效的中断处理机制:NVIC 负责中断管理,Cortex-M3/M4 使用 NVIC 进行中断分配,支持快速中断响应(低延迟),支持 Tail-Chaining(尾链接优化),减少中断切换开销。
📌 NVIC 架构示意图:
+-----------------------------------+| Cortex-M 内核 |+-----------------------------------+| NVIC 控制器 || - 中断向量表 (Vector Table) || - 优先级寄存器 (IPR) || - 使能寄存器 (ISER) || - 清除寄存器 (ICER) || - 挂起寄存器 (ISPR / ICPR) || - 系统控制寄存器 (AIRCR) |+-----------------------------------+| 外设(UART, GPIO, TIM) |+-----------------------------------+
NVIC 寄存器
在 STM32F103 及其他 Cortex-M 系列 MCU 中,NVIC 主要通过以下寄存器进行控制:
寄存器 | 作用 |
---|---|
ISER(中断使能寄存器) | 设置某个中断为“使能”状态 |
ICER(中断清除寄存器) | 关闭某个中断 |
ISPR(中断挂起寄存器) | 设置某个中断为“挂起”状态(软件触发) |
ICPR(中断清除挂起寄存器) | 取消某个中断的挂起状态 |
IABR(中断激活状态寄存器) | 读取当前激活的中断 |
IPR(中断优先级寄存器) | 设置中断优先级 |
STIR(软件触发中断寄存器) | 手动触发一个中断(仅限 Cortex-M3/M4) |
NVIC 中断优先级管理
⭐ 1. 中断优先级划分
NVIC 采用 8 位优先级字段,在不同的 STM32 设备中,实际使用的优先级位数可能不同:
- NVIC 采用 分组优先级(Group Priority)+ 子优先级(Sub Priority) 机制:
- 分组优先级(Preempt Priority):决定中断是否可以抢占其他中断。
- 子优先级(Sub Priority):当多个相同分组优先级的中断发生时,决定处理顺序。
📌 优先级编码格式(STM32F103,4-bit):
| 4-bit 优先级字段 | |
|-----------------|
| Preemption(4) | Sub(0) |
- 数值越小,优先级越高(0 最高,255 最低)。
- 抢占优先级高的中断可以中断低优先级的中断。
⭐ 2. NVIC 优先级配置示例
使用 CMSIS(Cortex Microcontroller Software Interface Standard) 提供的函数可以轻松配置 NVIC:
#include "stm32f10x.h"// 配置中断优先级
void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 选择 USART1 中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级 1(数值小,优先级高)NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级 1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断NVIC_Init(&NVIC_InitStructure);
}// USART1_IRQn:定义要配置的中断源
// NVIC_IRQChannelPreemptionPriority:设置抢占优先级
// NVIC_IRQChannelSubPriority:设置子优先级
// NVIC_IRQChannelCmd:使能该中断
示例二:Cortex-M 配置优先级:
void NVIC_SetPriority_Config(void) {NVIC_SetPriorityGrouping(2); // 2 位抢占,2 位子优先级NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(2, 1, 1));
}
⭐ 3. NVIC 优先级分组
通过 SCB->AIRCR 配置 优先级分组:
分组模式 | 抢占优先级位数 | 子优先级位数 | 适用场景 |
---|---|---|---|
0b000(Group 0) | 0 位 | 4 位 | 适用于无抢占,所有中断按优先级顺序执行 |
0b100(Group 1) | 1 位 | 3 位 | 适用于少量高优先级抢占中断 |
0b101(Group 2) | 2 位 | 2 位 | 适用于多级抢占 |
0b110(Group 3) | 3 位 | 1 位 | 适用于实时系统,多级抢占 |
0b111(Group 4) | 4 位 | 0 位 | 适用于完全抢占,所有中断可被更高优先级中断打断 |
示例:高优先级中断打断低优先级中断:
📌 在 NVIC 配置中
EXTI0_IRQn 抢占优先级 0
TIM2_IRQn 抢占优先级 2➡ 当 TIM2 在运行时,EXTI0 可以抢占 TIM2。
void TIM2_IRQHandler(void) {// 低优先级中断(定时器中断)if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}void EXTI0_IRQHandler(void) {// 高优先级中断(外部中断)if (EXTI_GetITStatus(EXTI_Line0) != RESET) {EXTI_ClearITPendingBit(EXTI_Line0);}
}
NVIC 低功耗管理
NVIC 具备低功耗模式下的中断唤醒功能:
- 睡眠模式(Sleep Mode):等待中断(WFI)或事件(WFE)唤醒。
- 停止模式(Stop Mode):只有特定外设(如 RTC、EXTI)可唤醒。
- 待机模式(Standby Mode):最低功耗模式,仅通过外部中断(EXTI)或 RTC 唤醒。
示例代码(使用 WFI 指令进入低功耗模式):
void Enter_SleepMode(void)
{__WFI(); // 等待中断唤醒
}
不过,在某些情况下,可以通过软件触发中断(不依赖外部事件):
NVIC_SetPendingIRQ(EXTI0_IRQn); // 触发 EXTI0 中断挂起// 应用场景:
// 手动测试中断处理函数
// 在任务调度器中强制触发某个中断
NVIC 相关 API(CMSIS)
函数 | 作用 |
---|---|
NVIC_EnableIRQ(IRQn_Type IRQn) | 使能指定中断 |
NVIC_DisableIRQ(IRQn_Type IRQn) | 禁用指定中断 |
NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) | 设置中断优先级 |
NVIC_GetPriority(IRQn_Type IRQn) | 获取当前中断优先级 |
NVIC_SetPendingIRQ(IRQn_Type IRQn) | 触发中断挂起 |
NVIC_ClearPendingIRQ(IRQn_Type IRQn) | 清除中断挂起 |
NVIC_GetPendingIRQ(IRQn_Type IRQn) | 获取中断挂起状态 |
NVIC_GetActive(IRQn_Type IRQn) | 读取当前激活的中断 |
NVIC 是 ARM Cortex-M 系列的核心中断管理单元,支持多级中断嵌套、优先级分配和中断屏蔽,合理配置 NVIC 优先级,可以提高系统的实时性和响应速度,掌握 NVIC 操作 API(使能/禁用/挂起/清除)在嵌入式开发是十分重要的一环。它支持 60+ 中断源,最高 256 级优先级; 支持抢占式优先级调度,优化中断响应;支持低功耗模式唤醒,适用于电池供电设备;提供 CMSIS API,简化 NVIC 配置,可以利用 NVIC 提高 STM32 应用的实时性,优化中断的处理机制。
以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。
我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!