本章我们将介绍如何将
STM32F429
的
IO
口作为外部中断输入。
一、STM32F4 外部中断简介
这里首先介绍STM32F4 IO
口中断的一些基础概念。STM32F4
的每个 IO
都可以作为外部中断的中断输入口,这点也是 STM32F4
的强大之处。STM32F429
的中断控制器支持 22
个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F429
的 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
唤醒事件。
从上面可以看出,STM32F4
供 IO
口使用的中断线只有 16
个,但是 STM32F4
的 IO
口却远远不止 16 个,那么 STM32F4
是怎么把 16 个中断线和 IO
口一一对应起来的呢?于是 STM32
就这样设计,GPIO
的引脚 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)
分别对应中断线 0~15
。这样每个中断线对应了最多 9 个 IO
口,以线 0 为例:它对应了 GPIOA.0
、GPIOB.0
、GPIOC.0
、GPIOD.0
、GPIOE.0
、GPIOF.0
、GPIOG.0
、GPIOH.0
、GPIOI.0
。而中断线每次只能连接到 1 个 IO
口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO
上了。下面我们看看 GPIO
跟中断线的映射关系图:
GPIO
和中断线映射关系是在寄存器SYSCFG_EXTICR1~ SYSCFG_EXTICR4
中配置的。所以我们要配置外部中断,还需要打开 SYSCFG
时钟。
接下来我们来看看使用 HAL
库配置外部中断的一般步骤。HAL
中外部中断相关配置函数和定义在文件 stm32f4xx_hal_exti.h
和 stm32f4xx_hal_exti.c
文件中。
-
使能 IO 口时钟。
首先,我们要使用IO
口作为中断输入,所以我们要使能相应的IO
口时钟。 -
设置 IO 口模式,触发条件,开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系。
在函数HAL_GPIO_Init
中一次性完成。例如我们要设置PA0
链接中断线 0,并且为上升沿触发,代码为:GPIO_InitTypeDef GPIO_Initure; GPIO_Initure.Pin=GPIO_PIN_0; //PA0 GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //外部中断,上升沿触发 GPIO_Initure.Pull=GPIO_PULLDOWN; //默认下拉 HAL_GPIO_Init(GPIOA,&GPIO_Initure);
当我们调用
HAL_GPIO_Init
设置IO
的Mode
值为GPIO_MODE_IT_RISING
(外部中断上升 沿 触 发 ),GPIO_MODE_IT_FALLING
(外部中断下降沿触发)或者GPIO_MODE_IT_RISING_FALLING
(外部中断双边沿触发)的时候,该函数内部会通过判断
Mode
的值来开启SYSCFG
时钟,并且设置IO
口和中断线的映射关系。
因为我们这里初始化的是PA0
,调用该函数后中断线 0 会自动连接到PA0
。如果某个时间,我们又同样的方式初始化了PB0
,那么PA0
与中断线的链接将被清除,而直接链接PB0
到中断线 0。 -
配置中断优先级(NVIC),并使能中断。
我们设置好中断线和GPIO
映射关系,然后又设置好了中断的触发模式等初始化参数。既然是外部中断,涉及到中断我们当然还要设置NVIC
中断优先级。设置中断线 0 的中断优先级并使能外部中断 0 的方法为:HAL_NVIC_SetPriority(EXTI0_IRQn,2,1); //抢占优先级为 2,子优先级为 1 HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线 0
-
编写中断服务函数。
我们配置完中断优先级之后,接着要做的就是编写中断服务函数。中断服务函数的名字是在HAL
库中事先有定义的。这里需要说明一下,STM32F4
的IO
口外部中断函数只有 7 个,分别为:void EXTI0_IRQHandler(); void EXTI1_IRQHandler(); void EXTI2_IRQHandler(); void EXTI3_IRQHandler(); void EXTI4_IRQHandler(); void EXTI9_5_IRQHandler(); void EXTI15_10_IRQHandler();
中断线
0-4
每个中断线对应一个中断函数,中断线5-9
共用中断函数EXTI9_5_IRQHandler
,中断线10-15
共用中断函数EXTI15_10_IRQHandler
。一般情况下,我们可以把中断控制逻辑直接编写在中断服务函数中,但是HAL
库把中断处理过程进行了简单封装。 -
编写中断处理回调函数 HAL_GPIO_EXTI_Callback
HAL
库为了用户使用方便,它提供了一个中断通用入口函数HAL_GPIO_EXTI_IRQHandler
,在该函数内部直接调用回调函数HAL_GPIO_EXTI_Callback
。我们可以看看HAL_GPIO_EXTI_IRQHandler
函数定义:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(