STM32F1----NVIC

本文详细介绍了STM32微控制器中NVIC(嵌套向量中断控制器)的配置方法,包括中断优先级分组的设定、NVIC初始化结构体的配置与使用等关键步骤。此外还解释了抢占优先级与子优先级的概念及其在中断处理中的作用。

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

1.NVIC初始化流程
<1>配置中断优先级分组

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

<2>建立NVIC初始化结构体

NVIC_InitTypeDef   NVIC_InitStructure;

<3>配置NVIC结构体并初始化

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

2.NVIC初始化结构体

typedef struct
{
  uint8_t NVIC_IRQChannel;                    /*指定要启用或禁用的IRQ通道 */

  uint8_t NVIC_IRQChannelPreemptionPriority;  /*指定IRQ通道的抢占优先级*/

  uint8_t NVIC_IRQChannelSubPriority;         /*指定IRQ通道的子先级*/

  FunctionalState NVIC_IRQChannelCmd;         /*指定是否在使能*/   
} NVIC_InitTypeDef;

/*优先级组的宏定义*/
#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
                                                            4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
                                                            3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
                                                            2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
                                                            1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
                                                            0 bits for subpriority */

3.NVIC初始化例程

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	NVIC_InitTypeDef   NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

注释
<1> 一般来说,NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)函数只能被调用一次,多次重复调用该函数设置不同的优先级分组的结果是未定义的,谁也不知道会发生什么。

<2> NVIC不会单独使用,总是和中断联系在一起,包括但不限于外部中断,定时器中断,串口通信中断······也就是说使用任何形式的中断都要预先配置好NVIC,确定他的优先级分组,抢占优先级和子优先级,然后使能中断,最后在初始化NVIC。

<3> 当优先级分组和配置的抢占优先级与子优先级不符和时,会发生什么尚不清楚,但是一定要注意这个问题。

4.NVIC常用函数

/*设置优先级分组*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

/*初始化NVIC结构体*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

/*设置系统进入低功耗的模式*/
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);

/*设置SysTick的时钟源*/
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

5.NVIC优先级的补充说明
  NVIC的全称是Nested vectoredinterrupt controller,即嵌套向量中断控制器。
  对于M3和M4内核的MCU,每个中断的优先级都是用寄存器中的8位来设置的。8位的话就可以设置2^8 =256级中断,实际中用不了这么多,所以芯片厂商根据自己生产的芯片做出了调整。比如ST的STM32F1xx和F4xx只使用了这个8位中的高四位[7:4],低四位取零,这样2^4=16,只能表示16级中断嵌套。
在这里插入图片描述
注:

<1>抢占优先级的级别高于响应优先级,数值越小所代表的优先级越大

<2>具体优先级的确定和嵌套规则:

  • 1 只能高抢先优先级的中断可以打断低抢占优先级的中断服务,构成中断嵌套。
  • 2 当2个(N个)相同抢占优先级的中断出现,他们之间不能构成中断嵌套,但STM32首先响应子优先级高的中断。
  • 3 当2个(N个)个抢占优先级和子优先级相同的中断出现,STM32首先响应中断同道所对应的中断向量地址低的中断,就是谁先发生谁先被执行。

<3>通俗的来说
  具有高抢占式优先级的中断可以在具有低抢占式优先级的中断服务程序执行过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以抢占低抢占式优先级的中断的执行。在抢占式优先级相同的情况下,有几个子优先级不同的中断同时到来,那么高子优先级的中断优先被响应

  在抢占式优先级相同的情况下,如果有低子优先级中断正在执行,高子优先级的中断要等待已被响应的低子优先级中断执行结束后才能得到响应,即子优先级不支持中断嵌套。Reset、NMI、HardFault 优先级为负数,高于普通中断优先级,且优先级不可配置。

  系统中断(比如:PendSV,SVC,SysTick)不一定比外部中断(比如SPI,USART)要高。

### 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、付费专栏及课程。

余额充值