第6章 STM32F4外部中断简介

第六章 STM32F4外部中断简介

1. 导入

STM32F4 的每个 IO 都可以作为外部中断的中断输入口,这点也是 STM32F4 的强大之处。 STM32F407 的中断控制器支持 23个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F407 的 23 个外部中断为:

  • 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跟中断线的映射关系图:

屏幕截图 2024 09 11 102727

2. 配置外部中断步骤

2.1 使能 IO 口时钟,初始化 IO 口为输入

首先,我们要使用 IO 口作为中断输入,所以我们要使能相应的 IO 口时钟,具体的操作方法跟我们按键实验是一致的,这里就不做过多讲解。

2.2 设置 IO 口模式,触发条件, 开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系。

该步骤如果我们使用标准库那么需要多个函数分部实现。而当我们使用 HAL 库的时候,则都是在函数 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。

2.3 配置中断优先级(NVIC),并使能中断

我们设置好中断线和 GPIO 映射关系,然后又设置好了中断的触发模式等初始化参数。既然是外部中断,涉及到中断我们当然还要设置 NVIC 中断优先级。这个在前面已经讲解过,这里我们就接着上面的范例, 设置中断线 0 的中断优先级并使能外部中断 0 的方法为:

HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 1);// 抢占优先级为 2,子优先级为 1
HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 使能中断线 2

2.4 编写中断服务函数

我们配置完中断优先级之后,接着要做的就是编写中断服务函数。中断服务函数的名字是在 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 库把中断处理过程进行了简单封装,请看下面步骤 5 讲解。

2.5 编写中断处理回调函数HA_GPIO-EXTI-Callback

在使用 HAL 库的时候,我们也可以跟使用标准库一样,在中断服务函数中编写控制逻辑。但是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(GPIO_Pin);
    }
}

该函数实现的作用非常简单,就是清除中断标志位,然后调用回调函数HAL_GPIO_EXTI_Callback()实现控制逻辑。所以我们编写中断控制逻辑将跟串口实验类似,在中断服务函数中直接调用外部中断共用处理函数 HAL_GPIO_EXTI_IRQHandler,然后在回调函数 HAL_GPIO_EXTI_Callback 中通过判断中断是来自哪个 IO 口编写相应的中断服务控制逻辑。

3. 流程小结

下面我们再总结一下配置 IO 口外部中断的一般步骤:

  1. 使能 IO 口时钟。

  2. 调用函数 HAL_GPIO_Init 设置 IO 口模式,触发条件,使能 SYSCFG 时钟以及设置 IO口与中断线的映射关系。

  3. 配置中断优先级(NVIC),并使能中断

  4. 在中断服务函数中调用外部中断共用入口函数 HAL_GPIO_EXTI_IRQHandler。

  5. 编写外部中断回调函数 HAL_GPIO_EXTI_Callback。


2024.9.29 第一次修订,后期不再维护

2024.12.23 简化内容

posted @ 2024-09-29 10:48  hazy1k  阅读(16)  评论(0编辑  收藏  举报