一、什么是中断?
想象一下你正在家里做饭,突然门铃响了,你听到门铃声后,会暂时放下手中的事情(比如炒菜),去开门看看是谁。在这个例子中,门铃声就是一个"中断",它打断了你原本在做的事情(炒菜)。
在STM32(一个常用的微控制器)中,中断也是类似的概念。STM32有很多功能,比如控制LED灯、读取传感器数据、与电脑通信等。当STM32正在执行某个任务时,如果外部发生了某个事件(比如一个按钮被按下、一个传感器值发生了变化),这个事件就会产生一个"中断信号",告诉STM32:"嘿,有事情发生了,你需要停下来看看!"
STM32在接收到中断信号后,会暂时放下当前的任务(就像你放下炒菜的铲子去开门一样),然后跳转到专门处理这个中断的程序(我们称之为"中断服务程序")去执行。在这个中断服务程序中,STM32会处理这个中断事件,比如读取按钮的状态、处理传感器的数据等。处理完中断事件后,STM32会返回到之前被打断的任务中,继续执行。
STM32支持多种类型的中断,比如外部IO中断 (比如按钮被按下)、定时器中断 (比如每隔一段时间就触发一次)、串口通信中断 (比如接收到电脑发来的数据)等。每种中断都可以设置不同的优先级,这样当多个中断同时发生时,STM32会先处理优先级高的中断。
二、外部中断
了解了什么是中断以后,我们来介绍一下STM32的外部中断,此处以STM32F429为例,它拥有22个外部中断,每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。这22个中断分别为:
EXTI 线 0~15 :对应外部 IO 口的输入中断。
EXTI 线 16 :连接到 PVD 输出。
EXTI 线 17 :连接到 RTC 闹钟事件。
EXTI 线 18 :连接到 USB OTG FS 唤醒事件。
EXTI 线 19 :连接到以太网唤醒事件。
EXTI 线 20 :连接到 USB OTG HS(在 FS 中配置)唤醒事件。
EXTI 线 21 :连接到 RTC 入侵和时间戳事件。
EXTI 线 22:连接到 RTC 唤醒事件。
从上面看到EXTI线0-15对应了外部的IO口中断,但是那么多的IO口,是如何对应这16个EXTI线的呢?
STM32是这么设计的,PA0,PB0,PC0...PI0(也就是所有的GPIO0),对应了EXTI0。然后PA1,PB1,PC1...PI1(所有的GPIO1),对应了EXTI1。这样依次类推,一直到EXTI15。中断可以监控GPIO的上升沿或者下降沿并跳转到我们写的对应的函数,注意的是:一个EXTI线中断只能给一个引脚使用,比如给PA0加了外部中断以后,就不能再给PB0加外部中断了。
三、代码实现
比如这里我们给GPIO_PE3加一个上升沿触发的中断。
1.使能GPIO
cpp
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE时钟
//PE3 输入
GPIO_Initure.Pin=GPIO_PIN_3; //PE3
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //上升沿触发
GPIO_Initure.Pull=GPIO_NOPULL; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOE,&GPIO_Initure);
//给PE3加上升沿中断
HAL_NVIC_SetPriority(EXTI3_IRQn,4,2); //抢占优先级为4,子优先级为2
HAL_NVIC_EnableIRQ(EXTI3_IRQn); //使能中断线3
2.中断函数
cpp
void EXTI3_IRQHandler(void)
{
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_3) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3);
Gather_FLAG=1;
}
}
这段代码里面,如果进了中断,先清除外部中断位,然后改变了一个全局变量的标识符,我们可以通过标识符的改变在其它运行的代码中继续我们耗时的工作,切忌不要在中断里面进行耗时工作。
注意,在编写中断服务程序时,一定要确保在中断处理完成后清除相应的中断标志位,否则中断可能会持续触发,导致程序无法正常工作。