STM32基础-NVIC中断控制器

本文详细介绍了NVIC中断控制器的工作原理,包括抢占优先级、响应优先级和自然优先级的概念,以及中断嵌套现象。提供了STM32F407ZGT6芯片的优先级设置示例,展示了如何通过结构体和函数配置TIM3_IRQn和USART1_IRQn的中断优先级,以及优先级分组的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


  

一、NVIC是什么?

  NVIC是一种中断控制器。当一个中断正在处理时,另一个更高优先级的中断可以打断当前中断的执行,并立即得到处理。这种机制使得处理器在高速运行的同时,能够及时响应不同优先级的中断请求。

二、有哪些优先级?(只有抢占优先级才会发生中断嵌套!!)

1. 抢占优先级: 抢占优先级是指中断的打断优先级,抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。
2. 响应优先级: 响应优先级是指中断的响应顺序,响应优先级只有在抢占优先级相同的情况下才有意义。当抢占优先级相同时,俩个中断同时发生,响应优先级高的中断先响应。
3. 自然优先级: 按照自带的优先级编号(硬件固定)在抢占和响应优先级相同的情况下决定先执行哪个中断,数字越小级别越高。这个是由厂家设计好的。
  每个中断源的抢占优先级和响应优先级由用户决定(软件设置),而自然优先级已经被硬件固定, 不可更改。优先级越高其对应的值越低。数字越小,优先级越高。

三、什么是中断嵌套?

答:通俗来讲就是停止当前正在进行的任务去执行抢占优先级更高的中断任务。
   例如:A的抢占优先级为0,B的抢占优先级为1。则当两个中断请求同时发生时,先执行抢占优先级高的A。但是当CPU正处理B时发生了A的中断请求,则停止执行B,先去执行A的中断,当执行完A中断后再去执行剩下的B程序。这就是中断嵌套。

四、优先级的优先等级(序号越低,优先级越高)

(1)优先级大小:抢占优先级 > 响应优先级 > 自然优先级。
(2)抢占优先级相同,响应优先级不同,则先处理响应优先级高的。但是响应优先级没有中断嵌套。
   例:如果A的抢占优先级为0,B的抢占优先级也为0。A的响应优先级为0,B的响应优先级为1。则两个同时发生中断请求时,在抢占优先级相同时先处理响应优先级高的A。但是如果CPU正在处理B时发生了A的中断请求,则继续执行B,当B完成后再执行A。因为响应优先级不会发生中断嵌套。
(3)如果抢占优先级和响应优先级都相同,则比较它们的硬件中断编号(自然优先级),中断编号越小,优先级越高。(硬件中断编号从中断向量表中查看)

五、优先级分组

   Core-M4内核最多支持256级的可编程优先级。用8位来表示优先级级别,,优先级级别分为8组,分别是组0~组7。但是ST公司设计STM32F407ZGT6时,为了精简设计,只用了16 个可编程优先级(使用了 高四位4 位来设置中断优先级,设置低四位的值是无效的)。所以不同的芯片优先级分组会有不同。
以STM32F407ZGT6为例:
分组配置寄存器SCB->AIRCR。
   由 3bit ( AIRCR[10:8] ) 控制抢占优先级与响应优先级分别占几位。由 4bit ( IP bit[7:4] ) 控制不同的优先级决定中断发生的先后。
在这里插入图片描述
IP bit[7:0]:
在这里插入图片描述
   STM32的中断优先级使用4~7共4个位控制。抢占优先级占2位有4种选择,响应优先级占2位有4种选择,故中断共可配置16种优先级。
   例如:要配置2位抢占优先级,2位响应优先级,就需先配置 寄存器AIRCR[10:8]的数值为101。
   注意:一般情况下,系统代码执行过程中,只设置一次中断优先级分组,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。如果设置了多次,则以最后一次为准。

六、优先级设置示例

例如在同一工程项目中有TIM3_IRQn、USART1_IRQn。优先级配置如下(可根据自己目的修改)。

1. 方式一:用结构体配置

(1)配置NVIC控制器。
示例一:TIM3_IRQn优先级设置:

	NVIC_InitTypeDef NVIC_InitStructure; //结构体重命名
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //选择通道(要中断的对象)
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //设置响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道使能
	NVIC_Init(&NVIC_InitStructure);  //根据以上参数初始化NVIC寄存器

示例二:USART1_IRQn优先级设置:

	NVIC_InitTypeDef NVIC_InitStructure; //结构体重命名
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器**

(2)在主函数中初始化优先级分组

