【星云 Orbit • STM32F4】04.一触即发:GPIO 外部中断

【星云 Orbit- • STM32F4】04. 一触即发:外部中断控制

摘要

本文详细介绍了如何使用STM32F407微控制器的HAL库实现外部中断功能。通过配置GPIO引脚作为外部中断源,并在中断回调函数中处理按键事件,实现了按键控制LED状态翻转的功能。本文旨在为初学者提供一个详细、易懂的教程,包括硬件电路设计、软件架构、代码实现及应用示例。


1. 引言

外部中断是嵌入式系统中常见的功能,用于检测外部事件并触发相应的中断处理程序。STM32F407微控制器提供了丰富的GPIO资源和灵活的中断配置,通过HAL库可以方便地实现外部中断功能。本文以STM32F407开发板为例,详细介绍了如何配置外部中断,实现按键控制LED状态翻转的功能。


2. 硬件设计

2.1 硬件资源

本实验使用STM32F407开发板上的两个按键和两个LED,具体资源如下:

  • LED
    • LED0:连接到GPIOF的Pin 9
    • LED1:连接到GPIOF的Pin 10
  • 按键
    • WKUP:连接到GPIOA的Pin 0
    • KEY0:连接到GPIOE的Pin 4

2.2 硬件接线

本实验使用的两个 STM32F407 板载按键,分别为 KEY0 按键和 WKUP 按键,其与板载 MCU 的连接原理图如下所示:

在这里插入图片描述
从原理图中可以看出,WKUP 按键和 KEY0 按键的一端连接到了电源正极(VCC),而另一端分别与 MCU 的 PA0 引脚和 PE4 引脚相连接。对于该硬件设计,PA0 引脚和 PE4 引脚应当配置为下拉模式,这样一来,在按键被按下的时候,PA0 引脚或 PE4 引脚就会从原来的低电平状态变为高电平状态,在这期间就会有一个上升沿的跳变,因此可以使用该上升沿信号作为中断的触发源。


3. 软件设计

3.1 软件架构

本实验的软件架构主要包括以下几个部分:

  1. 系统初始化:初始化HAL库、时钟、延时、串口和LED。
  2. 外部中断初始化:配置GPIO引脚作为外部中断源,并设置中断优先级。
  3. 中断服务函数:处理外部中断事件,实现按键控制LED状态翻转的功能。

为了提高代码的可读性和可维护性,我们将代码分为多个模块,每个模块负责一个特定的功能。

3.2 GPIO 配置

使用 HAL 库配置 GPIO 引脚为外部中断模式:

  • 模式:上升沿触发中断。
  • 上拉/下拉:下拉模式。

3.3 中断配置

3.3.1 设置中断优先级

使用 HAL_NVIC_SetPriority 函数设置中断优先级:

HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority);
  • IRQn:NVIC 中断请求,例如 EXTI0_IRQnUSART1_IRQn 等(在 stm32f407xx.h 文件中有定义)。
  • PreemptPriority:抢占优先级。
  • SubPriority:子优先级。
3.3.2 使能中断

使用 HAL_NVIC_EnableIRQ 函数使能中断:

HAL_NVIC_EnableIRQ(IRQn_Type IRQn);
  • IRQn:NVIC 中断请求,例如 EXTI0_IRQnUSART1_IRQn 等(在 stm32f407xx.h 文件中有定义)。

3.3 中断服务函数

编写中断服务函数,处理按键按下事件:

  • WKUP_INT_IRQHandler:处理 WKUP 按键中断。
  • KEY0_INT_IRQHandler:处理 KEY0 按键中断。

3.4 中断回调函数

使用 HAL_GPIO_EXTI_Callback 函数处理中断事件,翻转 LED 状态。


4. 代码实现

4.1 系统初始化模块

