HAL_NVIC

张开发
2026/4/3 10:55:07 15 分钟阅读
HAL_NVIC
文章目录一、NVIC简介NVIC 做什么二、NVIC模块详解1、NVIC 寄存器2、优先级的定义1.优先级寄存器NVIC_IPRx2.优先级分组3、NVIC 工作完整流程4、F103中断向量表1.内核异常向量固定所有 CM3 通用2.外部中断向量STM32F103 专用三、CudeMx配置NVIC1、NVIC配置界面2、打开NVIC界面3、NVIC 页面里有什么4、最重要一步选择 优先级分组四、NVIC模块组成1、数据结构2、句柄3、API1. 设置中断优先级2. 使能中断3. 禁止中断4. 设置优先级分组5. 挂起中断手动触发6. 清除挂起7. 获取中断活动状态4、状态/错误1. 使能状态2. 优先级状态3. 挂起状态Pending4. 活动状态Active五、NVIC模块通用模版1、NVIC配置2、开启更新中断3、中断服务stm32f1xx_it.c4、中断回调函数处理数据一、NVIC简介NVICNested 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 个可屏蔽中断。typedefstruct{__IOuint32_tISER[8];// 中断使能寄存器uint32_tRESERVED0[24];__IOuint32_tICER[8];// 中断清除寄存器uint32_tRSERVED1[24];__IOuint32_tISPR[8];// 中断使能悬起寄存器uint32_tRESERVED2[24];__IOuint32_tICPR[8];// 中断清除悬起寄存器uint32_tRESERVED3[24];__IOuint32_tIABR[8];// 中断有效位寄存器uint32_tRESERVED4[56];__IOuint8_tIP[240];// 中断优先级寄存器(8Bit wide)uint32_tRESERVED5[644];__Ouint32_tSTIR;// 软件触发中断寄存器}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()/** * 配置中断优先级分组抢占优先级和子优先级 * 形参如下 * 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则抢占优先级就不存在优先级就全部由子优先级控制 */voidNVIC_PriorityGroupConfig(uint32_tNVIC_PriorityGroup){// 设置优先级分组SCB-AIRCRAIRCR_VECTKEY_MASK|NVIC_PriorityGroup;}3、NVIC 工作完整流程外部 / 外设产生中断信号。中断挂起标志置 1。NVIC 读取该中断优先级。NVIC 比较若比当前运行中断抢占优先级更高 → 打断若相同 → 排队按子优先级决定顺序。CPU 自动保存现场入栈。跳转到对应的 中断服务函数ISR。执行完后恢复现场回到原来程序。4、F103中断向量表1.内核异常向量固定所有 CM3 通用2.外部中断向量STM32F103 专用三、CudeMx配置NVIC1、NVIC配置界面2、打开NVIC界面在 CubeMX 界面左边 System Core点击 NVIC进入中断配置页面3、NVIC 页面里有什么主要 3 块Enable是否打开中断打勾 使能Preemption Priority抢占优先级Sub Priority子优先级4、最重要一步选择 优先级分组在 NVIC 页面上方Priority Group (优先级分组)STM32F103 最常用、最稳妥的是NVIC_PriorityGroup_22 位抢占优先级0~32 位子优先级0~3数字越小优先级越高四、NVIC模块组成1、数据结构typedefstruct{__IOuint32_tISER[8];// 中断使能__IOuint32_tICER[8];// 中断禁止__IOuint32_tISPR[8];// 挂起置位__IOuint32_tICPR[8];// 挂起清除__IOuint32_tIABR[8];// 活动标志__IOuint8_tIP[240];// 优先级寄存器最重要}NVIC_Type;2、句柄NVIC 没有句柄3、API1. 设置中断优先级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_22 位抢占 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配置// 1. 分组系统只一次HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);// 2. 设置优先级HAL_NVIC_SetPriority(XXX_IRQn,抢占优先级,子优先级);// 3. 使能中断HAL_NVIC_EnableIRQ(XXX_IRQn);2、开启更新中断// 4. 开启外设中断__HAL_XXX_ENABLE_IT(...);3、中断服务stm32f1xx_it.c//5.中断服务voidXXX_IRQHandler(void){HAL_XXX_IRQHandler(hxxx);}4、中断回调函数处理数据//6.中断回调函数voidHAL_XXX_Callback(XXXT_HandleTypeDef*hxxx){if(hxxx-Instance…){// 接收到数据在这里处理}}

更多文章