目录
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(下面会讲中断优先级分组)
然后设置中断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;
- 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:外部中断的一般配置步骤
- 使能SYSCFG系统配置控制器时钟
- 初始化IO口为输入
- 设置IO口与中断线的映射关系
- 初始化线上中断,设置触发条件等
- 配置中断分组(NVIC),并使能中断
- 编写中断服务函数
- 清除中断标志位