原子哥给出的概念是这样的:打断CPU正常执行的程序,转而处理紧急程序,然后返回原暂停的程序继续运行,就叫中断。
当发生中断时,当前执行的程序会被暂时中止,进而进入中断处理函数对中断事件进行处理,处理完毕后,又回到之前被暂停的程序继续执行。
使得CPU在能够执行主程序的同时,对重要事件做出及时的响应,提高CPU的工作效率,高效处理紧急程序,不会一直占用CPU资源。
1. 实时控制:在确定时间内对相应事件作出响应,如:温度监控
2. 故障处理:检测到故障,需要第一时间处理,如:电梯门夹人了
3. 数据传输:不确定数据何时会来,如:串口数据接收
信号从外部进来,通过GPIO输入,来到AFIO将GPIO引脚映射到EXTI线上, 通过EXTI进行中断屏蔽或上升/下降沿触发中断,之后来到NVIC中断总管家进行优先级判断, CPU以优先级从高到低处理中断。
NVIC(Nested vectored interrupt controller),嵌套向量中断控制器,属于内核(M3/4/7)。
NVIC支持256个中断(16内核+240外部),支持256个优先级,允许裁剪!NVIC是一种中断控制器,用于管理中断系统和中断请求。
ST公司把256个优先级进行了裁剪(用不到那么多),变成了16个中断优先级。
STM32型号 | 内核中断 | 外部中断 | 中断优先级 |
---|---|---|---|
STM32F103xx | 10 | 60 | 16 |
STM32F407xx | 10 | 82 | 16 |
STM32F429xx | 10 | 91 | 16 |
不管是内核中断还是外部中断,都有对应中断服务函数,那么问题来了,什么是中断服务函数呢?中断服务函数就是中断的入口,当某一个中断发生之后,需要进入中断服务函数当中执行相应的中断程序,中断服务函数又被定义在了中断向量表里,追根溯源那么什么又是中断向量表呢?
首先啊,定义一块固定的内存,以4字节对齐(STM32是32位单片机,1字节是8位,所以32位就是4字节),用于存放各个中断服务函数的首地址。
中断向量表定义在启动文件(.s文件)中,当发生中断时,CPU会自动执行对应的中断服务函数,
当正常执行程序时,CPU一直都被main函数占用,当发生中断时,这些中断服务函数会抢夺CPU的使用权,如下图所示。
OK,现在我们在工程里面找到启动文件,如下图所示,__Vectors就是中断向量表开始的位置。 上部分是内核中断有10个,下面是外部中断服务函数有60个。
在《STM32F103系列参考手册》9.1.2 中断和异常向量 里有对中断向量表的说明,深色背景的是内核中断,位置从0开始的是外部中断,总共有60个外部中断服务函数。
NVIC相关寄存器 | 位数 | 寄存器个数 | 备注 |
---|---|---|---|
中断使能寄存器(ISER) | 32 | 8 | 每个位控制一个中断 |
中断除能寄存器(ICER) | 32 | 8 | 每个位控制一个中断 |
应用程序中断及复位控制寄存器(AIRCR) | 32 | 1 | 位[10:8]控制优先级分组 |
中断优先级寄存器(IPR) | 8 | 240 | 8个位对应一个中断,而STM32只使用高4位 |
在《ARM Cortex-M3与Cortex-M4权威指南》的 7.8小节对NVIC寄存器有详细介绍;
当外部发中断,进入到NVIC,首先由中断使能和失能寄存器进行配置,来控制这些中断开与关,如上图所示,中断1失能,中断2,3,4使能,就来到了中断优先级寄存器(IPR),IPR对中断2-4根据对应的优先级进行判断,优先级越高的中断先得到CPU的控制权。
1,抢占优先级(pre):高抢占优先级可以打断正在执行的低抢占优先级中断
2,响应优先级(sub):当抢占优先级相同时,响应优先级高的先执行,但是不能互相打断
3,抢占和响应都相同的情况下,自然优先级越高的,先执行
4,自然优先级:中断向量表的优先级
5,数值越小,表示优先级越高
举例说明:优先级分组为1,有1位抢占优先级,3位响应优先级,那么抢占优先级就有2^1=2个,响应优先级有2^3=8个。
注意:一个工程中,一般只设置一次中断优先级分组。
中断优先级举例(假设分组是2)
编号 | 自然优先级 | 对应外设 | 抢占优先级 | 响应优先级 | 执行顺序 |
---|---|---|---|---|---|
3 | 10 | RTC | 2 | 1 | 2 |
6 | 13 | EXTI0 | 3 | 0 | 4 |
7 | 14 | EXTI1 | 2 | 0 | 1 |
-1 | 6 | Systick | 3 | 0 | 3 |
由表中可知RTC和EXTI1的抢占优先级都为2,但是响应优先级不同,EXTI1的响应优先级为0,RTC的响应优先级为1,数值小的先执行,所以EXTI1是第一个执行,第二个是RTC;而EXTI0和Systick的抢占优先级和响应优先级都相同,这个时候就要看自然优先级,数值越小,就先执行,所以systick是第三个执行,第四个是EXTI0。
而高抢占优先级可以打断正在执行的低抢占优先级中断,比如EXTI0/Systick正在执行,这时RTC就可以打断它先执行。但是响应优先级高的不能打断响应优先级低的。
1. 设置中断分组 HAL_NVIC_SetPriorityGrouping
2. 设置中断优先级 HAL_NVIC_SetPriority
3. 使能中断 HAL_NVIC_EnableIRQ
主线任务:学习中断EXTI主要掌握EXTI线0~15与GPIO 引脚的对应关系
External(Extended))interrupt/event Controller,外部(扩展)中断事件控制器,其中包含20个产生事件/中断请求的边沿检测器,即总共:20条EXTI线(F1系列)
中断和事件的理解:
中断:要进入NVIC,有相应的中断服务函数,需要CPU处理
事件:不进入NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC
F1/F4/F7系列
每条EXTI线都可以单独配置:选择类型(中断或者事件)、触发方式(上升沿,下降沿或者双边沿触发)、支持软件触发、开启/屏蔽、有挂起状态位
这里的输入线就是EXTI线,这些输入线可以通过寄存器设置为任意一个 GPIO,从《STM32F103数据手册》中我们得知,F1系列有20根,非互联型有19根;
接下来我们分析下这部分框图:
首先我们来看第①部分:信号从某一条EXTI线输入进来,经过边沿检测电路,到达或门,那么信号如何通过边沿检测电路呢?就由上升沿触发选择寄存器和下降沿触发选择寄存器这俩寄存器决定了,这俩都是32位寄存器,但它们的有效位却是由EXTI线的条数决定的,eg:F1有20条EXTI线,那么上升沿&下降沿触发选择寄存器就是20位有效。当上升沿触发选择寄存器的对应位置1,此时输入线来了一个上升沿,那么允许该信号通过边沿检测电路,而要是此时来一个下降沿,那就不允许它通过;同理,当下降沿触发选择寄存器的对应位置1,此时输入线来了一个下降沿,那么就允许该信号通过边沿检测电路,而要是此时来一个上升沿,那就不允许它通过;
第②部分:当信号通过边沿检测电路来到或门,此时或门一个输入为1,那么输出也就为1(或门:有1为1),而不用去理会软件中断事件寄存器的状态,从而实现硬件触发中断;而如果边沿检测电路是0,此时决定或门输出1的就是软件中断事件寄存器了,从而实现软件触发中断。
第③部分: 不管是通过软件中断还是硬件中断触发,或门的输出都是1,那么请求挂起寄存器的对应位也置1,这时与门的一个输入就为1,要想与门输出为1,必须中断屏蔽寄存器的对应位也为1才行,这样才能把信号输入到NVIC中断控制器,如果中断屏蔽寄存器的对应位为0,那么与门输出为0,也就阻止了信号输入到NVIC中断控制器中,也就无法产生中断。所以,中断屏蔽寄存器的作用就体现出来了!!通过控制中断屏蔽寄存器(EXTI_IMR)来控制中断的产生。
第④部分:同理,事件屏蔽寄存器对应位为1时,信号会通过与门和脉冲发生器输入到某个外设,从而产生事件,控制其他外设实现某种功能。
具体细致的讲解大家可以观看“正点原子”这部分 :第58讲 入门篇-EXTI工作原理(F1 F4 F7)_哔哩哔哩_bilibili
Alternate Function IO,即复用功能IO,主要用于重映射和外部中断映射配置。
我们主要用到AFIO_EXTICR1~4这四个寄存器,用来配置EXTI中断线0~15对应的IO口。
也就是说,EXTI0对应PA~PG的引脚0,而EXTI0[3:0]写入的值对应的是PA还是PB、PC...PG端口号;
EXTI x ----->引脚 0 ~ 15
EXTI x [3:0]------->PA~PG端口号
USART/TIM/SPI等产生的外设中断,不会进入EXTI,而是由外设自己的寄存器配置,开启相应的外设中断,直接进入NVIC。
发生中断,进入中断服务函数,在中断服务函数里面调用HAL库中断处理公用函数,中断处理公用函数里面用来进行异常处理,清中断标志,以及调用各种数据处理回调函数(发生什么中断,调用什么回调函数)。
下篇笔记是实战部分,通过按键实现外部中断控制LED灯亮灭。
本篇完。
本人博客仅代表个人见解方便记录成长笔记。
若有不足,请指出,感谢您的阅读!