中断和事件 (Interrupts and events)
嵌套向量中断控制器 (Nested vectored interrupt controller -NVIC)
中断是相对 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.
来源: http://www.bubuko.com/infodetail-3384190.html