按键的单击、双击、连续按、短按和长按实现思路

概念区分

看到好多教程说了这些概念,有的说单击就是短按,连续按就是长按等等。

其实,仔细想想,这几个概念是有一些区别的。

假如一个按键,没按下时是高电平,按下时是低电平,以此来理解这些概念。

单击:按键按下后,第一次检测到低电平,则触发动作,之后即使按键还处于低电平状态,也不会触发动作。

双击:必须连续按下两次,才会触发相应的动作。

连续按:只要按键一直被按下,即一直处于低电平状态,则会根据调用间隔不停地触发动作。

短按:按键按下后不会立即触发动作,而是会经过一小段时间,才会触发动作。

长按:按键按下后不会立即触发动作,而是会经过一长段时间,才会触发动作。

注意区分以上五种功能,以下记录实现思路。

补充注意:在配置外部中断时,有个上升沿触发或者下降沿触发,这里指的是,下降沿发生时触发了中断,但是判断按键是否处于按下状态,依然是判断低电平。

连续按

连续按相对简单,所以先讲这个。

按下去之后,就会一直有效,具体有效的间隔时长,可以自行设定,比如快点的话,就1秒钟检测60次,慢点的话,就1秒钟检测十几二十次差不多,再慢点,就一秒钟检测一两次也行,具体根据需要来。但是间隔一定不能超过人能反应过来的时间。

只要固定间隔比如100ms检测一次电平,如果是有效电平,就触发动作即可。

对应的按键扫描思路如下:

这个代码可以写在硬件层,然后业务层调用后判断即可。

比如,业务层每隔100ms调用一次该函数,每次都返回的是1,说明一直处于按下状态,然后就执行相应的动作即可。

想想键盘按键被卡住。

单击

单击则是在连续按的基础上,做一些限制,如果之前已经按下过,那么之后即使还处于按下状态,也不会触发动作。

因此,需要加一个变量,来记录按键是否已经被按下过。

不支持连续按的实现,有一个关键点,就是这一次的判断和上一次的按键状态有关,怎么理解呢?如果上一次是高电平,这一次检测是低电平,那么就会因为是第一次触发,所以会被视为有效。但是如果这次检测到的是低电平,但是其上一次检测的也是低电平,那么,就表示是发生了连续按,此时,需要阻止其触发动作。

所以,扫描按键在判断时,不能只判断这一次是否处于按下状态,还要结合上一次的按键的状态。

对应的按键扫描思路如下:

这段代码的最后应该还有个return 0;

注意,这里的是否已经被按下标志key_up需要定义为static变量,是为了让其只在第一次调用时被初始化。

这里的代码理解就是,只有之前没被按下并且这次被按下才能生效,如果没有被按下,或者之前已经被按下这次还是按下,都不会生效。

上面的方式,轮询和外部中断中都适用。

如果是外部中断,还有另外的实现思路

就是下降沿触发进入中断后,给一个全局的状态标志,只要触发进入了中断,则状态标志置位,触发功能之后,状态标志再复位。

再简单点,直接将操作逻辑放在中断里,这样,按下一次就只会触发一次,后续即使还是按下的状态,也不会重复执行。

有时,为了不在中断里放过多的业务逻辑,保证中断的快进快出,就可以只在中断里判断标志位,然后在其他地方(比如按键的专用c文件中)根据标志位执行相应的动作。

其实,就算在中断里,也还是可以根据低电平来判断是不是处于按下状态,从而实现单击或者连续按。

这里算是提供基于边沿触发的外部中断下的一种思路吧。

双击

短按和长按

短按和长按其实都是同一种思路,区别就是延时触发的延迟时间长短不同。

所以,这里的关键就是,如何合理地检测低电平持续的时间

短按,其实可以理解为单击,就是按下之后要很快松开,因为时间长了会被判定为长按。

一开始,我的想法是,检测是否有低电平发生,如果有,就再延时一段时间比如5s,之后再次判断是否还是低电平,如果是,则表示发生了长按。可是,一细想,又发现这个思路有BUG,如果我先按下按键,然后松开,等到快5秒的时候再按下,这样,也会两次都检测到低电平,但实际并不是长按。

我又想,那么在5秒内,一直判断是不是低电平不就行了,所以,需要造一个5秒的for循环,在里面一直判断是不是低电平,只要有一个高电平发生,就不能判定为长按,而是被判定为短按。