4.1.1 HAL库初始化
#include "stm32f4xx_hal.h"// 初始化HAL库
void hal_init(void)
{HAL_Init(); // 初始化HAL库
}
4.1.2 时钟配置
#include "stm32f4xx_hal.h"// 配置时钟
void sys_stm32_clock_init(uint32_t pllm, uint32_t plln, uint32_t pllp, uint32_t pllr)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};// 初始化RCC OscRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = pllm;RCC_OscInitStruct.PLL.PLLN = plln;RCC_OscInitStruct.PLL.PLLP = pllp;RCC_OscInitStruct.PLL.PLLR = pllr;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){// 初始化失败while (1){}}// 初始化RCC ClkRCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK){// 初始化失败while (1){}}
}
4.1.3 延时初始化
#include "stm32f4xx_hal.h"// 延时函数
void delay_ms(uint32_t ms)
{HAL_Delay(ms); // 使用HAL库提供的延时函数
}
4.1.4 串口初始化
#include "stm32f4xx_hal.h"// 初始化串口
void usart_init(uint32_t baudrate)
{USART_HandleTypeDef huart1;huart1.Instance = USART1;huart1.Init.BaudRate = baudrate;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){// 初始化失败while (1){}}
}
4.1.5 LED初始化
#include "stm32f4xx_hal.h"// 定义LED和按键的GPIO引脚
#define LED0_GPIO_PORT GPIOF
#define LED0_GPIO_PIN GPIO_PIN_9
#define LED1_GPIO_PORT GPIOF
#define LED1_GPIO_PIN GPIO_PIN_10// 初始化LED
void led_init(void)
{GPIO_InitTypeDef gpio_init_struct = {0};// 使能GPIO端口时钟__HAL_RCC_GPIOF_CLK_ENABLE();// 配置LED0引脚gpio_init_struct.Pin = LED0_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;gpio_init_struct.Pull = GPIO_NOPULL;gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(LED0_GPIO_PORT, &gpio_init_struct);// 配置LED1引脚gpio_init_struct.Pin = LED1_GPIO_PIN;HAL_GPIO_Init(LED1_GPIO_PORT, &gpio_init_struct);// 关闭LEDHAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET);HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET);
}

4.2 外部中断初始化模块

4.2.1 GPIO引脚配置
#include "stm32f4xx_hal.h"// 定义按键的GPIO引脚
#define WKUP_INT_GPIO_PORT GPIOA
#define WKUP_INT_GPIO_PIN GPIO_PIN_0
#define WKUP_INT_GPIO_CLK_ENABLE() do { HAL_RCC_GPIOA_CLK_ENABLE(); } while (0)
#define WKUP_INT_IRQn EXTI0_IRQn
#define WKUP_INT_IRQHandler EXTI0_IRQHandler#define KEY0_INT_GPIO_PORT GPIOE
#define KEY0_INT_GPIO_PIN GPIO_PIN_4
#define KEY0_INT_GPIO_CLK_ENABLE() do { HAL_RCC_GPIOE_CLK_ENABLE(); } while (0)
#define KEY0_INT_IRQn EXTI4_IRQn
#define KEY0_INT_IRQHandler EXTI4_IRQHandler// 初始化外部中断
void exti_init(void)
{GPIO_InitTypeDef gpio_init_struct = {0};// 使能GPIO端口时钟WKUP_INT_GPIO_CLK_ENABLE();KEY0_INT_GPIO_CLK_ENABLE();// 配置WKUP控制引脚gpio_init_struct.Pin = WKUP_INT_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_IT_RISING;gpio_init_struct.Pull = GPIO_PULLDOWN;gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(WKUP_INT_GPIO_PORT, &gpio_init_struct);// 配置KEY0控制引脚gpio_init_struct.Pin = KEY0_INT_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_IT_RISING;gpio_init_struct.Pull = GPIO_PULLDOWN;gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(KEY0_INT_GPIO_PORT, &gpio_init_struct);// 配置中断优先级并使能中断HAL_NVIC_SetPriority(WKUP_INT_IRQn, 0, 0);HAL_NVIC_EnableIRQ(WKUP_INT_IRQn);HAL_NVIC_SetPriority(KEY0_INT_IRQn, 0, 0);HAL_NVIC_EnableIRQ(KEY0_INT_IRQn);
}

4.3 中断服务函数模块

4.3.1 外部中断服务函数
#include "stm32f4xx_hal.h"// 外部中断服务函数
void WKUP_INT_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(WKUP_INT_GPIO_PIN); // 处理WKUP按键的外部中断
}void KEY0_INT_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(KEY0_INT_GPIO_PIN); // 处理KEY0按键的外部中断
}
4.3.2 HAL库外部中断回调函数
#include "stm32f4xx_hal.h"// HAL库外部中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{// 机械按键消抖(仅演示,切勿在实际工程的中断服务函数中进行阻塞延时)delay_ms(20);switch (GPIO_Pin){case WKUP_INT_GPIO_PIN:HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); // 翻转LED0状态break;case KEY0_INT_GPIO_PIN:HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN); // 翻转LED1状态break;}
}

4.4 主程序模块

