一、按键简介
常态下,独立按键是断开的,按下的时候才闭合。每个独立按键会单独占用一个 IO 口,通过 IO 口的高低电平判断按键的状态。但是按键在闭合和断开的时候,都存在抖动现象,即按键在闭合时不会马上就稳定的连接,断开时也不会马上断开。这是机械触点,无法避免。
按键抖动波形图如下:
按下抖动和释放抖动的时间一般为 5~10ms,如果在抖动阶段采样,其不稳定状态可能出现一次按键动作被认为是多次按下的情况。为了避免抖动可能带来的误操作,我们要做的措施就是给按键消抖(即采样稳定闭合阶段)。消抖方法分为硬件消抖和软件消抖,我们常用软件的方法消抖。
软件消抖,最简单的延时消抖。检测到按键按下后,一般进行10ms 延时,用于跳过抖动的时间段,如果消抖效果不好可以调整这个 10ms 延时,因为不同类型的按键抖动时间可能有偏差。待延时过后再检测按键状态,如果没有按下,那我们就判断这是抖动或者干扰造成的;如果还是按下,那么我们就认为这是按键真的按下了。对按键释放的判断同理。
硬件消抖,利用 RC 电路的电容充放电特性来对抖动产生的电压毛刺进行平滑出来,从而实现消抖,但是成本会更高一点。
二、源码实现
2.1、原理图
K1、K2 和 K3 设计为采样到按键另一端的低电平为有效电平,而 KEY_UP 则需要采样到高电平才为按键有效,并且按键外部没有上下拉电阻,所以需要在 STM32F407 内部设置上下拉。因此,K1、K2 和 K3 配置为 上拉输入,KEY_UP 配置为 下拉输入。
2.2、程序源码
按键初始化函数内容如下:
/**
* @brief 按键初始化函数
*
*/
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOE_CLK_ENABLE(); // 使能GPIOE的时钟
GPIO_InitStruct.Pin = GPIO_PIN_2; // GPIO引脚
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 使用上拉
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); // GPIO初始化
GPIO_InitStruct.Pin = GPIO_PIN_3; // GPIO引脚
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); // GPIO初始化
}
按键扫描函数内容如下:
/**
* @brief 按键扫描函数
*
* @return uint8_t 返回0代表按键没有按下,返回1代表按键按下
*/
uint8_t Key_Scan(void)
{
if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_2) == GPIO_PIN_RESET) // 读取GPIO的电平
{
HAL_Delay(10); // 按键消抖
if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_2) == GPIO_PIN_RESET) // 再次读取GPIO的电平
{
while (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_2) == GPIO_PIN_RESET); // 等待按键释放
return 1; // 按键按下返回1
}
}
return 0; // 按键没有按下返回0
}
有关时钟配置函数请在 STM32 的时钟系统 篇章查看。
有关 LED 配置函数请在 点亮 LED 篇章查看。
main() 函数内容如下:
int main(void)
{
HAL_Init();
System_Clock_Init(8, 336, 2, 7);
LED_Init();
Key_Init();
while (1)
{
if (Key_Scan())
{
HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9); // GPIO电平翻转
}
}
return 0;
}
标签:HAL,07,PIN,消抖,按下,按键,GPIO,输入
From: https://www.cnblogs.com/kurome/p/18047781