【STM32学习笔记】(12)——深入浅出NVIC(嵌套向量中断控制器)

NVIC(嵌套向量中断控制器)简介

        在讲如何配置中断优先级之前,我们需要先了解下 NVIC。NVIC 是嵌套向量中断控制器,控制着整个STM32芯片中断相关的功能,它跟Cortex-M3 内核紧密联系,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对Cortex-M3内核里面的 NVIC 进行裁剪,把不需要的部分去掉,所以说 STM32 的 NVIC 是 Cortex-M 3 的 NVIC 的一个子集。

NVIC 寄存器简介

/**
  中断	 NVIC 结构体定义
 */
typedef struct
{
  __IO uint32_t ISER[8];                 /*!<Offset: 0x000  中断使能寄存器          */
  uint32_t RESERVED0[24];                                   
  __IO uint32_t ICER[8];                 /*!<Offset: 0x080  中断清除寄存器          */
  uint32_t RSERVED1[24];                                    
  __IO uint32_t ISPR[8];            	 /*!<Offset: 0x100  中断使能悬起寄存器      */
  uint32_t RESERVED2[24];                                   
  __IO uint32_t ICPR[8];                 /*!<Offset: 0x180  中断清除悬起寄存器 	  */
  uint32_t RESERVED3[24];                                    
  __IO uint32_t IABR[8];            	 /*!<Offset:0x200   中断有效位寄存器       */
  uint32_t RESERVED4[56];                                   
  __IO uint8_t  IP[240];                 /*!< Offset: 0x300  中断优先级寄存器 (8Bit wide) */
  uint32_t RESERVED5[644];                                  
  __O  uint32_t STIR;                    /*!< Offset: 0xE00  软件触发中断寄存器     */
}  NVIC_Type;   

        在配置中断的时候我们一般只用 ISER、ICER 和 IP 这三个寄存器,ISER 用来使能中断,ICER 用来清除中断,IP 用来设置中断优先级

NVIC 中断配置固件库

       固件库头文件 core_cm3.h 中,提供了 NVIC 的一些函数,这些函数遵循 CMSIS 规则,只要是 Cortex-M3 的处理器都可以使用,具体如下:

 

优先级的介绍

       优先级的分组由内核外设SCB 的应用程序中断及复位控制寄存器 AIRCR 的 PRIGROUP[10:8] 位决定,F103 分为了 5 组,具体如下:主优先级 = 抢占优先级。

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

/**
* 配置中断优先级分组:抢占优先级和子优先级
* 形参如下:
* @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)
{
  	/* 检查参数*/
  	assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
    /* 设置优先级分组*/ 
    SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}

 

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

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

NVIC中断编程步骤

        在配置每个中断的时候一般有 3 个编程步骤:

        1、使能外设某个中断,这个具体由每个外设的相关中断使能位控制。比如串口有发送完成中断,接收完成中断,这两个中断都由串口控制寄存器的相关中断使能位控制。

        2、初始化 NVIC_InitTypeDef 结构体,配置中断优先级分组,设置抢占优先级和子优先级,使能中断请求。NVIC_InitTypeDef 结构体在固件库头文件 misc.h 中定义。

typedef struct
{
  uint8_t NVIC_IRQChannel;                      /*!< 中断源 */

  uint8_t NVIC_IRQChannelPreemptionPriority;    /*!< 抢占优先级 */

  uint8_t NVIC_IRQChannelSubPriority;         	/*!< 子优先级*/

  FunctionalState NVIC_IRQChannelCmd;           /*!< 中断使能或者失能 */   
} NVIC_InitTypeDef;

         a. NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序 也不会报错,只会导致不响应中断。具体的成员配置可参考 stm32f10x.h 头文件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。