4.4.1 主程序
#include "stm32f4xx_hal.h"
#include "system_init.h"
#include "exti_init.h"
#include "led_init.h"
#include "usart_init.h"
#include "delay.h"int main(void)
{hal_init(); // 初始化HAL库sys_stm32_clock_init(336, 8, 2, 7); // 配置时钟,168MHzdelay_init(168); // 初始化延时usart_init(115200); // 初始化串口led_init(); // 初始化LEDexti_init(); // 初始化外部中断while (1){// 主循环中不执行任何操作}
}

5. 下载验证

在完成编译和烧录操作后,可以看到板子上的LED0和LED1默认是处于熄灭的状态。若此时按下WKUP按键,则能够看到LED0的亮灭状态发生了一次翻转。同样的,若此时按下KEY0按键,则能够看到LED1的亮灭状态发生了一次翻转,与预期的实验现象效果相符。


6. 总结

本文详细介绍了如何使用STM32F407微控制器的HAL库实现外部中断功能,通过配置GPIO引脚作为外部中断源,并在中断回调函数中处理按键事件,实现了按键控制LED状态翻转的功能。本文涵盖了硬件电路设计、软件架构、代码实现及应用示例,旨在为初学者提供一个详细、易懂的教程。通过本文的学习,读者可以掌握STM32F407外部中断的基本配置和使用方法,为后续的嵌入式系统开发打下坚实的基础。

在完成编译和烧录操作后,可以看到板子上的LED0和LED1默认是处于熄灭的状态。若此时按下WKUP按键,则能够看到LED0的亮灭状态发生了一次翻转。同样的,若此时按下KEY0按键,则能够看到LED1的亮灭状态发生了一次翻转,与预期的实验现象效果相符。


6. 总结

本文详细介绍了如何使用STM32F407微控制器的HAL库实现外部中断功能,通过配置GPIO引脚作为外部中断源,并在中断回调函数中处理按键事件,实现了按键控制LED状态翻转的功能。本文涵盖了硬件电路设计、软件架构、代码实现及应用示例,旨在为初学者提供一个详细、易懂的教程。通过本文的学习,读者可以掌握STM32F407外部中断的基本配置和使用方法,为后续的嵌入式系统开发打下坚实的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/27711.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(新版本onenet)stm32+esp8266/01s mqtt连接onenet上报温湿度和远程控制(含小程序)

物联网实践教程:微信小程序结合OneNET平台MQTT实现STM32单片机远程智能控制 远程上报和接收数据——汇总 前言 之前在学校获得了一个新玩意:ESP-01sWIFI模块,去搜了一下这个小东西很有玩点,远程控制LED啥的,然后我就想…

并发编程(线程基础)面试题及原理

1. 进程与线程 1.1 进程 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。 当一个程序被运…

基于开源库编写MQTT通讯

目录 1. MQTT是什么?2. 开发交互UI3. 服务器核心代码4. 客户端核心代码5. 消息订阅与发布6. 通讯测试7. MQTT与PLC通讯最后. 核心总结 1. MQTT是什么? MQTT(Message Queuing Terlemetry Transport)消息队列遥测协议;是…

vector习题

完数和盈数 题目 完数VS盈数_牛客题霸_牛客网 一个数如果恰好等于它的各因子(该数本身除外)之和,如:6321。则称其为“完数”;若因子之和大于该数,则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。 输入描述&#xff…

vscode通过ssh远程连接(linux系统)不能跳转问题

1.问题描述 unbantu中的vscode能够通过函数跳转到函数定义,而windows通过ssh连接unbantu的vscode却无法跳转 2.原因: 主要原因是这里缺少插件,这里是unbantu给主机的服务器,与ubantu本地vscode插件相互独立,能否跳转…

神经网络 - 激活函数(Swish函数、GELU函数)

一、Swish 函数 Swish 函数是一种较新的激活函数,由 Ramachandran 等人在 2017 年提出,其数学表达式通常为 其中 σ(x) 是 Sigmoid 函数(Logistic 函数)。 如何理解 Swish 函数 自门控特性 Swish 函数可以看作是对输入 x 进行“…

安全运营的“黄金4小时“:如何突破告警疲劳困局

在当今复杂多变的网络安全环境中,安全团队面临着前所未有的挑战。尤其是面对高级持续性威胁(APT)时,最初的“黄金4小时”成为决定成败的关键窗口。在这段时间内,快速而准确地响应可以极大地降低损失,然而&a…

【Pytest】setup和teardown的四个级别

