【自学嵌入式:stm32单片机】EXTI外部中断

EXTI外部中断

中断系统

  • 中断:在主程序运行过程中,出现了特定的中断触发条件(中断使得CPU暂停当前正在运行的程序,转而去处理中断程序源),处理完成后又返回原来被暂停的位置继续运行
  • 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
  • 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回

中断执行流程

image

STM32中断

  • 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设
  • 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

内核中断

位置 优先级 优先级类型 名称 说明 地址
- - - 保留 0x0000_0000
-3 固定 Reset 复位 0x0000_0004
-2 固定 NMI 不可屏蔽中断
RCC时钟安全系统(CSS)联接到NMI向量
0x0000_0008
-1 固定 硬件失效(HardFault) 所有类型的失效 0x0000_000C
0 可设置 可设置 存储管理(MemManage) 存储器管理 0x0000_0010
1 可设置 可设置 总线错误(BusFault) 预取指失败,存储器访问失败 0x0000_0014
2 可设置 可设置 错误应用(UsageFault) 未定义的指令或非法状态 0x0000_0018
- - - 保留 0x0000_001C
~0x0000_002B
3 可设置 可设置 SVCcall 通过SWI指令的系统服务调用 0x0000_002C
4 可设置 可设置 调试监控(DebugMonitor) 调试监控器 0x0000_0030
- - - 保留 0x0000_0034
5 可设置 可设置 PendSV 可挂起的系统服务 0x0000_0038
6 可设置 可设置 SysTick 系统嘀嗒定时器 0x0000_003C

外设中断

位置 优先级 优先级类型 名称 说明 地址
0 7 可设置 WWDG 窗口定时器中断 ,窗口看门狗,用来检测程序运行的中断,如果程序卡死了,窗口看门狗就会申请中断 0x0000_0040
1 8 可设置 PVD 连到EXTI的电源电压检测(PVD)中断,电源电压不足,PVD会申请中断,是不是电池没电了,要赶紧保存一下重要数据 0x0000_0044
2 9 可设置 TAMPER 侵入检测中断 0x0000_0048
3 10 可设置 RTC 实时时钟(RTC)全局中断 0x0000_004C
4 11 可设置 FLASH 闪存全局中断 0x0000_0050
5 12 可设置 RCC 复位和时钟控制(RCC)中断 0x0000_0054
6 13 可设置 EXTI0 EXTI线0中断 0x0000_0058
7 14 可设置 EXTI1 EXTI线1中断 0x0000_005C
8 15 可设置 EXTI2 EXTI线2中断 0x0000_0060
9 16 可设置 EXTI3 EXTI线3中断 0x0000_0064
10 17 可设置 EXTI4 EXTI线4中断 0x0000_0068
11 18 可设置 DMA1通道1 DMA1通道1全局中断 0x0000_006C
12 19 可设置 DMA1通道2 DMA1通道2全局中断 0x0000_0070
13 20 可设置 DMA1通道3 DMA1通道3全局中断 0x0000_0074
14 21 可设置 DMA1通道4 DMA1通道4全局中断 0x0000_0078
15 22 可设置 DMA1通道5 DMA1通道5全局中断 0x0000_007C
16 23 可设置 DMA1通道6 DMA1通道6全局中断 0x0000_0080
17 24 可设置 DMA1通道7 DMA1通道7全局中断 0x0000_0084
18 25 可设置 ADC1_2 ADC1和ADC2全局中断 0x0000_0088
19 26 可设置 USB_HP_CAN_TX USB高优先级或CAN发送中断 0x0000_008C
20 27 可设置 USB_LP_CAN_RX0 USB低优先级或CAN接收0中断 0x0000_0090
21 28 可设置 CAN_RX1 CAN接收1中断 0x0000_0094
22 29 可设置 CAN_SCE CAN SCE中断 0x0000_0098
23 30 可设置 EXTI9_5 EXTI线[9:5]中断 0x0000_009C
24 31 可设置 TIM1_BRK TIM1刹车中断 0x0000_00A0
25 32 可设置 TIM1_UP TIM1更新中断 0x0000_00A4
26 33 可设置 TIM1_TRG_COM TIM1触发和通信中断 0x0000_00A8
27 34 可设置 TIM1_CC TIM1捕获比较中断 0x0000_00AC
28 35 可设置 TIM2 TIM2全局中断 0x0000_00B0
29 36 可设置 TIM3 TIM3全局中断 0x0000_00B4
30 37 可设置 TIM4 TIM4全局中断 0x0000_00B8
31 38 可设置 I2C1_EV I²C1事件中断 0x0000_00BC
32 39 可设置 I2C1_ER I²C1错误中断 0x0000_00C0
33 40 可设置 I2C2_EV I²C2事件中断 0x0000_00C4
34 41 可设置 I2C2_ER I²C2错误中断 0x0000_00C8
35 42 可设置 SPI1 SPI1全局中断 0x0000_00CC
36 43 可设置 SPI2 SPI2全局中断 0x0000_00D0
37 44 可设置 USART1 USART1全局中断 0x0000_00D4
38 45 可设置 USART2 USART2全局中断 0x0000_00D8
39 46 可设置 USART3 USART3全局中断 0x0000_00DC
40 47 可设置 EXTI15_10 EXTI线[15:10]中断 0x0000_00E0
41 48 可设置 RTCAlarm 连到EXTI的RTC闹钟中断 0x0000_00E4
42 49 可设置 USB唤醒 连到EXTI的从USB待机唤醒中断 0x0000_00E8
43 50 可设置 TIM8_BRK TIM8刹车中断 0x0000_00EC
44 51 可设置 TIM8_UP TIM8更新中断 0x0000_00F0
45 52 可设置 TIM8_TRG_COM TIM8触发和通信中断 0x0000_00F4
46 53 可设置 TIM8_CC TIM8捕获比较中断 0x0000_00F8
47 54 可设置 ADC3 ADC3全局中断 0x0000_00FC
48 55 可设置 FSMC FSMC全局中断 0x0000_0100
49 56 可设置 SDIO SDIO全局中断 0x0000_0104
50 57 可设置 TIM5 TIM5全局中断 0x0000_0108
51 58 可设置 SPI3 SPI3全局中断 0x0000_010C
52 59 可设置 UART4 UART4全局中断 0x0000_0110
53 60 可设置 UART5 UART5全局中断 0x0000_0114
54 61 可设置 TIM6 TIM6全局中断 0x0000_0118
55 62 可设置 TIM7 TIM7全局中断 0x0000_011C
56 63 可设置 DMA2通道1 DMA2通道1全局中断 0x0000_0120
57 64 可设置 DMA2通道2 DMA2通道2全局中断 0x0000_0124
58 65 可设置 DMA2通道3 DMA2通道3全局中断 0x0000_0128
59 66 可设置 DMA2通道4_5 DMA2通道4和DMA2通道5全局中断 0x0000_012C

