【STM32】NVIC(嵌套向量中断控制器)

什么是 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 架构示意图:

handlebars 复制代码
			+-----------------------------------+
            |          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)

c 复制代码
| 4-bit 优先级字段 |  |
|-----------------|  
|  Preemption(4)  |  Sub(0)  |
  • 数值越小,优先级越高(0 最高,255 最低)。
  • 抢占优先级高的中断可以中断低优先级的中断。

2. NVIC 优先级配置示例

使用 CMSIS(Cortex Microcontroller Software Interface Standard) 提供的函数可以轻松配置 NVIC:

c 复制代码
#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;  // 子优先级 1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  // 使能中断
    NVIC_Init(&NVIC_InitStructure);
}

// USART1_IRQn:定义要配置的中断源
// NVIC_IRQChannelPreemptionPriority:设置抢占优先级
// NVIC_IRQChannelSubPriority:设置子优先级
// NVIC_IRQChannelCmd:使能该中断

示例二:Cortex-M 配置优先级:

c 复制代码
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。
c 复制代码
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 指令进入低功耗模式):

c 复制代码
void Enter_SleepMode(void)
{
    __WFI();  // 等待中断唤醒
}

不过,在某些情况下,可以通过软件触发中断(不依赖外部事件):

c 复制代码
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 应用的实时性,优化中断的处理机制。

以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

相关推荐
番茄老夫子39 分钟前
ST的全新STM32U3微控制器(MCU)简析
stm32·单片机·嵌入式硬件
公子无缘2 小时前
【嵌入式】复刻SQFMI开源的Watchy墨水屏电子表——(2)软件部分
c语言·嵌入式硬件·物联网·开源·esp32
古希腊掌握嵌入式的神3 小时前
ESP32学习 -从STM32工程架构进阶到ESP32架构
stm32·学习·架构·esp32
励志的小陈3 小时前
栈区、堆区、静态区
c语言·开发语言
共享家95273 小时前
二叉树算法题实战:从遍历到子树判断
c语言·开发语言·数据结构·算法·leetcode
z_鑫3 小时前
数据结构:用C语言实现插入排序
c语言·开发语言·数据结构
亲爱的老吉先森4 小时前
C语言学习笔记(第三部份)
c语言·笔记·学习
youngerwang5 小时前
【嵌入式硬件测试之道连载之开篇语+第一章】
网络·功能测试·嵌入式硬件·深度学习·硬件架构·硬件工程·测试覆盖率
单片机学习之路5 小时前
使用STM32CubeMX+DMA+空闲中断实现串口接收和发送数据(STM32G070CBT6)
stm32·单片机·嵌入式硬件