一、中断概述
中断:在主程序运行过程中,出现了特定事件,使得 CPU 暂停当前正在运行的程序,转而去处理这个事件,等这个事件处理完成之后,CPU 再回到刚才被打断的位置继续处理
中断源:打断 CPU 执行的特定事件
断点:被中断源打断的位置
执行中断处理程序:处理特定事件的过程
中断嵌套:在执行中断程序的时候,这个时候有可能被另外一个中断源给中断,CPU 转而去执行另外一个中断源的中断处理程序
中断优先级:优先级高的可以打断优先级低的,优先级低的无法打断优先级高的
外部中断源与内部中断源:中断源可以是外部的,也可以是内部的
二、STM32 的中断
Cortex-M3
内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256 级的可编程中断设置一般情况下,芯片厂商会对
Cortex-M3
的中断进行裁剪STM32 有 84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级
STM32F103 系列有 70 个中断,有 10 个内核中断和 60 个可编程的外部中断
三、NVIC 嵌套向量中断控制器
1、概述
NVIC(Nested Vectored Interrupt Controller)嵌套向量中断控制器,是用于管理中断的核心模块
NVIC 可以高效处理多优先级中断,支持低延迟响应
NVIC 管理着包括内核异常,外部中断等所有中断,由 NVIC 决定哪个中断的处理程序交给 CPU 来执行
每一个外部中断都可以被使能或者禁止,并且可以被设置为挂起状态或者清除状态
处理器的中断可以是电平形式的,也可以是脉冲形式的,这样 NVIC 就可以处理任何中断源
16 个 IO 的中断与 PVD(电源电压检测),RTC(实时时钟),USB,以太网检测这 20 个外部中断会通过 EXTI 来控制,然后交给 NVIC,其他中断都是直接交给 NVIC 来处理
2、中断优先级
- NVIC 为了方便管理中断,可以通过软件给每个中断设置优先级,NVIC 用 4 个位来控制优先级,值小的优先级高,把优先级分为两种:抢占优先级与响应优先级
优先级值越小,优先级越高
如果不设置优先级,则默认优先级为 0
先比较抢占优先级,抢占优先级高的可以打断抢占优先级低的
若抢占优先级一样,再比较响应优先级,但是响应优先级不会导致中断嵌套
若抢占优先级一样的同时挂起,则优先处理响应抢占优先级高的
若挂起的优先级(抢占和响应)都一样,则查找中断向量表,值小的先响应
- NVIC 对优先级分了 5 组,在程序中先对中断进行分组,而且分组只能分一次,若多次分,只有最后一次生效
分组 | 抢占优先级 | 响应优先级 |
---|---|---|
0 | 0 位取值范围:0 |
4 位取值范围:0 ~ 15 |
1 | 1 位取值范围:0 ~ 1 |
3 位取值范围:0 ~ 7 |
2 | 2 位取值范围:0 ~ 3 |
2 位取值范围:0 ~ 3 |
3 | 3 位取值范围:0 ~ 7 |
1 位取值范围:0 ~ 1 |
4 | 4 位取值范围:0 ~ 15 |
0 位取值范围:0 |
四、外部中断配置寄存器组
typedef struct
{
__IO uint32_t EVCR;
__IO uint32_t MAPR;
__IO uint32_t EXTICR[4];
uint32_t RESERVED0;
__IO uint32_t MAPR2;
} AFIO_TypeDef;
其中,
EXTICR[4]
是外部中断配置寄存器组它由 4 个 32 位寄存器组成,每个寄存器控制 4 个外部中断线的配置
外部中断配置寄存器组用于将 GPIO 引脚连接到对应的 EXTI 中断线
寄存器 | 地址偏移 | 管理的中断线 |
---|---|---|
EXTICR[0] |
0x08 |
EXTI0 ~ EXTI3 |
EXTICR[1] |
0x0C |
EXTI4 ~ EXTI7 |
EXTICR[2] |
0x10 |
EXTI8 ~ EXTI11 |
EXTICR[3] |
0x14 |
EXTI12 ~ EXTI15 |
- 例如,
EXTICR[0]
就是控制EXTI0 ~ EXTI3
这 4 个外部中断线的配置
位域 | 功能 | 对应 GPIO 端口 |
---|---|---|
EXTI3[15:11] |
选择 EXTI3 的 GPIO 端口(PA3 ~ PI3) | 0000 : PA30001 : PB30010 : PC30011 : PD30100 : PE30101 : PF30110 : PG30111 : PH31000 : PI3 |
EXTI2[11:8] |
选择 EXTI2 的 GPIO 端口(PA2 ~ PI2) | 0000 : PA20001 : PB20010 : PC20011 : PD20100 : PE20101 : PF20110 : PG20111 : PH21000 : PI2 |
EXTI1[7:4] |
选择 EXTI1 的 GPIO 端口(PA1 ~ PI1) | 0000 : PA10001 : PB10010 : PC10011 : PD10100 : PE10101 : PF10110 : PG10111 : PH11000 : PI1 |
EXTI0[3:0] |
选择 EXTI0 的 GPIO 端口(PA0 ~ PI0) | 0000 : PA00001 : PB00010 : PC00011 : PD00100 : PE00101 : PF00110 : PG00111 : PH01000 : PI0 |
五、EXTI 外部中断控制器
基本介绍
EXTI,全称 External Interrupt/Event Controller,即外部中断控制器
EXTI 是 STM32 中用于管理外部中断和事件的模块,它负责检测 GPIO 引脚、外设或软件触发的中断 / 事件请求,并将其传递给 NVIC 或直接触发事件响应
typedef struct
{
__IO uint32_t IMR;
__IO uint32_t EMR;
__IO uint32_t RTSR;
__IO uint32_t FTSR;
__IO uint32_t SWIER;
__IO uint32_t PR;
} EXTI_TypeDef;
寄存器 | 地址偏移 | 功能 |
---|---|---|
IMR |
0x00 |
中断屏蔽寄存器 |
EMR |
0x04 |
事件屏蔽寄存器 |
RTSR |
0x08 |
上升沿触发选择寄存器 |
FTSR |
0x0C |
下降沿触发选择寄存器 |
SWIER |
0x10 |
软件中断事件寄存器 |
PR |
0x14 |
中断挂起寄存器 |
IMR
IMR 全称 Interrupt Mask Register,即中断屏蔽寄存器
IMR 控制是否允许外部中断线产生中断请求,即屏蔽或使能
位域 | 说明 |
---|---|
[31:20] |
保留,必须始终保持为复位状态(0) |
[19:0] |
线 x 上的中断屏蔽 0:屏蔽来自线 x 上的中断请求 1:开放来自线 x 上的中断请求 注:位 19 只适用于互联型产品,对于其它产品为保留位 |
EMR
EMR 全称 Event Mask Register,即事件屏蔽寄存器
EMR 控制是否允许外部中断线产生事件请求,即屏蔽或使能
位域 | 说明 |
---|---|
[31:20] |
保留,必须始终保持为复位状态(0) |
[19:0] |
线 x 上的事件屏蔽 0:屏蔽来自线 x 上的事件请求 1:开放来自线 x 上的事件请求 注:位 19 只适用于互联型产品,对于其它产品为保留位 |
RTSR
RTSR 全称 Rising Trigger Selection Register,即上升沿触发选择寄存器
RTSR 配置外部中断 / 事件的触发条件为信号上升沿,即从低电平跳变到高电平
位域 | 说明 |
---|---|
[31:19] |
保留,必须始终保持为复位状态(0) 注:位 19 只适用于互联型产品,对于其它产品为保留位 |
[18:0] |
线 x 上的上升沿触发选择 0:禁止来自线 x 上的上升沿触发 1:开放来自线 x 上的上升沿触发 |
FTSR
FTSR 全称 Falling Trigger Selection Register,即下降沿触发选择寄存器
FTSR 配置外部中断 / 事件的触发条件为信号下降沿,即从低电平跳变到高电平
位域 | 说明 |
---|---|
[31:19] |
保留,必须始终保持为复位状态(0) 注:位 19 只适用于互联型产品,对于其它产品为保留位 |
[18:0] |
线 x 上的下降沿触发选择 0:禁止来自线 x 上的下降沿触发 1:开放来自线 x 上的下降沿触发 |
SWIER
SWIER 全称 Software Interrupt Event Register,即软件中断事件寄存器
SWIER 通过软件写入模拟外部中断 / 事件的触发,即无需实际电平变化
位域 | 说明 |
---|---|
[31:19] |
保留,必须始终保持为复位状态(0) 注:位 19 只适用于互联型产品,对于其它产品为保留位 |
[18:0] |
线 x 上的软件中断 / 事件 当该位为 0 时,写 1 将设置 PR 中相应的挂起位,如果在 IMR 和 EMR 中允许产生该中断 / 事件,则此时将产生一个中断 / 事件 通过清除 PR 的对应位,即写 1 到 PR,可以间接清除该位为 0 |
PR
PR 全称 Pending Register,即中断挂起寄存器
OR 标志请求是否已触发且未处理(挂起状态)
位域 | 说明 |
---|---|
[31:19] |
保留,必须始终保持为复位状态(0) 注:位 19 只适用于互联型产品,对于其它产品为保留位 |
[18:0] |
线 x 上的挂起位 0:没有发生触发请求 1:发生了选择的触发请求 当在外部中断线上发生了选择的边沿事件,该位被置 1,在该位中写入 1 可以清除它,也可以通过改变边沿检测的极性清除 |
六、实例实操
- 使用按钮 PE4 作为按键输入,通过外部中断控制 LED 灯 PB5
#include "stm32f10x.h"
int main()
{
// RCC APB2 使能
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // 使能 GPIOB 时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPEEN; // 使能 GPIOE 时钟
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // 使能 AFIO 时钟(用于外部中断配置)
// 清除 PB5 配置
GPIOB->CRL &= ~(GPIO_CRL_MODE5 | GPIO_CRL_CNF5);
// 清除 PE4 配置
GPIOE->CRL &= ~(GPIO_CRL_MODE4 | GPIO_CRL_CNF4);
// 设置 PB5 为推挽输出模式,最大速度为 50MH
GPIOB->CRL |= GPIO_CRL_MODE5_0 | GPIO_CRL_MODE5_1;
// 设置 PE4 为输入模式,上拉
GPIOE->CRL |= GPIO_CRL_CNF4_0;
GPIOE->ODR |= GPIO_ODR_ODR4;
// 点亮 PB5
GPIOB->ODR &= ~GPIO_ODR_ODR5;
// 清除 EXTI4 配置
AFIO->EXTICR[1] &= ~AFIO_EXTICR2_EXTI4; // 清除 EXTI4 的连接
EXTI->IMR &= ~EXTI_IMR_MR4; // 禁用EXTI4中断屏蔽
EXTI->FTSR &= ~EXTI_FTSR_TR4; // 禁用EXTI4下降沿触发
// 设置 EXTI4 配置
AFIO->EXTICR[1] |= AFIO_EXTICR2_EXTI4_PE; // 将 PE4 连接到 EXTI4
EXTI->IMR |= EXTI_IMR_MR4; // 使能 EXTI4 中断屏蔽
EXTI->FTSR |= EXTI_FTSR_TR4; // 使能 EXTI4 下降沿触发
// 设置 EXTI4 中断优先级为15
NVIC_SetPriority(EXTI4_IRQn, 0x0F);
// 使能 EXTI4 中断通道
NVIC_EnableIRQ(EXTI4_IRQn);
while (1)
;
}
void EXTI4_IRQHandler(void)
{
// 检查中断标志
if (EXTI->PR & EXTI_PR_PR4)
{
EXTI->PR = EXTI_PR_PR4;
// 软件消抖
for (volatile uint32_t i = 0; i < 720000; i++)
;
// 翻转 PB5
GPIOB->ODR ^= GPIO_ODR_ODR5;
}
}