STM32中断NVIC、EXTI外部中断

目录

1:NVIC(嵌套向量中断控制器)

2:抢占优先级&响应优先级

3:中断管理的方法

4:EXTI外部中断概述

5:外部中断的一般配置步骤


eg:STM32F407ZGT6

1:NVIC(嵌套向量中断控制器)

在参考手册的描述中(我就直接Copy了哈):

嵌套向量中断控制器 NVIC 包含以下特性:
STM32F405xx/07xx STM32F415xx/17xx 具有 82 个可屏蔽中断通道, STM32F42xxx
    和 STM32F43xxx 具有多达 86 个可屏蔽中断通道(不包括 Cortex™-M4F 的 16 根中 断线)
16 个可编程优先级使用了 4 位中断优先级)
低延迟异常和中断处理
电源管理控制
系统控制寄存器的实现
 
嵌套向量中断控制器 (NVIC) 和处理器内核接口紧密配合,可以实现低延迟的中断处理和晚
到中断的高效处理。
 
F4是用的CM4内核,而CM4内核支持 256个中断,其中包含了 16个内核中断240个外部中断,并且具用 256级的可编程中断设置
SO————STM32F407ZGT6用到的中断资源只是CM4内核中断资源的一部分
 

敲黑板:

STM32F40xx/STM32F41xx的 92个中断里面,包括 10个内核中断82个可屏蔽中断,具有 16级可编程的中断优先级,而我们常用的就是这82个可屏蔽中断。(具体的参数可以去看相应芯片的数据手册)
 
 

2:抢占优先级&响应优先级

就是两种中断的级别,可以组合。

  • 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的
  • 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断
  • 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行
  • 如果两个中断的抢占优先级和响应优先级是一样的,那就看哪个先发生就安排哪个。

假设先设置中断优先级分组为2(下面会讲中断优先级分组)

扫描二维码关注公众号,回复: 11244137 查看本文章

然后设置中断A的抢占优先级为2,响应优先级为1

              中断B的抢占优先级为3,响应优先级为0

              中断C的抢占优先级为2,响应优先级为0

那么这三个中断的优先级顺序为: C>=A>B  (号子越小越牛逼) 

3:中断管理的方法

首先,要对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级

 写代码的时候,先设置完一次中断优先级分组后,就不要去改变了,随意的分组会导致中断管理混乱。且后面所有的中断都要满足你这个分组的要求,比如,我设置为组2,那么你后面所有的中断抢占和响应优先级都不能高于0x03

分组配置是在应用程序中断及复位控制寄存器SCB->AIRCR中配置

  /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;

 OK,有了中断优先级的概念后,再来看中断设置的相关寄存器

