1. NVIC 基本概念

1.1 NVIC 作用

NVIC(Nested Vectored Interrupt Controller)是 ARM Cortex-M4 内核的一部分,主要负责 管理和调度中断,包括:

  • 使能/屏蔽中断

  • 设置中断优先级

  • 响应和分发中断

  • 支持中断嵌套

1.2 中断优先级划分

在 GD32F407 中,中断优先级由 先占优先级(Preempt Priority)子优先级(Sub Priority) 组成。

  • 先占优先级:决定是否可以抢占正在执行的中断(数值越小,优先级越高)。

  • 子优先级:用于区分同一先占优先级下的中断,数值小的会优先执行。

2. NVIC 相关寄存器

寄存器名 作用
NVIC_ISER (中断使能寄存器) 用于使能中断
NVIC_ICER (中断清除寄存器) 用于禁用中断
NVIC_ISPR (中断挂起寄存器) 设置中断挂起标志
NVIC_ICPR (中断清除挂起寄存器) 清除中断挂起标志
NVIC_IABR (中断活动标志寄存器) 读取当前中断是否处于活动状态
NVIC_IPR (中断优先级寄存器) 设置中断优先级

3. NVIC 中断优先级配置

3.1 设置优先级分组

GD32F407 允许通过 NVIC_SetPriorityGrouping() 设置优先级分组,影响先占优先级和子优先级的位数。

PRIGROUP 值 先占优先级位数 子优先级位数
0 4 0
1 3 1
2 2 2
3 1 3
4 0 4

示例代码:

void NVIC_Configuration(void) {
    // 设置优先级分组: 2 位先占优先级 + 2 位子优先级
    NVIC_SetPriorityGrouping(NVIC_PRIGROUP_PRE2_SUB2);
}

3.2 设置中断优先级

使用 nvic_irq_enable() 设置中断的 先占优先级子优先级

nvic_irq_enable(USART1_IRQn, 0, 0);  // 先占优先级 0,子优先级 0
nvic_irq_enable(TIM3_IRQn, 2, 2);    // 先占优先级 2,子优先级 2

或者使用 NVIC_InitTypeDef 结构体:

NVIC_InitTypeDef NVIC_InitStructure;

// 配置 USART1
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  // 先占优先级 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         // 子优先级 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

4. NVIC 使能、屏蔽和清除中断

4.1 使能中断

NVIC_EnableIRQ(USART1_IRQn);  // 使能 USART1 中断

4.2 禁用中断

NVIC_DisableIRQ(USART1_IRQn);  // 禁用 USART1 中断

4.3 清除中断挂起标志

NVIC_ClearPendingIRQ(USART1_IRQn);  // 清除 USART1 挂起标志

5. NVIC 常见问题

5.1 为什么 NVIC_EnableIRQ(USART1); 会报错?

正确写法

NVIC_EnableIRQ(USART1_IRQn);  // 需要传入 USART1_IRQn,而不是 USART1

错误写法

NVIC_EnableIRQ(USART1);  // USART1 是外设地址,而不是中断号

5.2 为什么高优先级的中断没有抢占低优先级的中断?

可能的原因:

  1. 没有正确设置优先级分组,导致优先级没有正确比较。

  2. 没有开启全局中断 (__enable_irq();)

  3. 被屏蔽了(检查 NVIC_GetEnableIRQ() 是否返回 0)。

5.3 如何手动触发中断?

NVIC_SetPendingIRQ(USART1_IRQn);  // 触发 USART1 中断

6. 总结

  1. NVIC 负责中断管理,包括使能、屏蔽、优先级分配等。

  2. 中断优先级包括“先占优先级”和“子优先级”,数值越小优先级越高。

  3. 使用 nvic_irq_enable()NVIC_Init() 进行中断配置。

  4. NVIC API 操作时,参数必须使用 xxx_IRQn,不能直接写外设名。

掌握 NVIC,才能真正玩转 STM32/GD32!🚀

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