HAL_NVIC

文章目录

  • 一、NVIC简介
    • [   NVIC 做什么?](#   NVIC 做什么?)
  • 二、NVIC模块详解
    • [   1、NVIC 寄存器](#   1、NVIC 寄存器)
    • [   2、优先级的定义](#   2、优先级的定义)
      • [     1.优先级寄存器NVIC_IPRx](#     1.优先级寄存器NVIC_IPRx)
      • [     2.优先级分组](#     2.优先级分组)
    • [   3、NVIC 工作完整流程](#   3、NVIC 工作完整流程)
    • [   4、F103中断向量表](#   4、F103中断向量表)
      • [     1.内核异常向量(固定,所有 CM3 通用)](#     1.内核异常向量(固定,所有 CM3 通用))
      • [     2.外部中断向量(STM32F103 专用)](#     2.外部中断向量(STM32F103 专用))
  • 三、CudeMx配置NVIC
    • [   1、NVIC配置界面](#   1、NVIC配置界面)
    • [   2、打开NVIC界面](#   2、打开NVIC界面)
    • [   3、NVIC 页面里有什么?](#   3、NVIC 页面里有什么?)
    • [   4、最重要一步:选择 优先级分组](#   4、最重要一步:选择 优先级分组)
  • 四、NVIC模块组成
    • [   1、数据结构](#   1、数据结构)
    • [   2、句柄](#   2、句柄)
    • [   3、API](#   3、API)
      • [     1. 设置中断优先级](#     1. 设置中断优先级)
      • [     2. 使能中断](#     2. 使能中断)
      • [     3. 禁止中断](#     3. 禁止中断)
      • [     4. 设置优先级分组](#     4. 设置优先级分组)
      • [     5. 挂起中断(手动触发)](#     5. 挂起中断(手动触发))
      • [     6. 清除挂起](#     6. 清除挂起)
      • [     7. 获取中断活动状态](#     7. 获取中断活动状态)
    • [   4、状态/错误](#   4、状态/错误)
      • [     1. 使能状态](#     1. 使能状态)
      • [     2. 优先级状态](#     2. 优先级状态)
      • [     3. 挂起状态(Pending)](#     3. 挂起状态(Pending))
      • [     4. 活动状态(Active)](#     4. 活动状态(Active))
  • 五、NVIC模块通用模版
    • [   1、NVIC配置](#   1、NVIC配置)
    • [   2、开启更新中断](#   2、开启更新中断)
    • [   3、中断服务(stm32f1xx_it.c)](#   3、中断服务(stm32f1xx_it.c))
    • [   4、中断回调函数(处理数据)](#   4、中断回调函数(处理数据))

一、NVIC简介

NVIC:Nested Vectored Interrupt Controller嵌套向量中断控制器,整个芯片的中断管理员。

NVIC 是 Cortex‑M3 内置的中断硬件管理器。

NVIC 做什么?

哪个中断可以触发。

中断优先级谁高谁低。

高优先级中断能不能打断低优先级(嵌套)。

中断发生时,CPU 跳去执行哪个函数。

所有中断(串口、定时器、EXTI、DMA...)都必须经过 NVIC 配置才能用。

二、NVIC模块详解

1、NVIC 寄存器

NVIC 寄存器定义在 core_cm3.h 文件中,CM3 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256 级的可编程中断设置。

STM32F103xE芯片有 70 个中断,包括 10 个内核中断和 60 个可屏蔽中断,具有 16 级可编程的中断优先级,我们常用的就是这 60 个可屏蔽中断。

c 复制代码
		typedef struct {
		    __IO uint32_t ISER[8];       // 中断使能寄存器
		    uint32_t RESERVED0[24];
		    __IO uint32_t ICER[8];       // 中断清除寄存器
		    uint32_t RSERVED1[24];
		    __IO uint32_t ISPR[8];       // 中断使能悬起寄存器
		    uint32_t RESERVED2[24];
		    __IO uint32_t ICPR[8];       // 中断清除悬起寄存器
		    uint32_t RESERVED3[24];
		    __IO uint32_t IABR[8];       // 中断有效位寄存器
		    uint32_t RESERVED4[56];
		    __IO uint8_t  IP[240];       // 中断优先级寄存器(8Bit wide)
		    uint32_t RESERVED5[644];
		    __O  uint32_t STIR;          // 软件触发中断寄存器
		}  NVIC_Type;

一般使用ISER、ICER和IP 三个寄存器,IESR用来使能中断,ICER用来失能中断,IP用来设置中断优先级。

ISER[8] :全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。

CM3 内核支持 256 个中断,这里用 8 个 32 位寄存器来控制,每个位控制一个中断。

但是 STM32F103 的可屏蔽中断只有 60 个,所以对我们来说,有用的就是两个(ISER[0]和 ISER[1]),总共可以表示 64 个中断。

ICER[8] :全称是:Interrupt Clear-Enable Registers,是一个中断除能寄存器组。

ISPR[8] :全称是:Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。

ICPR[8] :全称是:Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。

IABR[8] :全称是:Interrupt Active Bit Registers,是一个中断激活标志位寄存器组。

IP[240] :全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。

IP 寄存器组由 240 个 8bit 的寄存器组成,每个可屏蔽中断占用 8bit,这样总共可以表示 240 个可屏蔽中断。

而 STM32 只用到了其中的前 60 个。IP[59]~IP[0]分别对应中断 59~0。

2、优先级的定义

1.优先级寄存器NVIC_IPRx

用于表达优先级的4bit,又被分组成抢占优先级和子优先级。

如果有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行,

如果抢占优先级相同,就比较子优先级。

如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

2.优先级分组

设置优先级分组可调用库函数NVIC_PriorityGroupConfig()实现,有关NVIC中断相关的库函数都在库文件misc.c和misc.h中。

中断优先级分组库函数NVIC_PriorityGroupConfig()

c 复制代码
			/**
			* 配置中断优先级分组:抢占优先级和子优先级
			* 形参如下:
			* @arg NVIC_PriorityGroup_0: 0bit for抢占优先级
			*                            4 bits for 子优先级
			* @arg NVIC_PriorityGroup_1: 1 bit for抢占优先级
			*                            3 bits for 子优先级
			* @arg NVIC_PriorityGroup_2: 2 bit for抢占优先级
			*                            2 bits for 子优先级
			* @arg NVIC_PriorityGroup_3: 3 bit for抢占优先级
			*                            1 bits for 子优先级
			* @arg NVIC_PriorityGroup_4: 4 bit for抢占优先级
			*                            0 bits for 子优先级
			* @注意 如果优先级分组为0,则抢占优先级就不存在,优先级就全部由子优先级控制
			*/
			void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
			{
			    // 设置优先级分组
			    SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
			}

3、NVIC 工作完整流程

外部 / 外设产生中断信号。

中断挂起标志置 1。

NVIC 读取该中断优先级。

NVIC 比较:

若比当前运行中断抢占优先级更高 → 打断!

若相同 → 排队,按子优先级决定顺序。

CPU 自动保存现场(入栈)。

跳转到对应的 中断服务函数(ISR)。

执行完后恢复现场,回到原来程序。

4、F103中断向量表

1.内核异常向量(固定,所有 CM3 通用)

2.外部中断向量(STM32F103 专用)

三、CudeMx配置NVIC

1、NVIC配置界面

2、打开NVIC界面

在 CubeMX 界面:

左边 System Core

点击 NVIC

进入中断配置页面

3、NVIC 页面里有什么?

主要 3 块:

Enable:是否打开中断(打勾 = 使能)

Preemption Priority:抢占优先级

Sub Priority:子优先级

4、最重要一步:选择 优先级分组

在 NVIC 页面上方:

Priority Group (优先级分组)

STM32F103 最常用、最稳妥的是:

NVIC_PriorityGroup_2

2 位抢占优先级(0~3)

2 位子优先级(0~3)

数字越小,优先级越高!

四、NVIC模块组成

1、数据结构

c 复制代码
		typedef struct
		{
		  __IO uint32_t ISER[8];       // 中断使能
		  __IO uint32_t ICER[8];       // 中断禁止
		  __IO uint32_t ISPR[8];       // 挂起置位
		  __IO uint32_t ICPR[8];       // 挂起清除
		  __IO uint32_t IABR[8];       // 活动标志
		  __IO uint8_t  IP[240];       // 优先级寄存器(最重要)
		} NVIC_Type;

2、句柄

NVIC 没有句柄!

3、API

1. 设置中断优先级

HAL_NVIC_SetPriority(IRQn, PreemptPriority, SubPriority);

示例:

HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);

2. 使能中断

HAL_NVIC_EnableIRQ(IRQn);

3. 禁止中断

HAL_NVIC_DisableIRQ(IRQn);

4. 设置优先级分组

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);

F103 最常用:GROUP_2(2 位抢占 + 2 位子优先级)

5. 挂起中断(手动触发)

NVIC_SetPendingIRQ(IRQn);

6. 清除挂起

NVIC_ClearPendingIRQ(IRQn);

7. 获取中断活动状态

uint32_t status = NVIC_GetActive(IRQn);

4、状态/错误

NVIC 有 4 种状态:

1. 使能状态

已使能|已禁止

中断是否已使能:

uint32_t en = NVIC_GetEnableIRQ(IRQn);

2. 优先级状态

抢占优先级|子优先级

获取当前优先级分组:

uint32_t pg = HAL_NVIC_GetPriorityGrouping();

3. 挂起状态(Pending)

中断触发了,但还没来得及处理。

中断是否挂起:

uint32_t pending = NVIC_GetPendingIRQ(IRQn);

4. 活动状态(Active)

正在执行中断服务函数。

中断是否正在执行:

uint32_t active = NVIC_GetActive(IRQn);

五、NVIC模块通用模版

NVIC应用实例都与具体外设有关,请查看外设对应实例。

1、NVIC配置

c 复制代码
		// 1. 分组(系统只一次)
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		
		// 2. 设置优先级
		HAL_NVIC_SetPriority(XXX_IRQn, 抢占优先级, 子优先级);
		
		// 3. 使能中断
		HAL_NVIC_EnableIRQ(XXX_IRQn);
		

2、开启更新中断

c 复制代码
		// 4. 开启外设中断
		__HAL_XXX_ENABLE_IT(...);

3、中断服务(stm32f1xx_it.c)

c 复制代码
		//5.中断服务
		void XXX_IRQHandler(void)
		{
		  HAL_XXX_IRQHandler(&hxxx);
		}

4、中断回调函数(处理数据)

c 复制代码
		//6.中断回调函数
		void HAL_XXX_Callback(XXXT_HandleTypeDef *hxxx)
		{
		  if(hxxx->Instance == ...)
		  {
		    // 接收到数据,在这里处理
		  }
		}
相关推荐
养一回月亮!2 小时前
STM32F407VET6驱动1.8寸TFT LCD移植LVGL,实现矩阵按键控制UI
stm32·单片机·lvgl
恒森宇电子有限公司2 小时前
芯晞微CSM4056H 单节锂离子电池充电器芯片 封装ESOP-8
单片机·嵌入式硬件
果果燕2 小时前
ARM嵌入式学习(五)---IMX6ULL外部中断
单片机·嵌入式硬件
无人机9012 小时前
Delphi网络编程实战:UDP通信与多线程网络优化详解
单片机·嵌入式硬件
笨笨饿2 小时前
博客目录框架
c语言·开发语言·arm开发·git·嵌入式硬件·神经网络·编辑器
KOYUELEC光与电子努力加油3 小时前
BROADCOM博通集成 Matter 1.5平台认证就绪、BK7239N等芯片助力智能家居无缝融合
服务器·科技·单片机·智能家居
Lugas Luo4 小时前
SATA Port Multiplier (SATA 集线器) 原理与驱动架构深度剖析
linux·嵌入式硬件
zmj3203244 小时前
芯片的ISP在系统编程-模式
单片机·嵌入式开发
zmj3203244 小时前
KW45的ISP模式
stm32·单片机·嵌入式硬件·kw45