NVIC 方法详解

NVIC 方法详解

NVIC(Nested Vectored Interrupt Controller)是 Cortex-M 内核的中断控制器,负责管理中断的优先级、使能和挂起。HAL 库提供了一组简洁的 NVIC 操作函数。

中断优先级基础

STM32F103 使用 4 位优先级分组,支持 16 级抢占优先级和 16 级子优先级(具体取决于分组设置)。

分组方式抢占优先级位数子优先级位数
NVIC_PRIORITYGROUP_004
NVIC_PRIORITYGROUP_113
NVIC_PRIORITYGROUP_222
NVIC_PRIORITYGROUP_331
NVIC_PRIORITYGROUP_440

NVIC_PRIORITYGROUP_4 最常用,只有抢占优先级,没有子优先级,响应速度最快。

HAL_NVIC_SetPriorityGrouping

void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup);

参数拆解

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
//                           │
//                           └── 优先级分组方式

功能

设置中断优先级分组。

HAL_NVIC_SetPriority

void HAL_NVIC_SetPriority(IRQn_Type IRQn,
                          uint32_t PreemptPriority,
                          uint32_t SubPriority);

参数拆解

HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
//                   │             │  │
//                   │             │  └── 子优先级
//                   │             └───── 抢占优先级
//                   └─────────────────── 中断号

功能

设置指定中断的抢占优先级和子优先级。

参数

参数说明
IRQn中断号,如 TIM2_IRQnUSART1_IRQn
PreemptPriority抢占优先级,数值越小优先级越高
SubPriority子优先级

HAL_NVIC_EnableIRQ

void HAL_NVIC_EnableIRQ(IRQn_Type IRQn);

参数拆解

HAL_NVIC_EnableIRQ(TIM2_IRQn);
//                 │
//                 └── 中断号

功能

使能指定中断。

HAL_NVIC_DisableIRQ

void HAL_NVIC_DisableIRQ(IRQn_Type IRQn);

参数拆解

HAL_NVIC_DisableIRQ(TIM2_IRQn);
//                  │
//                  └── 中断号

功能

禁用指定中断。

HAL_NVIC_SetPendingIRQ

void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);

参数拆解

HAL_NVIC_SetPendingIRQ(TIM2_IRQn);
//                     │
//                     └── 中断号

功能

软件设置指定中断为挂起状态,触发一次中断。

HAL_NVIC_ClearPendingIRQ

void HAL_NVIC_ClearPendingIRQ(IRQn_Type IRQn);

参数拆解

HAL_NVIC_ClearPendingIRQ(TIM2_IRQn);
//                       │
//                       └── 中断号

功能

清除指定中断的挂起状态。

HAL_NVIC_SystemReset

void HAL_NVIC_SystemReset(void);

功能

执行系统软件复位,相当于按复位键。

完整示例:定时器中断配置

// 1. 配置中断优先级分组
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

// 2. 设置定时器中断优先级并使能
HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);

// 3. 启动定时器中断
HAL_TIM_Base_Start_IT(&htim2);

// 4. 中断服务函数
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim2);
}

// 5. 回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == &htim2) {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
}

如果在中断服务函数中调用 HAL_Delay,必须保证 SysTick 的抢占优先级高于该中断,否则会出现死循环。