这个函数: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
参数可选:(序号对应下图的组)
   NVIC_PriorityGroup_0
   NVIC_PriorityGroup_1
   NVIC_PriorityGroup_2
   NVIC_PriorityGroup_3
   NVIC_PriorityGroup_4
   如当我们选择优先级分组为2时,则有2个位决定抢占优先级,2个位决定响应优先级。抢占优先级两个位有4种选择值:00、01、10、11。分别是0~3(不能超过,除非先修改优先级组)。响应优先级同理。
在这里插入图片描述

主函数:

int main(void) {
    // 配置中断优先级分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    // 其他初始化工作
    // 主循环或其他操作
    while (1) {
        // 主程序逻辑
    }
}

当配置好优先级后,当中断响应时就可以根据优先级响应规则进行处理。规则如上文标题四中所示。

2. 方式二:直接用函数配置

(1)配置NVIC控制器

示例一:配置SysTick_IRQn中断优先级:

	NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(5,1,2));  // 设置SysTick_IRQn中断优先级
	NVIC_EnableIRQ(SysTick_IRQn);    //使能SysTick_IRQn的NVIC响应。
// NVIC_SetPriority ();
		//第一个参数是中断号,这里是 SysTick_IRQn,表示 SysTick 定时器的中断。
		//第二个参数是优先级值,通过 NVIC_EncodePriority() 函数生成。该函数用于设置优先级。
//NVIC_EnableIRQ(SysTick_IRQn):这行代码用于使能 SysTick 中断。通过这个函数,你告诉 NVIC 可以响应 SysTick 中断。

上面代码使用合成优先级值函数:NVIC_EncodePriority(5,1,2);
   NVIC_EncodePriority() 由三个参数组成,上面的函数参数中: 5 表示优先级组号(下图中红框圈住的组号),1 表示抢占优先级等级,2 表示响应优先级等级。

(2)在主函数中初始化优先组

 NVIC_SetPriorityGrouping(5);

   该函数参数和NVIC_EncodePriority函数第一个参数一致,具体参数设置如上述NVIC_EncodePriority函数第一个参数所示。

主函数:

int main(void) {
    // 配置中断优先级分组
    NVIC_SetPriorityGrouping(5);
    // 其他初始化工作
    // 主循环或其他操作
    while (1) {
        // 主程序逻辑
    }
}
### STM32NVIC 配置及使用教程 #### 一、NVIC简介 嵌套向量中断控制器(Nested Vectored Interrupt Controller, NVIC)是ARM Cortex-M系列微处理器的一部分,负责管理多个外设请求并决定哪个中断应该优先处理。对于STM32来说,NVIC允许开发者配置不同类型的中断源及其属性,比如抢占优先级响应优先级等。 #### 二、通过STM32CubeMX初始化NVIC 为了简化开发流程,ST意法半导体提供了图形化的配置工具——STM32CubeMX[^1]。该软件能够帮助用户快速完成MCU的初步设定,包括但不限于时钟树调整、GPIO定义以及各类外设的选择与基础参数指定。当涉及到NVIC时,在项目创建阶段就可以勾选所需启用的具体中断线,并为其分配合适的优先级别;随后生成相应的启动代码框架供后续编程调用。 #### 三、手动编写NVIC相关代码实例 除了借助于自动化工具之外,掌握如何直接操作硬件寄存器也是十分必要的技能之一。下面给出一段简单的例子展示怎样利用标准库函数来激活某个特定的外部中断(EXTI),这里假设目标为按键触发事件: ```c // 包含头文件 #include "stm32f1xx_hal.h" int main(void){ // 初始化系统时钟其他必要组件... /* 设置EXTI线路 */ __HAL_RCC_GPIOA_CLK_ENABLE(); // 开启PA端口时钟 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发模式 HAL_GPIO_Init(GPIOA,&GPIO_InitStruct); /* 配置NVIC */ NVIC_InitTypeDef nvic_struct={0}; nvic_struct.NVIC_IRQChannel = EXTI0_IRQn; // 指定要开启的IRQ通道号 nvic_struct.NVIC_IRQChannelPreemptionPriority=0;// 抢占式优先权等级设置为最高 nvic_struct.NVIC_IRQChannelSubPriority = 1; // 子优先权等级可随意设定 nvic_struct.NVIC_IRQChannelCmd = ENABLE; // 启动此IRQ通道 NVIC_Init(&nvic_struct); // 应用上述配置 while (1){ // 主循环体... } } ``` 值得注意的是,在实际应用过程中还需要实现对应的中断服务程序(ISR), 并将其链接到正确的地址上以便CPU跳转执行。以上述案例为例,则需另外声明如下形式的服务例程: ```c void EXTI0_IRQHandler(void){ if(__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_0)!=RESET){ // 清除标志位以防重复进入ISR __HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_0); // 插入具体业务逻辑... } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值