外部中断

芯片外部的 GPIO 输入中断, 通过检测 GPIO 的输入变化, 来产生中断或者是事件请求的外设模块.

EXTI 简介

EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的20 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

中断/事件线

中断优先级

抢占优先级:决定了一个中断能否打断正在执行的其他中断(即“插队”)

响应优先级:当多个中断的抢占优先级相同时,决定了它们的执行顺序(即“排队”)

两者都是数值越小, 优先级越高. (先看抢占优先级, 再看响应优先级)

主要区别是: 抢占优先级高可以打断其他中断, 而响应优先级高并不能打断其他中断.

上面的表格主要就是说明有 5 种优先级的分组方式

不同的分组方式, 其抢占优先级与响应优先级能够设置的级别不同.

(设置抢占级别多, 响应能设置的级别就少了, 反之亦然)

外部中断/事件控制器框图

图中的 20 , 表示 20 个中断/事件线

输入线就是中断的输入信号进入,

经过边沿检测电路(设置的 "上升沿" or "下降沿" 触发)

然后经过 ③ 或门, 该或门的两个来源分别为: 软件中断事件寄存器, GPIO 引脚边沿检测.

然后继续向左, 通过请求挂起寄存器.

请求挂起寄存器用来记录某个中断事件已经发生, 但还没被处理的标志寄存器.

(告诉 CPU 这里产生了一个中断, 需要处理, 就会在对应的寄存器中对应位写 1, 表示中断挂起了, 等待 CPU 处理.

当 CPU 知道之后就会手动清除这个挂起位, 表示该中断已经在处理, 可以将该标志清除. 否则会一直挂起, CPU 也会一直处理)

再向做, 经过 ⑥ 与门 (两个输入都有效, 才会输出), 当已经成功挂起, 并且通过一个事件屏蔽寄存器(控制是否允许某条中断线/事件线产生中断或事件, 即 允不允许中断产生, 如果允许, 在寄存器中通常设置为 1).

然后在经过 ⑦ 脉冲发生器来触发事件.

而当配置的是触发中断, 则经过的是 ④ 与门, 同样经过挂起寄存器已经挂起 并且中断屏蔽寄存器允许产生中断, 两个信号有效. 经过与门产生信号至 NVIC 中断控制器中, 产生中断.

回调函数应用

回调函数的作用 —— HAL_GPIO_EXTI_Callback ()

回调函数是什么?

回调函数是用户定义的函数,由库函数在特定事件发生时自动调用。

HAL_GPIO_EXTI_Callback() 是 HAL库提供的 GPIO 外部中断回调函数。

为什么要用回调函数?

把中断触发和业务逻辑分开,结构更清晰。

多个引脚共用一个回调函数,方便集中管理多个中断来源

项目配置

GPIO 配置

使用核心板上 KEY1 作为外部中断输入, 其对应引脚为 PA0

设置 PA1, PA2, PA3 对应核心板上三个 LED 灯, 默认电平为高 (灯灭)

设置 PA0 为 GPIO_EXTI0, GPIO mode 为 External Interrupt Rising edge trigger detection(外部中断上升沿 (低电平变高电平) 触发检测)

NVIC 配置

首先, 使能 EXTI0l, 点击右侧复选框勾选即可.

设置优先级分组

这里选择第四个优先级分组, 因为现在只用到这一个中断, 也用不到响应优先级. 所以随意, 其他选项默认

代码部分

这个函数在 EXTI0_IRQHandler -> HAL_GPIO_EXTI_IRQHandler 中被调用

这里 HAL_GPIO_EXTI_IRQHandler 对应的是检测我们指定引脚的中断挂起标志是否被设置.

也就是表示该引脚确实触发了中断, 就会调用这个 HAL_GPIO_EXTI_Callback 回调函数. (并且清除标志)

HAL_GPIO_EXTI_Callback

这里的 HAL_GPIO_EXTI_Callback 是一个 弱定义 函数, 该函数是用户自定义的.

以方便我们在别的地方编写一个函数来覆盖它.

该函数的参数也是 GPIO_Pin, 也就是引脚, 那么我们就可以在这个函数里判断传入的引脚是哪一个引脚.

通过区分引脚来做出对应的中断反应.

这里的 UNUSED(GPIO_Pin); 是如果在函数中没有用到参数, 编译器会有警告 (参数没有被使用) .

使用这个函数就可以消除编译器的这个警告.

当我们在其他地方编写好这个函数之后, 当外部中断触发时, 就会自动调用该回调函数, 来执行对应的代码.

在 USER CODE BEGIN 4 处定义这个函数. 并编写业务逻辑代码 (外部中断触发按键亮灭灯)

/* USER CODE BEGIN 4 */
/**
  * @brief  EXTI line detection callbacks.
  * @param  GPIO_Pin: Specifies the pins connected EXTI line
  * @retval None
  */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == KEY1_EXTI0_Pin) // 触发外部中断的是对应的 KEY1 的引脚 | 中断来源是按键1
  {
    // 切换红, 绿, 蓝三个LED灯的状态 (灭->亮, 亮->灭)
    HAL_GPIO_TogglePin(GPIOA, LED_R_Pin | LED_G_Pin | LED_B_Pin);
  }
}
/* USER CODE END 4 */
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