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],这可能会导致单片机误判按键的状态变化次数。为了避免这种情况的发生,通常采用软件延时法或者硬件滤波法来解决。 #### 软件延时法 通过引入一段短暂的延迟时间(通常是几毫秒),可以有效过滤掉按键动带来的干扰信号。这种方法简单易行,在大多数应用场景下都能满足需求。 以下是基于定时器中断方式的一个具体代码实例: ```c #include "stm32f10x.h" #define KEY_PORT GPIOC #define KEY_PIN GPIO_Pin_13 volatile uint8_t key_flag = 0; void Key_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = KEY_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式 GPIO_Init(KEY_PORT, &GPIO_InitStructure); } // 定时器初始化函数设置为每5ms触发一次中断 void TIM3_Int_Init(u16 arr,u16 psc){ ... } void TIM3_IRQHandler(void){ if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){ static uint8_t count=0; if(!(KEY_PORT->IDR&KEY_PIN)){ count++; if(count>=20){ // 延迟约100ms (20*5ms) key_flag=!key_flag; count=0; } }else{ count=0; } TIM_ClearITPendingBit(TIM3,TIM_IT_Update); } } ``` 上述代码展示了如何利用TIM3定时器产生的周期性中断来进行按键状态监测并完成去处理的过程[^2]。 #### 硬件滤波法 除了软件手段外,还可以借助RC电路或者其他专用芯片构建外部滤波单元以减少噪声影响。不过这种方式会增加额外成本以及PCB布局复杂度,一般仅当对实时性和精度有极高要求时才会选用此方案。 综上所述,无论是采取哪种途径达成目的,都需要充分考虑到实际项目中的各种约束条件再做决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值