STM32按键扫描及按键消抖

一.按键消抖

1.原理

在STM32单片机中,其硬件的按键设计有一些缺点,当我们按下按键时,并不会直接输出一个高或低电平,松开时也同理,如图

这是因为按键的机械设计,按下或松开时会有抖动,称为机械抖动,这样会对想通过按键实现的功能输出不稳定。

2.解决办法

解决方法有硬件消抖和软件消抖,这里我们只讨论软件消抖。

单次机械抖动的持续时间大约为10ms~20ms,在我们前期没有学习定时器和中断的情况下,只需要在按下按键和松开按键后面加一个简单的延时10ms~20ms函数就可以。

二.按键扫描函数

1.示例

先看一段代码


u8 key_scan(void)
{
	
	u8 key = 0xff;
	
	//检测按键按下
	if((KEY1)||(!KEY2)||(!KEY3)||(!KEY4))
	{
		//延时消抖
		delay_ms(20);
		
		//再次检测按键按下
		if(KEY1)
		//赋值键值
		key = 1;
	  if(!KEY2)
		key = 2;
		if(!KEY3)
		key = 3;
		if(!KEY4)
		key = 4;
		
	}
	
	//等待按键抬起
   while((KEY1)&&(!KEY2)&&(!KEY3)&&(!KEY4))
	{
	}
    delay_ms(20);
	
	//返回键值
	return key;
}

在这段代码中按键KEY1是高电平触发,KEY2,KEY3,KEY4都是低电平触发。

乍一看,是不是这段代码就已经实现了按键扫描的功能了,当按下按键1时触发消抖然后变量key被赋值1,之后通过while循环来卡住程序判断按键有没有松开,最后返回key也就是1到函数,在主函数设置一个变量接住这个按键扫描函数,当这个变量为1时就可以实现你想实现的功能。其他按键也同理。

但是,如果你想在主函数中的按键控制功能后面再实现别的功能,比如实现一个流水灯功能。你会发现,当你按下某个按键没有松开时,该按键对应的功能被实现,但流水灯的程序却被等待按键抬起的程序卡住了没有运行。虽然说谁都不会闲着按着按键很久不松,但人类正常按下按键到松开的时间终归有大约100ms的时间,这对于人类来说时间很短,但对单片机来说可以执行很多很多次任务,因为单片机执行程序是微秒级的。对于那些项目级程序来说,这种程序可能会造成一些漏洞。

那我们能不能去掉那条等待按键抬起的程序呢,答案是不行的,因为去掉之后,我们按一次按键就会执行多次按键扫描函数,原因如之前所讲———按一次按键大概100ms左右,在这期间主函数循环早已执行很多次了。说到主函数,顺便提一下,按键扫描函数完成后是要放在主函数的while循环里面的,这是因为STM32需要不断读取GPIO引脚的状态,以检查是否有按键被按下。

2.标志位思想

我们可以在按键扫描函数里增加一个变量代表标志位。

u8 key_scan(void)
{
	static u8 flag = 1;
	u8 key = 0xff;
	
	//检测按键按下
	if(((KEY1)||(!KEY2)||(!KEY3)||(!KEY4)) && flag)
	{
		//延时消抖
		delay_ms(20);
		flag = 0;
		//再次检测按键按下
		if(KEY1)
		//赋值键值
		key = 1;
	  if(!KEY2)
		key = 2;
		if(!KEY3)
		key = 3;
		if(!KEY4)
		key = 4;
		
	}
	
	//等待按键抬起
   else if((!KEY1)&&(KEY2)&&(KEY3)&&(KEY4))
	{
		delay_ms(20);
		flag = 1;
	}
	
	//返回键值
	return key;
}

在上述程序中,我们可以看出,当我们按下某个按键没松开时,标志位flag进行锁定,所以只会返回一次按键对应键值,其他返回值则会返回初始值0xff(因为按键没松开,程序会循环执行,不断产生返回值),按键松开后则会解锁标志位,解锁标志位后才能让下一次按键按下能返回键值。这段代码则不会卡住主程序,因为代码里面没有任何的while函数而是选择结构。

3.思路

最后我们说一下按键扫描的思路

①检测按键是否按下

②延时10~15ms

③再检测按键是否按下

④等待按键抬起  

⑤返回键值

该思路会卡住主程序,解决方案:增加标志位

通过按下按键锁定标志位,抬起按键解锁标志位

如果按键按下没有抬起,通过标志位锁定,不允许再识别按键

按键抬起标志位解锁,下次按按键又允许识别按键

### STM32按键实现方法 在STM32单片机中,由于机械按键的物理特性,在按下和释放瞬间会产生动现象。这种动会使得输入信号不稳定,导致单片机可能误判按键的状态变化[^1]。 #### 软件延时去法 一种常见的解决办法是在检测到按键状态改变之后加入一段短暂的延迟时间(通常为10ms至50ms),再重新读取该按键的状态来确认是否真的发生了按压或者抬起的动作。如果两次读数一致则认为是一次有效的触发事件;反之则是由噪声引起的瞬态波动应该忽略不计。 ```c #include "stm32f1xx_hal.h" #define KEY_GPIO_PORT GPIOA #define KEY_PIN GPIO_PIN_0 void Key_Init(void){ __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = KEY_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; // 或者设置上拉/下拉电阻 HAL_GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStruct); } uint8_t GetKeyState(void){ uint8_t key_state = HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_PIN); if(key_state != 1){ // 假设低电平有效 HAL_Delay(20); // 短暂等待一段时间让动结束 if(HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_PIN) == 0){ while(!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY_PIN)); // 等待按键弹起 return 1; // 返回表示有按键被按下并已松开 } } return 0; // 否则返回无按键活动 } ``` 此代码片段展示了如何通过软件方式去除按键动影响。当检测到按键处于闭合位置时,程序先暂停执行一小段时间以便于稳定下来后再做进一步验证。只有连续两次都得到相同的结果才会认定这确实是一个真实的按键行为[^2]。 #### 硬件RC滤波电路配合定时器中断处理 除了上述纯编程手段外还可以采用外部元件构建简单的RC充放电网络连接到I/O端口上来抑制高频干扰成分。与此同时利用内部定时器资源周期性查询引脚电平值的变化情况作为最终判定依据之一。这种方法可以更可靠地过滤掉大部分短促脉冲型扰动因素而不必担心错过任何实际发生的操作指令。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值