中断,在单片机中占有很是重要的地位。代码默认地从上向下执行,遇到条件或者其余语句,会按照指定的地方跳转。而在单片机执行代码的过程当中,不免会有一些突发的状况须要处理,这样就会打断当前的代码,待处理完突发状况以后,程序会回到被打断的地方继续执行。git
外部中断/事件控制器(EXTI)管理了控制器的 23 个中断/事件线。每一个中断/事件线都对应有一个边沿检测器,能够实现输入信号的上升沿检测和降低沿的检测。EXTI 能够实现对每一个中断/事件线进行单独配置,能够单独配置为中断或者事件,以及触发事件的属性。github
外部信号进入通过1的边沿检测电路,检测是否符合(有2和3的上升沿和降低沿选择寄存器决定),产生信号,而后和4软件中断事件寄存器或值,(在这里也就说能够写入软件中断事件寄存器模拟中断和事件),以后产生信号一分为二,看5中断屏蔽寄存器和7事件屏蔽寄存器,若是中断和事件都没有屏蔽,首先会产生事件,进入脉冲发生器。其次,会进入6挂起寄存器,而后进入NVIC。编程
注意:app
一、上面说,咱们可使用寄存器4软件模拟中断事件寄存器模式符合条件的信号进入,为何不能用6寄存器呢?由于框架
寄存器是可读可清除的寄存器,经过写1清除。写0无效。因此不能使用函数
二、关于挂起寄存器,挂起就是,证实有了中断,会在触发中断。可是不会硬件清除。ui
只能软件清除,或者修改边沿极性的时候清除。以下spa
先说EXTI吧, 翻译
EXTI 控制器的主要特性:code
下图是ST207的框架图
下图为翻译版
从图中看出和外部中断有关的寄存器有:上升沿触发选择、降低沿触发选择、软件中断事件寄存器、中断屏蔽寄存器、挂起请求寄存器、事件屏蔽寄存器和NVIC中断控制寄存器等。此外就是对输入线的理解了。
另外七根 EXTI 线链接方式以下
也就是说对于一个外部中断线能够和多个GPIO相连,当你要使用哪个IO的时候只要对SYSCFG_EXTICR对应的位设置就行了,在中断屏蔽寄存器或事件屏蔽寄存器对应位能够设置使用哪个中断线
注:ST的使用SYSCFG_EXTICR来配置,GD的采用AFIO寄存器(在GPIO寄存器中)
EXTI是外部中断吧,上面的主要是针对的这22条中断线的说明,咱们还知道仍是有不少中断的,好比定时器中断,串口中断等等,他们不属于这22条中断线。
咱们能够在中断向量表中看到
其余的中断配置都在各个模块的寄存器中了
在上面的EXTI寄存器都设置好后就能够设置NVIC了,关于NVIC的芯片编程手册上描述较少,可是说了
因此咱们就参考一下M3手册吧
找到AIRCR寄存器,其中8到10位为优先级分组
咱们在代码中使用的库函数是
void NVIC_PRIGroup_Enable(uint32_t NVIC_PRIGroup) { /*Set the priority grouping value */ SCB->AIRCR =AIRCR_VECTKEY_MASK | NVIC_PRIGroup; }
其中咱们查到
一、SCB->AIRCR在库函数的地址是0XE000ED0C,不懂的如何查询的,请自行百度
二、查到SCB的结构体定义
咱们看到SCB是SystemControl Block的简写
下面咱们说一下分组的取值
在misc.c中有
* ========================================================================================================================== * NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority |NVIC_IRQChannelSubPriority | Description * ========================================================================================================================== * NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority * | | | 4 bits for subpriority * -------------------------------------------------------------------------------------------------------------------------- * NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority * | | | 3 bits for subpriority * -------------------------------------------------------------------------------------------------------------------------- * NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority * | | | 2 bits for subpriority * -------------------------------------------------------------------------------------------------------------------------- * NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority * | | | 1 bits for subpriority * -------------------------------------------------------------------------------------------------------------------------- * NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority * | | | 0 bits for subpriority * ==========================================================================================================================
抢占优先级& 响应优先级区别
例子:
假定设置中断优先级组为2,而后设置
中断3(RTC中断)的抢占优先级为2,响应优先级为1。
中断6(外部中断0)的抢占优先级为3,响应优先级为0
中断7(外部中断1)的抢占优先级为2,响应优先级为0。
那么这3个中断的优先级顺序为:中断7>中断3>中断6
表如今代码中
NVIC_InitPara NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQ = IRQn; NVIC_InitStructure.NVIC_IRQPreemptPriority =pri; NVIC_InitStructure.NVIC_IRQSubPriority = pri1; NVIC_InitStructure.NVIC_IRQEnable = ENABLE; NVIC_Init(&NVIC_InitStructure);
分组0,那么pri的取值范围0~0,pri1的取值范围0~16
分组2,那么pri的取值范围0~4,pri1的取值范围0~4
分组4,那么pri的取值范围0~16,pri1的取值范围0~0
下面咱们讲解一下NVIC寄存器
__IO uint8_t IP[240]; //中断优先级控制的寄存器组
__IO uint32_t ISER[8]; //中断使能寄存器组
__IO uint32_t ICER[8]; //中断失能寄存器组
__IO uint32_t ISPR[8]; //中断挂起寄存器组
__IO uint32_t ICPR[8]; //中断解挂寄存器组
__IO uint32_t IABR[8]; //中断激活标志位寄存器组
中断优先级控制的寄存器组:IP[240]
全称是:InterruptPriority Registers
240个8位寄存器,每一个中断使用一个寄存器来肯定优先级。
好比:STM32F10x系列一共60个可屏蔽中断,使用IP[59]~IP[0]。
每一个IP寄存器的高4位用来设置抢占和响应优先级(根据分组),低4位没有用到。
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
中断使能寄存器组:ISER[8]
做用:用来使能中断
32位寄存器,每一个位控制一个中断的使能。STM32F10x只有60个可屏蔽中断,因此只使用了其中的ISER[0]和ISER[1]。
ISER[0]的bit0~bit31分别对应中断0~31。ISER[1]的bit0~27对应中断32~59;
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
中断失能寄存器组:ICER[8]
做用:用来失能中断
32位寄存器,每一个位控制一个中断的失能。STM32F10x只有60个可屏蔽中断,因此只使用了其中的ICER[0]和ICER[1]。
ICER[0]的bit0~bit31分别对应中断0~31。ICER[1]的bit0~27对应中断32~59;
配置方法跟ISER同样。
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
中断挂起控制寄存器组:ISPR[8]
做用:用来挂起中断
中断解挂控制寄存器组:ICPR[8]
做用:用来解挂中断
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn); static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn); static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn);
中断激活标志位寄存器组:IABR[8]
做用:只读,经过它能够知道当前在执行的中断是哪个
若是对应位为1,说明该中断正在执行。
static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
必定要使能系统时钟
由于配置GPIO和中断线的映射关系须要SYSCFG
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource11);
只要用到外部中断,就必定要打开SYSCFG时钟
开源代码地址:
https://github.com/strongercjd/STM32F207VCT6/tree/master/09-EXTI
点击查看本文所在的专辑,STM32F207教程