static void KEY_Detect() 
{
	uint8_t i = 0;
	
	if(KEY1.KEY_Flag == TRUE)//先判断有按键按下
	{
		KEY1.Click = FALSE;
		KEY1.Press = TRUE;
		//触摸按键长按检测
		for(i=0;i<500;i++)
		{
			HAL_Delay(10);
			//如果5s内,按键状态出现高电平,此时按键为短按,跳出循环
			if(检测到高电平)
			{
				KEY1.Click = TRUE;
				KEY1.Press = FALSE;
				break; //跳出for循环
			}
		}
		
		if(是短按)
		{
			//短按对应的动作
		}
		
		if(是长按)
		{
			//长按对应的动作
		}
		
		//清除按键状态
		KEY1.KEY_Flag = FALSE;
		KEY1.Click = FALSE;
		KEY1.Press = FALSE;
	}
}

这种思路是可行的,但是根据for循环来实现按键时长,并不精准。

如果想要更精准的时间判断,怎么办呢?

最好是结合定时器。

定时器的思路其实和上述for循环是一样的。

也是每隔10ms判断一次按键状态,只是定时器方式是将这个判断放到定时器中了。

可以让其在10ms定时器里进入判断500次,只要没有高电平出现,就置位长按标志,否则置位短按标志。

之后再根据这个标志去执行相应动作即可。

又或者在定时器里面判断低电平来计数,只要计数大于等于500,就可以执行相应动作。

比如:

static int cnt=0;
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
    cnt++;
    if(cnt>500)
    {
        PRINT("long press\n");
        ……
        cnt =0;
    }
……
}

注意,编程时,不一定非要根据某种动作来执行另一种动作,可以先根据一种动作来设置一些相应的标志位,然后在其他地方根据标志位再进行一些动作,这样更加灵活。

  • 7
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 在STM32开发中,使用定时器可以方便地实现按键单击双击按功能。具体实现方式如下: 1. 按键单击: 当按键被按下时,启动定时器计时,若在规定的时间内松开键,则视为单击操作。可以设置定时器1为中断模式,启动定时器后等待中断响应即可。 2. 按键双击按键双击功能需要在单击结束后一定时间内再次单击才能触发,一般设置为200ms-300ms。实现方式与单击类似,只需在单击结束后启动定时器再次等待中断响应即可。 3. 按键按: 按键按功能一般指按住按键不动一定时间后触发,可以设置一个按时间阈值,一般为1s-2s。启动定时器开始计时,若在规定时间内键状态一直为高电平,则视为按操作。 总之,在STM32的开发中,使用定时器可以方便地实现按键单击双击按功能,只需设置好相应的时间参数和中断响应即可。 ### 回答2: 在STM32中使用定时器实现按键单击双击按的实现方法比较简单。 按键单击可以通过检测按键是否按下并保持一段时间来实现。在STM32中,可以通过读取GPIO口的状态来检测按键是否按下,并使用定时器来延时判断按键是否被松开。当按键被按下并且被松开时,即可判断为单击事件。 按键双击可以通过在单击事件的基础上增加一个短暂的时间间隔来实现。当第一次按下按键时,开启定时器计数并在计数完毕后进行单击判断,当第二次按下按键时,再次开启定时器计数并在计数完毕后进行单击判断,如果两次单击之间的时间间隔较短,则可以判断为双击事件。 按键按可以通过读取GPIO口状态并在一段时间内判断按键是否一直为按下状态来实现。当按键被按下时,开启定时器计数,并在计数完成后判断GPIO口是否一直为按下状态,如果是,则判断为按事件。 总之,在STM32中使用定时器实现按键单击双击按的方法非常简单,只需要结合GPIO口状态来进行相应的判断即可。 ### 回答3: STM32系列的微处理器内置了多种定时器功能,可用于实现按键单击双击按等功能。下面是使用定时器实现按键单击双击按的具体方法: 1、按键单击:当按键按下时,开启一个短时间的定时器,在定时器时间内检测按键是否释放,如果释放则判断为单击事件。 2、按键双击:当检测到按键第一次单击事件时,开启一个短时间的定时器,在定时器时间内检测是否有第二次单击事件,如果有,则判断为双击事件。 3、按键按:当按键按下一段时间后,开启一个时间定时器,在定时器时间内不断检测按键是否释放,如果一直按下不放,则判断为按事件。 需要注意的是,定时器的时间要适当设置,避免误判或判断不准确。此外,还需要进行防抖处理,避免按键抖动导致误判。 在STM32中,定时器的具体使用可以参考官方提供的开发文档和代码示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值