拓冰建站拓冰建站
首页 / 资讯中心 / 正文

【STM32 HAL库】02 - 按键输入检测实验(GPIO输入 + 软件消抖)

【STM32 HAL库】02 - 按键输入检测实验GPIO输入 软件消抖一、实验目的掌握 GPIO 引脚配置为输入模式的方法理解上拉/下拉输入的区别及适用场景学会机械按键的软件消抖处理方法实现按键按下翻转 LED 的功能二、硬件平台项目说明开发板野火霸天虎 STM32F407ZG主控芯片STM32F407ZGT6LQFP144KEY1 引脚PA0按下为高电平KEY2 引脚PC13按下为高电平LED 引脚PF6开漏输出低电平点亮外部晶振HSE 25 MHz系统时钟SYSCLK 168 MHz野火按键电路说明霸天虎板上的按键一端接 VCC另一端接 GPIO。按下时 GPIO 被拉至高电平松开时引脚悬空。因此 GPIO 需配置为内部下拉输入确保松开时引脚为稳定的低电平。三、软件环境软件版本/说明STM32CubeMXv6.x生成初始化代码Keil MDK-ARMv5编译下载固件包STM32Cube FW_F4下载器ST-LINK / CMSIS-DAP四、CubeMX 配置步骤4.1 基于 LED 工程创建打开上一个 LED 闪烁工程的.ioc文件 →File → Save Project As...→ 命名为02_Key_Input保存到工程目录。这样可以复用 LED 和时钟的配置只需添加按键引脚即可。4.2 配置 KEY1PA0在芯片引脚图上找到PA0左键选择GPIO_Input。点击左侧System Core → GPIO配置 PA0配置项值GPIO modeInput ModeGPIO Pull-up/Pull-downPull-down内部下拉User LabelKEY14.3 配置 KEY2PC13同理找到PC13选择GPIO_Input配置配置项值GPIO modeInput ModeGPIO Pull-up/Pull-downPull-down内部下拉User LabelKEY2PA0 默认显示为PA0-WKUPPC13 显示为PC13-ANTI_TAMP这是引脚的复用功能名配置为 GPIO_Input 后不影响使用。4.4 确认已有配置RCCHSE 25 MHzPLL → SYSCLK 168 MHz继承自 LED 工程LED_RPF6开漏输出继承自 LED 工程SYS DebugSerial Wire继承自 LED 工程4.5 生成代码点击GENERATE CODE生成代码。五、代码实现5.1 GPIO 初始化代码gpio.cCubeMX 自动生成void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; __HAL_RCC_GPIOC_CLK_ENABLE(); /* 使能 GPIOC 时钟 */ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能 GPIOA 时钟 */ /* LED_R: PF6 开漏输出 */ HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET); GPIO_InitStruct.Pin LED_R_Pin; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_R_GPIO_Port, GPIO_InitStruct); /* KEY1: PA0 下拉输入 */ GPIO_InitStruct.Pin KEY1_Pin; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLDOWN; HAL_GPIO_Init(KEY1_GPIO_Port, GPIO_InitStruct); /* KEY2: PC13 下拉输入 */ GPIO_InitStruct.Pin KEY2_Pin; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLDOWN; HAL_GPIO_Init(KEY2_GPIO_Port, GPIO_InitStruct); }5.2 按键扫描主逻辑main.c在while(1)循环的USER CODE BEGIN 3区域添加按键检测代码/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ /* 检测 KEY1 是否按下 */ if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) GPIO_PIN_SET) { HAL_Delay(20); /* 消抖延时 20ms */ if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) GPIO_PIN_SET) { HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin); /* 翻转 LED */ /* 等待按键松开,避免按住时重复触发 */ while (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) GPIO_PIN_SET); } } /* 检测 KEY2 是否按下 */ if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) GPIO_PIN_SET) { HAL_Delay(20); /* 消抖延时 20ms */ if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) GPIO_PIN_SET) { HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin); /* 翻转 LED */ while (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) GPIO_PIN_SET); } } } /* USER CODE END 3 */5.3 核心函数说明函数作用HAL_GPIO_ReadPin(GPIOx, GPIO_Pin)读取指定 GPIO 引脚的电平返回GPIO_PIN_SET(1) 或GPIO_PIN_RESET(0)HAL_GPIO_TogglePin(GPIOx, GPIO_Pin)翻转指定 GPIO 引脚的输出电平HAL_Delay(uint32_t Delay)毫秒级延时用于按键消抖5.4 宏定义main.hCubeMX 自动生成#define LED_R_Pin GPIO_PIN_6 #define LED_R_GPIO_Port GPIOF #define KEY1_Pin GPIO_PIN_0 #define KEY1_GPIO_Port GPIOA #define KEY2_Pin GPIO_PIN_13 #define KEY2_GPIO_Port GPIOC六、软件消抖原理6.1 为什么需要消抖机械按键按下和松开的瞬间金属触点会发生弹性抖动导致电平在几毫秒内快速跳变理想波形: ____ ____ | |___| |___ 实际波形: _/‾‾‾\_/‾‾‾\______ (按下时抖动) \___/‾‾‾\___ (松开时抖动)如果不处理消抖一次按下可能被识别为多次。6.2 软件消抖方法if (读到按下) { HAL_Delay(20); // 延时 20ms跳过抖动期 if (再次读到按下) // 确认确实按下 { 执行动作; while (读到按下); // 等待松手防止按住重复触发 } }关键点第一次检测到按下不立即处理延时 20ms 等待抖动结束再次读取确认仍为按下状态才执行动作执行后等待按键松开避免按住不放时循环触发七、编译与下载编译Keil 中按F7确认 0 Error(s)。下载按F8下载到开发板。验证按下 KEY1LED_R 翻转一次亮→灭 或 灭→亮按下 KEY2LED_R 同样翻转一次按住不放不会连续翻转等待松手逻辑生效八、实验现象初始状态 LED 常亮按下 KEY1 或 KEY2LED 状态翻转一次松开后再次按下才会再次翻转按住不放不会连续触发九、常见问题问题原因解决方法按键没反应GPIO 上下拉配反了野火按键按下为高电平需配 Pull-down按一次翻转多次没做消抖添加 HAL_Delay(20) 二次确认按住不放连续触发没有等待松手添加while(引脚按下);按键偶尔失灵延时太短抖动未结束增大消抖延时20~50msPA0 配置异常PA0 有 WKUP 复用功能确认设为 GPIO_Input不影响使用编译报错 KEY1_Pin 未定义User Label 未设置在 CubeMX 中为引脚设置 User Label十、上拉 vs 下拉选择按键电路按下电平GPIO 配置检测条件按键接 VCC高电平Pull-down下拉ReadPin GPIO_PIN_SET按键接 GND低电平Pull-up上拉ReadPin GPIO_PIN_RESET原则上下拉方向与按键按下时的电平相反确保松开时引脚有确定的默认电平避免悬空误触发。十一、工程目录结构02_Key_Input/ ├── Core/ │ ├── Inc/ │ │ ├── main.h ← KEY1/KEY2/LED_R 宏定义 │ │ ├── gpio.h │ │ └── stm32f4xx_hal_conf.h │ └── Src/ │ ├── main.c ← 按键扫描 LED 翻转逻辑 │ ├── gpio.c ← GPIO 初始化CubeMX 生成 │ ├── stm32f4xx_hal_msp.c │ ├── stm32f4xx_it.c │ └── system_stm32f4xx.c ├── Drivers/ ← STM32 HAL 库源码 ├── MDK-ARM/ ← Keil 工程文件 └── 02_Key_Input.ioc ← CubeMX 配置文件思考延伸本实验使用轮询方式检测按键主循环必须一直扫描按键才能响应。更高效的方式是使用EXTI 外部中断按键按下时触发中断主循环可以执行其他任务——这就是下一个实验要学的内容。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门