文章目录 1.setup和teardown简介2.模块级别的 setup 和 teardown3.函数级别的 setup 和 teardown4.方法级别的 setup 和 teardown5.类级别的 setup 和 teardown 1.setup和teardown简介 在 pytest 中,setup 和 teardown 用于在测试用例执行前后执行一些准备和清理操…

傅里叶分析

傅里叶分析之掐死教程(完整版)更新于2014.06.06 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析不仅仅是一个数学工具,更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是,傅里叶分析的公式看起来太复…

matlab 四维数据可视化(已解决)

虽然这不是传统意义上的“4维可视化”,但你可以通过在三维空间中表示两个维度来间接展示4维数据。例如,你可以使用颜色来表示第四个维度。 clc clear close all% 假设X, Y, Z为你的三维数据,C为第四维数据 X rand(100, 1); Y rand(100, 1);…

MAC 本地搭建部署 dify(含 github访问超时+Docker镜像源拉取超时解决方案)

目录 一、什么是 dify? 二、安装 docker 1. 什么是 docker? 2. docker下载地址 三、安装 dify 1. dify下载地址 2.可能遇到问题一: github访问超时 3.下载后完成解压 4.进入到 cmd 终端环境,执行下面三个命令 5.可能遇到…

rustup-init.exe 安装缓慢的解决办法

首先在rust官网下载安装程序,官网下载的 rustup-init.exe 下载慢,安装慢,或者直接卡死。 下载安装程序在本地,使用国内镜像加速 Rust 更新与下载。 使用国内镜像源:在 rustup-init.exe 程序文件夹下使用 PowerShell 中…

OpenAI发布GPT-4.5:功能非常特殊,推理很贵

今天凌晨4点,OpenAI进行了在线技术直播,发布了最新模型GPT-4.5。 GPT-4.5与之前的模型相比,本次最大的亮点是加上了“情商”,这也是目前所有大模型最缺、最难的功能。 此外,GPT-4.5 在SimpleQA上的测试数据显示&…

unity pico开发二:连接头盔,配置手柄按键事件

文章目录 导入UnityXR Interaction ToolKit构建基础内容 导入UnityXR Interaction ToolKit 检查一下packagemanager,unityxr interactionToolkit是否自动导入 我们需要升级到一个不超过3.x的版本,因为pico还不支持3.x的内容 然后右侧samples里导入初始…

k8s架构及服务详解

目录 1.1.容器是什么1.2.Namespace1.3.rootfs5.1.Service介绍5.1.1.Serice简介 5.1.1.1什么是Service5.1.1.2.Service的创建5.1.1.3.检测服务5.1.1.4.在运行的容器中远程执行命令 5.2.连接集群外部的服务 5.2.1.介绍服务endpoint5.2.2.手动配置服务的endpoint5.2.3.为外部服务…

【含文档+PPT+源码】基于SpringBoot和Vue的编程学习系统

项目介绍 本课程演示的是一款 基于SpringBoot和Vue的编程学习系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该…

【FL0090】基于SSM和微信小程序的球馆预约系统

🧑‍💻博主介绍🧑‍💻 全网粉丝10W,CSDN全栈领域优质创作者,博客之星、掘金/知乎/b站/华为云/阿里云等平台优质作者、专注于Java、小程序/APP、python、大数据等技术领域和毕业项目实战,以及程序定制化开发…

macos下myslq图形化工具之Sequel Ace

什么是Sequel Ace 官方github:https://github.com/Sequel-Ace/Sequel-Ace Sequel Ace 是一款快速、易于使用的 Mac 数据库管理应用程序,用于处理 MySQL 和 MariaDB 数据库。 Sequel Ace 是一款开源项目,采用 MIT 许可证。用户可以通过 Ope…

1.2.2 使用Maven方式构建Spring Boot项目

本次实战通过Maven方式构建了一个Spring Boot项目,实现了简单的Web应用。首先,创建了Maven项目并设置好项目名称、位置、构建系统和JDK等。接着,添加了Spring Boot的父项目依赖和web、thymeleaf起步依赖。然后,创建了项目启动类He…

Java【多线程】(2)线程属性与线程安全

目录 1.前言 2.正文 2.1线程的进阶实现 2.2线程的核心属性 2.3线程安全 2.3.1线程安全问题的原因 2.3.2加锁和互斥 2.3.3可重入(如何自己实现可重入锁) 2.4.4死锁(三种情况) 2.4.4.1第一种情况 2.4.4.2第二种情况 2.4…