一、引入
设想有这样一个需求:红色小灯以2s为周期循环亮灭闪烁,并且当检测到Key1按下后翻转绿色小灯亮灭。
我们新建一个工程,分配引脚,并且写以下代码刷板运行。
可以看到板子运行的结果很奇怪。除非长按Key1,绿色小灯几乎不受控制。
这实际上是因为在while(1)循环的过程中,大部分时间都在HAL_Delay(2000),真正给到Key1的判断时间很短。
那么有没有办法让STM32即使正在执行Delay这种耗时的任务,也能快速相应按键按下这种突发状况呢?这就需要我们用到“中断”了。
二、外部中断
在IOC文件中更改原先的PE3引脚类型为“EXTI_13"。“EXTI"是"External Interrupt”,即外部中断。
再移动到旁边的GPIO选项卡,可以看到PE3对应的GPIO mode也发生了变化。
所谓上升沿就是某个GPIO口低电平到高电平的变化,下降沿就是高电平到低电平的变化。
我们选择下降沿触发中断,并选择下面的上拉输入,这样当Key1按下,PE3处的电平就会由高电平变为低电平,从而进入中断任务。
接着,我们在NVIC选项卡中勾选上新建的中断向量。
然后我们保存并生成代码,在下图的目录位置中找到控制中断相应的文件。
it代表interrupt相关
进入文件,在该文件最下方的"xxxx_IRQHandler"就是CubeMX自动生成的中断控制函数。
STM32的运行过程现在可以用下图表示:
从图中也能看出来,我们需要保证中断函数的过程尽可能短,这样才不会影响正常的执行流程。
那么,我们在第一个注释对中写下控制小灯翻转亮灭的代码。
进行了软件消抖
编译刷板,结果如下:
正常运行的小灯在按下Key1之后直接停止运行,这是怎么回事呢?
其实,这是因为HAL_Delay()函数依赖于System tick timer(系统滴答)时钟中断。在NVIC选项卡中,可以发现该中断优先级比我们的EXTI中断优先级更低,这也就导致了HAL_Delay()函数无法在我们的EXTI中断函数中运行,程序也就卡死在这行代码上了。
知道了这一点,我们只需要调整优先级,让系统滴答优先级高于EXTI优先级,就能使程序正常运行了。
(编译刷板)
三、详细原理
这次实战中我们接触到了EXIT、NVIC、中断向量、中断优先级等等STM32的概念。通过下面的视频,我们可以了解到这些概念在STM32内部实现的原理。