typedef struct
{
  __IO uint32_t ISER[8];                 /*!< Offset: 0x000 (R/W)  中断使能寄存器组 */
       uint32_t RESERVED0[24];
  __IO uint32_t ICER[8];                 /*!< Offset: 0x080 (R/W)  中断失能寄存器组 */
       uint32_t RSERVED1[24];
  __IO uint32_t ISPR[8];                 /*!< Offset: 0x100 (R/W)  中断挂起寄存器组 */
       uint32_t RESERVED2[24];
  __IO uint32_t ICPR[8];                 /*!< Offset: 0x180 (R/W)  中断解挂寄存器组 */
       uint32_t RESERVED3[24];
  __IO uint32_t IABR[8];                 /*!< Offset: 0x200 (R/W)  中断激活标志位寄存器组 */
       uint32_t RESERVED4[56];
  __IO uint8_t  IP[240];                 /*!< Offset: 0x300 (R/W) 中断优先级控制寄存器组(8Bit wide) */
       uint32_t RESERVED5[644];
  __O  uint32_t STIR;                    /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;
  1.  IP[240]:Interrupt Priority Registers 中断优先级控制的寄存器组240个8位寄存器,

每个中断使用一个寄存器来确定优先级,前面介绍了,F40系列一共82个可屏蔽中断,使用IP[81]~IP[0].

每个IP寄存器的高四位都用来设置抢占和响应优先级(根据分组),低4位没有用到

    2:ISER[8]:中断使能寄存器组

用来使能中断的,32位寄存器,每个位控制一个中断的使能。一共82个可屏蔽中断,所以只使用了其中的ISER[0]~ISER[2] (因为是32位的) 

  •      ISER[0]的bit0~bit31分别对应中断0~31。
  •      ISER[1]的bit0~27对应中断32~63;
  •      ISER[2]的bit0~17对应于中断64~81

  3:ICER[8]:中断失能寄存器组

用来失能中断 32位寄存器,每个位控制一个中断的失能,和2一样。不多bb

4:中断挂起控制寄存器组ISPR[8],中断解挂控制寄存器组ICPR[8],都和前两个一样

5:IABR[8]:中断激活标志位寄存器组

只读,通过它可以知道当前在执行的中断是哪一个,如果对应位为1,说明该中断正在执行

/********************************************************************************************************************/

以上,就是中断最基本的一些知识,不需要去记住,不管是标准库,还是HAL库,都有相应的函数去调用,刨开那些函数,调用的也就是上面的寄存器。

至于代码,我就不贴了,网上一大堆

4:EXTI外部中断概述

STM32F4的每个IO都可以作为外部中断输入

STM32F4的中断控制器支持22个外部中断/事件请求:

  • EXTI线0~15:对应外部IO口的输入中断。
  • EXTI线16:连接到PVD输出。
  • EXTI线17:连接到RTC闹钟事件。
  • EXTI线18:连接到USB OTG FS唤醒事件。
  • EXTI线19:连接到以太网唤醒事件。
  • EXTI线20:连接到USB OTG HS(在FS中配置)唤醒事件。
  • EXTI线21:连接到RTC入侵和时间戳事件。
  • EXTI线22:连接到RTC唤醒事件。

每个外部中断线都可以独立的配置触发方式(上升沿,下降沿或双边沿触发),触发/屏蔽,专用的状态位。

上面,我们可以看到,IO口的输入中断线只有16个,而F4的IO口有多达百个,前面也说了,32的每个IO口都可以触发外部中断,所以,这个里面是有取舍的。

看这个图,就很明确了,把PX0拉到EXT0上,把PX1拉到EXT1上,这样,就可以用16根IO口外部中断线来管理上百个IO了。

但是还没结束,并不是16根中断线就可以分配到16个中断服务函数

很吝啬的是,只有7个中断服务函数

后面的EXTI9-5,EXTI15-10只能挤挤了。也就是说PX9~PX5共用一个外部中断服务函数,PX15~PX10共用一个外部中断服务函数

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);       //使能SYSCFG时钟
 
 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);//PA0 连接到中断线0

  /* 配置EXTI_Line0 */
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;              //LINE0
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;     //中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  //上升沿触发 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;               //使能LINE0
  EXTI_Init(&EXTI_InitStructure);                         //配置

 /*配置一下外部中断0的中断优先级和使能通道*/
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;            //外部中断0
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;       //子优先级2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //使能外部中断通道
  NVIC_Init(&NVIC_InitStructure);//配置

  //外部中断0服务程序
  void EXTI0_IRQHandler(void)
 {
	 EXTI_ClearITPendingBit(EXTI_Line0);                      //清除LINE0上的中断标志位 
  }	

看上面第一步,要使能系统配置控制器时钟,这个很重要

#define RCC_APB2Periph_SYSCFG            ((uint32_t)0x00004000)

/*调用RCC_APB2PeriphClockCmd,实际上赋值给了APB2ENR寄存器*/
RCC->APB2ENR |= RCC_APB2Periph;

/*
位 14 SYSCFGEN:系统配置控制器时钟使能 (System configuration controller clock enable)
由软件置 1 和清零。
0:禁止系统配置控制器时钟 
1:使能系统配置控制器时钟
使能了系统配置控制器后,可以看看SYSCFG_EXTICRX寄存器的描述,你就懂了
*/

5:外部中断的一般配置步骤

  1. 使能SYSCFG系统配置控制器时钟
  2. 初始化IO口为输入
  3. 设置IO口与中断线的映射关系
  4. 初始化线上中断,设置触发条件等
  5. 配置中断分组(NVIC),并使能中断
  6. 编写中断服务函数
  7. 清除中断标志位

猜你喜欢

转载自blog.csdn.net/qq_41867145/article/details/106217101