4.中断&外部中断

181 阅读6分钟

image.png

嵌入式芯片中可能产生中断的原因(不止这些):

image.png

1.外部中断(GPIO电平变化产生的中断)

首先我们来了解一下GPIO电平变化产生的中断也叫做外部中断(EXTI)--EXTernal Interrupt

外部中断,就是源于外部产生的中断,STM32芯片的外部也就是这些引脚

目标需求:

image.png

步骤:

1.1创建工程

名字为interrupt,过程略

1.2设置引脚

原理图:

image.png

image.png

image.png

保存然后生成代码

1.3书写代码

// 红色小灯循环亮灭的代码

HAL_GPIO_WritePin(LED_RED_GPIO_Port,LED_RED_Pin,GPIO_PIN_SET);

HAL_Delay(2000);

HAL_GPIO_WritePin(LED_RED_GPIO_Port,LED_RED_Pin,GPIO_PIN_RESET);

HAL_Delay(2000);

// 轮询方式检测按键并翻转绿色小灯状态,会发现这个其实不起作用,原因就是HAL_Delay(2000)占比时长太高,以至于我们的其他程序有效时间很少

// if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){

// HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port,LED_GREEN_Pin);

// while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET);

// }

image.png

image.png

1.4设置引脚

因为上述问题,我们需要把PB12更改为GPIO_EXTI12,也就是外部中断线12,这个具体概念下一章将会了解

image.png

然后重新设置用户标签

image.png

然后我们详细设置引脚配置

image.png

image.png

image.png

image.png

因此我们选择下降沿触发中断

image.png

1.5中断控制器

NVIC和中断向量的细节,在下一章会谈到,现在只需要知道加上这步操作

image.png

image.png

image.png

1.6书写代码

image.png

// 翻转绿灯亮灭

HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port,LED_GREEN_Pin);

1.7仿真

image.png

在多次尝试之后发现按键仍没有达到理想的效果,是因为按键抖动本次很难使用电容消除,所以我们需要使用软件进行消除按键抖动

image.png

image.png

此时编译运行之后还是有问题的,是因为多个中断的优先级问题,HAL_Delay函数依赖了一个叫做Systyem tick timer(系统滴答)的中断,这个中断可以为其提供1ms的时钟周期,但是他的优先级比我们所触发的优先级高一些,导致不能在我们的中断函数中运行,程序就会卡死,因此我们需要修改优先级:

image.png

修改完成之后重新编译运行就可以成功达到理想的要求了。

image.png

注意,上述的代码只能作为学习案例,在实际的开发中我们是很不推荐这样进行操作的。

上一个视频当中,我们挖了几个坑,包括NVIC EXIT 中断向量以及中断优先级,于是我们来详细了解这些概念。

2.EXTI(外部中断)

首先来到按键的原理图:

image.png

我们来看看PB12这个引脚的内部:

image.png

image.png

电流继续移动就会到达下面的图结构,我们将其称之为外部中断/事件控制器:

image.png

而类似这样的结构,在我们使用的STM32F1系列的芯片中共有19个,这19个外部中断控制器共用一套寄存器,图中的连线其实总共有19组,每个外部中断都对应着其中的一组线路,所以也可以将其称之为外部中断线:

image.png

这19个外部中断线的前16个,也就是EXTI0-EXTI15,分别对应其相应的GPIO口

image.png

在接下来的语境中,高电平与1等效,低电平与0等效

image.png

下面这一个配置是接受上升沿触发器和下降沿触发器的,根据配置,决定是否向后输出一个高电平信号:

image.png

如我们在之前的练习中选择了下降沿,那么下降沿接受到的时候就会往后面发送一个高电平

image.png

在我们理解了之后,软件中断事件寄存器也可以暂时忽略不计,接下来请求挂起寄存器将会是一个很重要的点。

它会将接受到信号的对应位置将其置为1,如之前的EXTI12(外部中断线12),就会把寄存器的第12位置为1:

image.png

然后会把这个信号通过与门发送到NVIC(中断控制器),与门的特性是只有两个都为1的时候,结果才为1,因此与门的另一个输入中断屏蔽寄存器,只有对应位置上为1的时候信号才能够进入到NVIC:

image.png

而将中断屏蔽寄存器对应位置设置为1的时候就是我们在CubeMX中将对应引脚设置为中断的时候,就已经帮我们生成对应的代码了。

3.NVIC(嵌套向量中断控制器)

这个东西的主要作用就是掌管这样一张中断向量表:

image.png

中断向量的意思就是指名称指向一个函数,在外部所有的中断函数中只有EXTI0-EXTI4拥有自己的中断向量,此外如上图所示。

当上述我们的电信号继续传递的时候,就会通过中断向量表进行查找到适用于哪个函数,因此之前的步骤之中我们就是适用EXTI15_10_IRQHandler。

需要注意的是,NVIC是一直监控引脚是否产生中断的,当EXTI15_10_IRQHandler结束之后,如果引脚还是处于中断激活状态,就会再次运行EXTI_15_10_Handler。因此,我们有必要在代码之中将引脚中断手动关闭。

image.png

这个函数的作用可以清除请求挂起寄存器。

如果同时发生多个中断,我们就会涉及到中断优先级了。

4.中断优先级

中断优先级可以分为抢占优先级和响应优先级,数字越小优先级越高。

image.png

image.png

如果抢占式优先级和响应式优先级相同,这种情况下一般是程序员不会考虑优先级才会写成一样,否则应该优先考虑设置成为不一样的优先级。那么如果真的发生了这种情况,那么系统会按照定义事件的顺序进行执行。

image.png

image.png

STM32为每个中断向量准备了4个二进制位来存储中断优先级信息,在CubeMX中我们可以设置任意位数用来表示抢占优先级和响应优先级。默认情况下,4位都是用来设置抢占优先级。这时每个中断向量的抢占优先级都可以设置为0-15。

image.png