表格中的EXTI0~EXTI4,下面的EXTI9_5~ EXTI15_10是本节要用到的外部中断资源,表右侧有中断地址,程序中的中断函数的地址是由编译器来分配的,是不固定的,中断跳转由于硬件的限制,只能跳到固定的地址执行程序,所以为了能让硬件跳转到一个不固定的中断函数里,这里就需要在内存中定义一个地址的列表,这个列表地址是固定的,中断发送后,就跳到这个固定位置,然后在这个固定位置,由编译器,再加上一条跳转到中断函数的代码,这样中断跳转就可以跳到任意位置,这个中断地址的列表,就叫中断向量表
【注】用AI解释一下就是:
咱们用生活里的事儿打个比方,你就明白了:

假设 STM32 芯片是一个 “小区”,里面有很多 “住户”—— 就是你写的各种程序(包括中断函数)。这些住户今天可能住 201,明天可能搬去 302,地址不固定(就像你说的,中断函数地址由编译器分配,不固定)。

现在小区里突然发生了 “突发事件”(比如着火、漏水,对应芯片里的 “中断”,比如按键按下、定时器到点),这时候需要专门的人来处理(就是 “中断函数”)。但小区的 “保安”(硬件)比较死板,他只认识小区里几个固定的 “岗亭”(固定地址),遇到事儿了只能先跑到岗亭,不能直接去找人(硬件限制,只能跳固定地址)。

那怎么让保安找到真正处理事儿的人呢?小区物业就搞了个 “岗亭列表”(中断向量表):每个岗亭都是固定位置(比如 1 号岗在大门左,2 号岗在 3 号楼底),而且每个岗亭里都贴了一张纸条,写着 “处理 XX 事件的人现在在 XXX 地址”(编译器提前写好的跳转指令)。

所以流程就是:

发生突发事件(中断);
保安(硬件)只能先跑到对应的固定岗亭(向量表的固定地址);
岗亭里的纸条(编译器写的跳转代码)告诉保安,真正处理的人在哪个不固定的地址(中断函数);
保安再跑去那个地址,让处理的人干活。

