STM32的所有GPIO都引入了EXTI的外部中断线上,也就是说,所有的I/O口经过配置后都能够触发中断。GPIO和EXTI的连接方式如图4.27所示。
图4.27 GPIO和EXTI连接方式 [2]
从右图可以看出,一共有16个中断线:EXTI0到EXTI15。
每个中断线都对应了从PAx到PHx一共7个GPIO。也就是说,在同一时刻每个中断线只能对应一个GPIO端口的中断,不能够同时对应所有端口的中断事件,但是可以分时复用。
在EXTI中,有三种触发中断的方式。
(1)上升沿触发。当GPIO口的输入电压由低电平变成高电平的瞬间。
(2)下降沿触发。当GPIO口的输入电压由高电平变成低电平的瞬间。
(3)双边沿触发。即GPIO口的输入电压由高电平变成低电平或者由低电平变成高电平时都会触发中断。
根据不同的电路,我们选择不同的触发方式,以确保中断能够被正常触发。
4.3小节已经讲了如何操作点亮和熄灭LED,而本书配套开发板上有5个按键。本节将实现以下功能:
(1)按下KEY0时,LED0灯亮。
(2)按下KEY1时,LED1灯亮。
(3)按下KEY2时,LED0灯灭。
(4)按下KEY3时,LED1灯灭。
为了实现这个功能,根据之前讲的中断原理,可以设置中断源为GPIO中断,触发方式为下降沿触发。中断处理函数对LED0、LED1进行操作,实现亮灭功能。按键的原理图如图4.28所示。
图4.28 按键原理图
KEY0、KEY1、KEY2、KEY3对应的GPIO口分别为GPIOF_9、GPIOF_8、GPIOF_7、GPIOF_6。根据图4.28,我们可以得知,我们对应的外部中断分别为EXTI9、EXTI8、EXTI7、EXTI6。
综上所述,我们编写代码可以按如下流程。
(1)设置GPIOF_9、GPIOF_8、GPIOF_7、GPIOF_6为输入引脚。
(2)将GPIOF_9、GPIOF_8、GPIOF_7、GPIOF_6和EXTI9、EXTI8、EXTI7、EXTI6进行连接,使其I/O引脚做中断引脚功能。
(3)设置EXTI9、EXTI8、EXTI7、EXTI6的中断优先级。
(4)编写中断处理函数,实现LED亮灭操作。
打开Chapter4\02_gpio_exti\mdk\02_gpio_exti.uvprojx工程文件,如图4.29所示。
图4.29 02_gpio_exti.uvprojx工程
其中,main.c是整个程序的入口,代码如下:
main函数通过调用KEY_IO_Init()、KEY_EXTI_Config()、KEY_NVIC_Config()三个函数去实现按键引脚相关的初始化。它们的源码部分在exti_key.c文件。代码如下:
代码中比较重要的部分是NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn。在STM32中,EXTI5、EXTI6、EXTI7、EXTI8、EXTI9这几个中断都连接到同一个中断源中。这几个中断共用一个中断处理函数,我们需要在中断处理函数中判断具体哪个中断是EXTI中断。
STM32的中断向量表在startup_stm32f40_41xxx.s文件69行处,代码如下:
往下110行左右可以看到EXTI9_5的中断处理函数,代码如下:
同样地,读者后续需要使用到哪种中断,都可以通过startup_stm32f40_41xxx.s文件的中断向量表找到中断处理函数名。
上面我们设置好EXTI9_5中断源,并使能中断,接下来需要在EXTI9_5_IRQHandler函数中实现对LED的操作。
EXTI9_5_IRQHandler函数原型在exti_key.c文件80行处,代码如下:
其中有两个比较重要的函数。
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
作用:判断是不是EXTI_Line中断触发。
返回值:RESET表示不是EXTI_Line中断触发;SET表示是EXTI_Line中断触发。
参数:EXTI_Line。外部中断号,取值从EXTI_Line0~EXTI_Line22。
void EXTI_Clear ITPendingBit(uint32_t EXTI_Line)
注意事项 :中断发生并进入中断处理函数,处理完后,需要把对应的中断标志位清零,否则该中断会一直发生并一直产生该中断,导致系统一直重复处理中断。这一点非常重要,后面读者在处理其中的中断的时候,最后一定要清除中断标志位。
本节主要讲解如何使用EXTI外部中断,并初步从源码上分析了STM32中断向量表。同时还实现了EXTI中断处理函数,其中比较重要的是中断清除标志位的操作。本节内容虽然不多,但可以通过本节学会如何使用中断,为后续的章节打下基础。本节有两个重要的知识点:
(1)中断处理函数最后一点要清除中断标志位。
(2)中断处理函数的处理时间一定要短,速度要够快,避免长时间处于中断状态中。