中断是相对CPU而言的,因此例如IIC、定时器这些芯片内产生的中断也被称为外部中断,不能狭隘的理解为由芯片外的信号触发
EXTI被称为外部中断/事件控制器(External interrupt/event controller)
什么是中断?什么是事件
EXTI的23个中断事件线与中断的关系? 在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时相应所有端口的中断事件
优先级定义
在NVIC
有一个专门的寄存器:中断优先级寄存器NVIC_IPRx
用来配置外部中断的优先级,IPR
宽度为8bit
,原则上每个外部中断可配置的优先级为0~255
,数值越小,优先级越高。在STM32F4
中使用了高4位设置中断优先级,也就是有16个可编程优先级。
中断优先级被分组为抢占优先级和子优先级。如果有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。
上面说到 NVIC 控制着芯片的中断相关功能, 那么肯定有很多对应的寄存器,在固件库 core_cm3.h 文件内定义了一个 NVIC 结构体,里面定义了相关寄存器,如下:
typedef struct
{
__IO uint32_t ISER[8]; //中断使能寄存器
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; //中断清除寄存器
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; //中断使能悬起寄存器
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; //中断清除悬起寄存器
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; //中断有效位寄存器
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; //中断优先级寄存器
uint32_t RESERVED5[644];
__O uint32_t STIR; //软件触发中断寄存器
} NVIC_Type;
在配置中断时,我们通常使用的只有 ISER、 ICER 和 IP 这三个寄存器,ISER是中断使能寄存器,ICER是中断清除寄存器,IP 是中断优先级寄存器。在固件库 core_cm3.h文件后面,还提供了一些对 NVIC 操作的库函数,这些函数都是遵循 CMSIS 标准, 所以只要是基于 Cortex-M3 内核的芯片都可以用这些函数来操作 NVIC,只不过我们很少这样做,甚至不使用这些函数,因为在后面我们会有更简单的办法来配置中断。至于这些函数内容,大家如果有兴趣的话,可以打开我们库函数版本任意程序,找到 core_cm3.h 文件查看即可。
这里多提一点__IO
的用法:
/* IO definitions (access restrictions to peripheral registers) */
#ifdef __cplusplus
#define __I volatile /*!< defines 'read only' permissions */
#else
#define __I volatile const /*!< defines 'read only' permissions */
#endif
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
其实就是将volatile关键字进行了重定义,用来区分读写,仅仅是语法提醒层面,并不强制。
前面讲解了那么多中断知识, 如果大家不理解也没有关系, 我们会应用即可,等到后面 STM32 熟练了,再回过头深入了解自然就会明白。要使用中断我们就需要先配置它,通常都需经过这几步:
(1)使能外设某个中断,这个具体是由外设相关中断使能位来控制,比如
定时器有溢出中断,这个可由定时器的控制寄存器中相应中断使能位来控制。
(2)设置中断优先级分组,初始化 NVIC_InitTypeDef 结构体,设置抢占
优先级和响应优先级,使能中断请求。
NVIC_InitTypeDef 结构体如下:
typedef struct
{
uint8_t NVIC_IRQChannel; //中断源
uint8_t NVIC_IRQChannelPreemptionPriority; //抢占优先级
uint8_t NVIC_IRQChannelSubPriority; //响应优先级
FunctionalState NVIC_IRQChannelCmd; //中断使能或失能
} NVIC_InitTypeDef;
下面我们对 NVIC_InitTypeDef 结构体成员进行一下简单介绍。
1.NVIC_IRQChannel:中断源的设置,不同的外设中断,中断源不一样,自
然名字也不一样,所以名字不能写错,否则不会进入中断。中断源放在stm32f10x.h 文件的 IRQn_Type结构体内,由于内容太多,这里就不复制所有中断源,只截取一部分,如下:
typedef enum IRQn
{
//Cortex-M3 处理器异常编号
NonMaskableInt_IRQn = -14,
MemoryManagement_IRQn = -12,
BusFault_IRQn = -11,
UsageFault_IRQn = -10,
SVCall_IRQn = -5,
DebugMonitor_IRQn = -4,
PendSV_IRQn = -2,
SysTick_IRQn = -1,
//STM32 外部中断编号
WWDG_IRQn = 0,
PVD_IRQn = 1,
TAMP_STAMP_IRQn = 2,
// 限于篇幅,中间部分代码省略,具体的可查看库文件 stm32f10x.h
DMA2_Channel2_IRQn = 57,
DMA2_Channel3_IRQn = 58,
DMA2_Channel4_5_IRQn = 59
}IRQn_Type;
2.NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定,可以参考前面中断优先级分组内容。
3.NVIC_IRQChannelSubPriority:响应优先级,具体的值要根据优先级分组
来确定,可以参考前面中断优先级分组内容。
4.NVIC_IRQChannelCmd:中断使能/失能设置,使能配置为 ENABLE,失能配置为 DISABLE。
原文:https://www.cnblogs.com/RegressionWorldLine/p/12203676.html