typedef enum IRQn
{
/******		Cortex-M3 处理器异常编号 		***********/
  NonMaskableInt_IRQn      = -14,    /*!< 2 不可屏蔽中断*/
  MemoryManagement_IRQn    = -12,    /*!< 4 Cortex-M3 内存管理中断*/
  BusFault_IRQn            = -11,    /*!< 5 Cortex-M3 总线故障中断*/
  UsageFault_IRQn          = -10,    /*!< 6 Cortex-M3 使用故障中断*/
  SVCall_IRQn              = -5,     /*!< 11 Cortex-M3 SV 呼叫中断*/
  DebugMonitor_IRQn        = -4,     /*!< 12 Cortex-M3 调试监视器中断*/
  PendSV_IRQn              = -2,     /*!< 14 Cortex-M3挂起 SV 中断*/
  SysTick_IRQn             = -1,     /*!< 15 Cortex-M3 系统滴答中断*/

/******  STM32 特定中断号码*******/
  WWDG_IRQn                = 0,      /*!< 窗口看门狗中断*/
  PVD_IRQn                 = 1,      /*!< PVD 通过 EXTI 线路检测中断*/
  TAMPER_IRQn              = 2,      /*!< 篡改中断*/
  RTC_IRQn                 = 3,      /*!< RTC 全局中断*/
  FLASH_IRQn               = 4,      /*!< 闪存全局中断*/
  RCC_IRQn                 = 5,      /*!< RCC 全局中断*/
  EXTI0_IRQn               = 6,      /*!< EXTI Line0 中断*/
  EXTI1_IRQn               = 7,      /*!< EXTI Line1 中断*/
  EXTI2_IRQn               = 8,      /*!< EXTI Line2 中断*/
  EXTI3_IRQn               = 9,      /*!< EXTI Line3 中断*/
  EXTI4_IRQn               = 10,     /*!< EXTI Line4 中断*/
  DMA1_Channel1_IRQn       = 11,     /*!< DMA1 Channel 1 全局中断*/
  DMA1_Channel2_IRQn       = 12,     /*!< DMA1 Channel 2 全局中断*/
  DMA1_Channel3_IRQn       = 13,     /*!< DMA1 Channel 3 全局中断*/
  DMA1_Channel4_IRQn       = 14,     /*!< DMA1 Channel 4 全局中断*/
  DMA1_Channel5_IRQn       = 15,     /*!< DMA1 Channel 5 全局中断*/
  DMA1_Channel6_IRQn       = 16,     /*!< DMA1 Channel 6 全局中断*/
  DMA1_Channel7_IRQn       = 17,     /*!< DMA1 Channel 7 全局中断*/
  ADC1_2_IRQn              = 18,     /*!< ADC1 and ADC2 全局中断*/
  USB_HP_CAN1_TX_IRQn      = 19,     /*!< USB 设备高优先级或 CAN1 TX 中断*/
  USB_LP_CAN1_RX0_IRQn     = 20,     /*!< USB 设备低优先级或 CAN1 RX0 中断*/
  CAN1_RX1_IRQn            = 21,     /*!< CAN1 RX1 中断*/
  CAN1_SCE_IRQn            = 22,     /*!< CAN1 单片机中断*/
  EXTI9_5_IRQn             = 23,     /*!< External Line[9:5] 中断*/
  TIM1_BRK_IRQn            = 24,     /*!< TIM1 打破 中断*/
  TIM1_UP_IRQn             = 25,     /*!< TIM1 更新 中断*/
  TIM1_TRG_COM_IRQn        = 26,     /*!< TIM1 触发和换向中断*/
  TIM1_CC_IRQn             = 27,     /*!< TIM1 捕获比较中断*/
  TIM2_IRQn                = 28,     /*!< TIM2 全局中断*/
  TIM3_IRQn                = 29,     /*!< TIM3 全局中断*/
  TIM4_IRQn                = 30,     /*!< TIM4 全局中断*/
  I2C1_EV_IRQn             = 31,     /*!< I2C1 事件中断*/
  I2C1_ER_IRQn             = 32,     /*!< I2C1 错误中断*/
  I2C2_EV_IRQn             = 33,     /*!< I2C2 事件中断*/
  I2C2_ER_IRQn             = 34,     /*!< I2C2 错误中断*/
  SPI1_IRQn                = 35,     /*!< SPI1 全局中断*/
  SPI2_IRQn                = 36,     /*!< SPI2 全局中断*/
  USART1_IRQn              = 37,     /*!< USART1 全局中断*/
  USART2_IRQn              = 38,     /*!< USART2 全局中断*/
  USART3_IRQn              = 39,     /*!< USART3 全局中断*/
  EXTI15_10_IRQn           = 40,     /*!< External Line[15:10] 中断*/
  RTCAlarm_IRQn            = 41,     /*!< 通过 EXTI 线路中断发出 RTC 报警*/
  USBWakeUp_IRQn           = 42,     /*!< USB 设备通过 EXTI 线路中断从挂起状态唤醒*/
  TIM8_BRK_IRQn            = 43,     /*!< TIM8 打破中断*/
  TIM8_UP_IRQn             = 44,     /*!< TIM8 更新中断*/
  TIM8_TRG_COM_IRQn        = 45,     /*!< TIM8 触发和换向中断*/
  TIM8_CC_IRQn             = 46,     /*!< TIM8 捕获比较中断*/
  ADC3_IRQn                = 47,     /*!< ADC3 全局中断*/
  FSMC_IRQn                = 48,     /*!< FSMC 全局中断*/
  SDIO_IRQn                = 49,     /*!< SDIO 全局中断*/
  TIM5_IRQn                = 50,     /*!< TIM5 全局中断*/
  SPI3_IRQn                = 51,     /*!< SPI3 全局中断*/
  UART4_IRQn               = 52,     /*!< UART4 全局中断*/
  UART5_IRQn               = 53,     /*!< UART5 全局中断*/
  TIM6_IRQn                = 54,     /*!< TIM6 全局中断*/
  TIM7_IRQn                = 55,     /*!< TIM7 全局中断*/
  DMA2_Channel1_IRQn       = 56,     /*!< DMA2 Channel 1 全局中断*/
  DMA2_Channel2_IRQn       = 57,     /*!< DMA2 Channel 2 全局中断*/
  DMA2_Channel3_IRQn       = 58,     /*!< DMA2 Channel 3 全局中断*/
  DMA2_Channel4_5_IRQn     = 59      /*!< DMA2 Channel 4 and Channel 5 全局中断*/
} IRQn_Type;

        b. NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定,具体参考下图。

        c. NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定,具体参考下图。

         d. NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的是 NVIC_ISER 和 NVIC_ICER 这两个寄存器。

代码举例:

        在配置中断优先级的函数中需要这样写:

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure);//⑤初始化 NVIC

        在main.c中需要调用此函数:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
//抢占优先级可选0~3,响应优先级可选0~3;

        3、编写中断服务函数。

在启动文件 startup_stm32f10x_hd.s 中我们预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我们重新编写,为了方便管理我们把中断服务函数统一写在 stm32f10x_it.c 这个库文件中。

物联沃分享整理
物联沃-IOTWORD物联网 » 【STM32学习笔记】(12)——深入浅出NVIC(嵌套向量中断控制器)

发表评论