这个 “岗亭列表”,就是中断向量表。它的作用就是用固定的 “中间站”,连接硬件只能认的固定地址和不固定的中断函数地址。

我们用C语言编程是不需要管这个中断向量表的,因为编译器都帮我们做好了

NVIC基本结构

image
NVIC是一个内核外设,是CPU的助手,STM32中断非常多,如果把这些线都引到CPU上,CPU还得引出很多线进行适配,设计上就很麻烦,并且如果很多中断同时申请,或者中断很懂产生了拥堵,CPU也会很难处理,毕竟CPU主要是用来运算的,中断分配的任务就放到别的地方,所以NVIC就出现了,NVIC有很多输入口,都接着中断线路,每条线写着\(n\)的意思是一个外设可能会同时占用多个中断通道,所以这里有\(n\)条线,NVIC根据每个中断的优先级分配中断的先后顺序,之后,通过右边这一个输出口告诉CPU该处理哪个中断,对于中断先后顺序分配的任务,CPU不需要知道。

NVIC优先级分组

  • NVIC的中断优先级由优先级寄存器的4位(0~15)决定(16个优先级,值越小,优先级越高),这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级,响应优先级可以处理非常紧急的中断(插队)
  • 抢占优先级高的可以中断嵌套(可以不等上一个中断处理完,先处理这个非常紧急的中断),响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
分组方式 抢占优先级 响应优先级
分组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

【注】让AI解释一下:
“分组” 的核心:定两部分各占几位
这 4 位怎么分给 “抢占” 和 “响应”?这就是 “分组” 要做的事。STM32 规定了 5 种分组方式(编号 0~4),比如:

分组 0:抢占优先级占 0 位,响应优先级占 4 位。
(意思是:所有中断抢占优先级都一样,只能靠响应优先级排序,且响应优先级有 16 级)
分组 2:抢占优先级占 2 位,响应优先级占 2 位。
(抢占优先级有 4 级:0~3;响应优先级也有 4 级:0~3)
分组 4:抢占优先级占 4 位,响应优先级占 0 位。
(只有抢占优先级,16 级;响应优先级无效)
举个例子:分组 2 的情况
假设系统用了分组 2(2 位抢占,2 位响应):

中断 A:抢占优先级 0(最高),响应优先级 0
中断 B:抢占优先级 1,响应优先级 0
中断 C:抢占优先级 0,响应优先级 1

规则如下:

A 和 B 同时来:A 抢占优先级更高,先处理 A(A 能打断 B)。
A 和 C 同时来:抢占优先级相同,看响应优先级,A 响应更高,先处理 A。
正在处理 B 时来了 A:A 抢占优先级更高,会打断 B,先处理 A,A 结束后再接着处理 B。
正在处理 A 时来了 C:两者抢占优先级相同,C 不能打断 A,只能等 A 处理完再执行 C。

EXTI

  • EXTI(Extern Interrupt)外部中断
  • EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
  • 支持的触发方式:上升沿/下降沿/双边沿(上升沿和下降沿都行)/软件触发(写代码主动触发也行)
  • 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断 (比如说,PA1和PB1不能同时中断,简单说:同号引脚(Pin1)的不同端口(PA/PB/PC...)不能同时配置触发中断(因为共用一条线),但可以切换配置分别使用。
  • 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒 (除了16个GPIO引脚,其他都是来“蹭网”的,用来唤醒STM32,借助它发生电平变化就中断的原理,要传输数据,唤醒休眠的stm32)
  • 触发响应方式:中断响应/事件响应 (如果选择触发事件,那外部中断的信号就不会通向CPU了,触发其他外设操作)

EXTI基本结构

image
外部中断9-5和外部中断15-10触发同一个中断函数,在编程的时候,我们在这两个中断函数里,需要再根据标志位区分到底是哪个中断进来的

AFIO复用IO口

image

  • AFIO主要用于引脚复用功能的选择和重定义(引脚默认定义的功能重新定义)
  • 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择

EXTI框图

image

软件中断和硬件中断接在或门上,任意为1都能触发中断,然后兵分两路,触发中断首先会置体格挂起寄存器,这相当于是一个中断标志位,可以读取这个寄存器判断是哪个通道触发的中断,如果中断挂起寄存器值1就继续向左走,和中断屏蔽寄存器共同进入一个与门,然后是NVIC中断控制器

posted @ 2025-08-11 15:22  秦瑞迁  阅读(88)  评论(0)    收藏  举报