GPIO--按键检测实战

GPIO–按键检测实战

大纲

  1. 需求分析
  2. 编程要点

具体案例

需求分析

首先我们要区分该芯片有无硬件防抖
按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生图按键抖动说明图 中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。而有些芯片通过加装电容器的方式完成

在这里插入图片描述
在这里插入图片描述

编程要点

  1. 使能 GPIO 端口时钟;
  2. 初始化 GPIO 目标引脚为输入模式 (浮空输入);
  3. 编写简单测试程序,检测按键的状态,实现按键控制 LED 灯。

编前准备

为了使工程更加有条理,我们把按键相关的代码独立分开存储,方便以后移植。在“工程模板”之上新建“bsp_key.c”及“bsp_key.h”文件,这些文件也可根据您的喜好命名,这些文件不属于 STM32 标准库的内容,是由我们自己根据应用需要编写的。

按键引脚宏定义

在编写按键驱动时,也要考虑更改硬件环境的情况。我们把按键检测引脚相关的宏定义到“bsp_key.h”文件中

// 引脚定义
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY1_GPIO_PORT GPIOA
#define KEY1_GPIO_PIN GPIO_Pin_0

#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_GPIO_PORT GPIOC
#define KEY2_GPIO_PIN GPIO_Pin_13

当然这是根据不同的硬件设施来写操作的端口和引脚,具体哪个端口和引脚请自行查阅手册

按键 GPIO 初始化函数

利用上面的定义的宏来编写初始化函数

void Key_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* 开启按键端口的时钟 */
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);
//选择按键的引脚
GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
// 设置按键的引脚为浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//使用结构体初始化按键
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);

//选择按键的引脚
GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
//设置按键的引脚为浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//使用结构体初始化按键
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);
}

(1) 使用 GPIO_InitTypeDef 定义 GPIO 初始化结构体变量,以便下面用于存储 GPIO 配置。

(2) 调用库函数 RCC_APB2PeriphClockCmd 来使能按键的 GPIO 端口时钟,调用时我们使用“|”操作同时配置两个按键的时钟。

(3) 向 GPIO 初始化结构体赋值,把引脚初始化成浮空输入模式,其中的 GPIO_Pin 使用宏“KEYx_GPIO_PIN”来赋值,使函数的实现方便移植。由于引脚的默认电平受按键电路影响,所以设置成浮空输入。

(4) 使用以上初始化结构体的配置,调用 GPIO_Init 函数向寄存器写入参数,完成 GPIO 的初始化,这里的 GPIO 端口使用“KEYx_GPIO_PORT”宏来赋值,也是为了程序移植方便。

(5) 使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它按键检测时使用的 GPIO
引脚。

检测按键功能编写

/** 按键按下标置宏
* 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0
* 若按键按下为低电平,把宏设置成 KEY_ON=0 ,KEY_OFF=1 即可
*/
#define KEY_ON 1
#define KEY_OFF 0

/**
* @brief 检测是否有按键按下
* @param GPIOx: 具体的端口, x 可以是(A...G)
* @param GPIO_PIN: 具体的端口位, 可以是 GPIO_PIN_x(x 可以是 0...15)
* @retval 按键的状态
* @arg KEY_ON: 按键按下
* @arg KEY_OFF: 按键没按下
*/
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
/* 检测是否有按键按下 */
if (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON ) {
/* 等待按键释放 */
while (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
} else
return KEY_OFF;
}

在这里我们定义了一个 Key_Scan 函数用于扫描按键状态。GPIO 引脚的输入电平可通过读取 IDR寄存器对应的数据位来感知,而 STM32 标准库提供了库函数 GPIO_ReadInputDataBit 来获取位状态,该函数输入 GPIO 端口及引脚号,函数返回该引脚的电平状态,高电平返回 1,低电平返回0。Key_Scan 函数中以 GPIO_ReadInputDataBit 的返回值与自定义的宏“KEY_ON”对比,若检测到按键按下,则使用 while 循环持续检测按键状态,直到按键释放,按键释放后 Key_Scan 函数返回一个“KEY_ON”值;若没有检测到按键按下,则函数直接返回“KEY_OFF”。若按键的硬件没有做消抖处理,需要在这个 Key_Scan 函数中做软件滤波,防止波纹抖动引起误触发。

主函数main函数

/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();

/* 初始化按键 */
Key_GPIO_Config();

/* 轮询按键状态,若按键按下则反转 LED */
while (1) {
if ( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) {
/*LED1 反转 */
LED1_TOGGLE;
}

if ( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON ) {
/*LED2 反转 */
LED2_TOGGLE;
  }
 }
}

代码中初始化 LED 灯及按键后,在 while 函数里不断调用 Key_Scan 函数,并判断其返回值,若返回值表示按键按下,则反转 LED 灯的状态。

### GPIO按键消抖的实现方法 #### 软件消抖 软件消抖是一种常见的按键消抖方式,其核心思想是对输入信号进行多次采样并判断稳定性。以下是一个基于STM32平台的典型软件消抖代码示例: ```c #define KEY_PIN GPIO_PIN_0 #define KEY_PORT GPIOA uint8_t keyState = 0; // 按键状态,0表示松开,1表示按下 void debounceSoftware(void) { if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == GPIO_PIN_SET) { HAL_Delay(20); // 延迟一段时间等待信号稳定 if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == GPIO_PIN_SET) { keyState = 1; // 确认按键被按下 } } else { HAL_Delay(20); // 同理延迟确认释放状态 if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) != GPIO_PIN_SET) { keyState = 0; // 确认按键已松开 } } } ``` 上述代码通过两次读取GPIO引脚的状态,并加入延时来过滤掉因机械开关引起的瞬态干扰[^1]。 #### 硬件消抖 硬件消抖通常依赖外部电路设计来减少或消除按键抖动的影响。一种常见的方式是在按键回路中串联电阻和电容形成RC滤波器。这种方式可以有效平滑电压波动,从而降低噪声影响[^2]。 对于更复杂的场景,也可以利用专门的IC芯片完成更加精确可靠的消抖功能。然而,在实际应用过程中需要注意选择合适的元件参数以及考虑成本等因素[^3]。 #### 改良版软件消抖逻辑 为了进一步提高可靠性,还可以采用如下改进策略:当检测到一次触发事件之后立即进入短时间内的循环监测阶段;只有连续几次都满足相同条件时才最终判定为真实有效的动作发生。例如下面这段来自某博客分享的经验优化版本即体现了这一点: ```c if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4) == 0){ HAL_Delay(20); if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4) == 0){ HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10); HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_9); while(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4) == 0){} } } ``` 此段程序不仅实现了基本的功能而且还解决了某些特定条件下可能出现误操作的问题[^4]。 综上所述,无论是采取纯软解还是硬配搭相结合的办法都可以达到良好效果,具体选用哪种取决于项目实际情况和个人偏好等多方面考量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挽天技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值