2. MCU 中断系统概述:中断向量表、中断优先级、中断嵌套、中断使能与屏蔽机制
中断系统是 MCU 实时响应外部或内部事件的硬件核心。在 UART 中断模式驱动开发中,理解中断系统的底层机制是配置可靠通信的基础。本节将系统梳理中断向量表、优先级、嵌套、使能与屏蔽四大核心概念,并给出它们在 Cortex-M 系列 MCU(如 STM32)中的典型实现。
2.1 中断向量表(Interrupt Vector Table, IVT)
中断向量表是一张存储在 MCU 起始地址(通常为 0x0000 0000 或 0x0800 0000)的地址映射表。每个中断源对应表中的一个表项,表项内容为该中断服务函数(ISR)的入口地址。当 MCU 响应中断时,硬件自动从向量表中取出对应地址并跳转执行。
关键点: 向量表在系统启动时由链接脚本定位,复位后 MCU 从向量表首地址(
__initial_sp)加载栈指针,从第二个字(Reset_Handler)加载复位入口。UART 中断的向量表项通常位于外部中断区域(如 IRQ 37~52 取决于具体 MCU)。
2.2 中断优先级(Interrupt Priority)
中断优先级决定了当多个中断同时触发时,MCU 优先响应哪一个。Cortex-M 内核支持可编程优先级,通常分为抢占优先级(Preemption Priority)和子优先级(Subpriority)。
| 优先级类型 | 作用 | 典型位数(STM32) | 数值与优先级关系 |
|---|---|---|---|
| 抢占优先级 | 决定是否打断正在执行的低优先级中断 | 4 位(0~15) | 数值越小,优先级越高 |
| 子优先级 | 当抢占优先级相同时,决定响应顺序 | 4 位(0~15) | 数值越小,优先级越高 |
配置建议: 在 UART 驱动中,通常将 UART 中断的抢占优先级设为中等(如 5~7),避免被 SysTick(通常为最低优先级)以外的低优先级中断干扰,同时不阻塞高实时性中断(如 TIM 定时器)。
2.3 中断嵌套(Interrupt Nesting)
中断嵌套是指一个中断服务函数正在执行时,被另一个更高优先级的中断打断的现象。Cortex-M 内核通过硬件自动压栈(Push)和出栈(Pop)现场来支持嵌套,无需软件干预。
2.4 中断使能与屏蔽机制
中断使能(Enable)与屏蔽(Mask)是控制中断是否被响应的两种手段。使能是允许特定中断源触发,屏蔽则是全局或局部地禁止中断响应。
2.4.1 中断使能
- 外设级使能: 在 UART 控制寄存器(如
USART_CR1)中设置RXNEIE(接收中断使能)或TCIE(发送完成中断使能)位。 - 内核级使能: 在 NVIC(嵌套向量中断控制器)中使能对应中断通道,调用
NVIC_EnableIRQ(USARTx_IRQn)。
2.4.2 中断屏蔽
- 全局屏蔽: 使用
__disable_irq()(CPSID I)关闭所有可屏蔽中断;使用__enable_irq()(CPSIE I)恢复。 - 优先级屏蔽: 设置
BASEPRI寄存器,屏蔽所有优先级低于或等于该值的中断。例如__set_BASEPRI(0x50)屏蔽优先级 >= 5 的中断。 - 局部屏蔽: 在 NVIC 中调用
NVIC_DisableIRQ(USARTx_IRQn)关闭特定中断。
常见陷阱: 在 ISR 内部使用
__disable_irq() 会导致所有中断被关闭,包括 SysTick,可能造成系统时钟失准。推荐使用 __set_BASEPRI() 进行优先级屏蔽,或使用临界区保护宏(如 __disable_irq() / __enable_irq() 对)仅保护关键代码段。
2.5 中断使能与屏蔽机制对比
| 机制 | 作用范围 | 实现方式 | 典型场景 |
|---|---|---|---|
| 全局使能/屏蔽 | 所有可屏蔽中断 | __enable_irq() / __disable_irq() |
系统初始化、临界区保护 |
| 优先级屏蔽 | 低于设定优先级的中断 | __set_BASEPRI(priority) |
ISR 内保护共享数据 |
| 外设级使能 | 单个外设中断源 | 设置外设控制寄存器位 | UART 接收/发送中断开关 |
| NVIC 通道使能 | 单个中断通道 | NVIC_EnableIRQ() / NVIC_DisableIRQ() |
动态控制 UART 中断响应 |
2.6 中断配置代码示例(STM32 UART)
/* 1. 设置中断优先级分组(抢占优先级 4 位,子优先级 0 位) */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/* 2. 配置 UART 中断优先级 */
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; /* 抢占优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 3. 使能 UART 外设级接收中断 */
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
/* 4. 全局中断使能(通常在系统初始化时已调用) */
__enable_irq();
/* 5. 在 ISR 中使用优先级屏蔽保护临界区 */
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
/* 进入临界区:屏蔽优先级 <= 10 的中断 */
__set_BASEPRI(0xA0);
/* 读取接收数据寄存器 */
uint8_t data = USART_ReceiveData(USART1);
/* 退出临界区:恢复 BASEPRI */
__set_BASEPRI(0);
/* 处理接收数据(如放入环形缓冲区) */
// ...
}
}
总结: 中断向量表提供 ISR 入口映射,优先级决定响应顺序,嵌套实现高优先级打断低优先级,使能与屏蔽机制提供灵活的中断控制粒度。在 UART 驱动开发中,合理配置这四层机制是保证数据不丢失、系统不卡死的核心前提。