按键状态机(实现单击,长按,双击)的模块分享

这篇具有很好参考价值的文章主要介绍了按键状态机(实现单击,长按,双击)的模块分享。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、相关说明

二、分析

三、模块代码

三、代码讲解

四、作者的话


一、相关说明

        1.需要的资源:一个定时器,一个按键。

        2.相关设置:利用定时器计时中断,10ms进行一次按键扫描。

        3.使用说明:定时器中断的优先级要设置高一点,相关的宏定义可以自行定义。

        4.实现功能:区分单个按键的单击,双击,长按。

        5.规定:双击:2次按下的间隔不超过200ms属于双击。

                      单击:第一次按下持续时间小于1s属于单击。

                      长按:第一次按下持续时间不小于1s属于长按。

        (时间长短可自己调整)

        6.目标:帮助理解按键的状态机。

二、分析

        1.时间线分析和状态概览

按键双击程序,一些简单的模块分享,stm32,51单片机,单片机

        2.状态分析和编程思路

按键双击程序,一些简单的模块分享,stm32,51单片机,单片机

         说明:一般按键有两种状态,按下和弹起,这里将按键按下的状态拆分为两种状态,以长按1s的标志触发为断点,拆分为按键按下到标志触发状态和标志触发到按键弹起的状态。而对于单击和双击可直接理解为按下状态,只是形式上作了拆分。而且按下抖动的状态实际编程中没有编写,有兴趣的小伙伴可以尝试添加。

那为什么要拆分按键按下的状态?
定时器会10ms进行实时检测。
长按标志到时会实时清零,如果不拆分状态只能等待按键弹起进入1状态,但此时长按标志已被清零,系统错乱,误判为单击。
要想长按标志不被清零,就不能在按下状态动态清零,所以只能设计为松手反馈。
而拆分状态后可将1s前要做的事和1s后要做的事拆分开,1s到时即可实时反馈。

三、模块代码

1.相关宏

    #define KEY GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)
   
    #define KEY_Up  1         //按键弹起
    #define KEY_DownShake  2  //按下抖动
    #define KEY_Down  3       //按键按下
    #define KEY_wait  4       //等待状态
     
    #define SHORT_KEY 1       //短按反馈
    #define LONG_KEY 2        //长按反馈
    #define DOUBLE_CLICK 3    //双击反馈
    
    #define FALSE 0
    #define TRUE 1  

2.函数主体

/**
  * @brief  KEY_Scan();// 按键检测
  * @note   按键检测,返回单击,双击,长按
  * @param  无
  * @retval 无
  * @author 常州工学院电子协会22级团体
	PS:key_return属于外部全局变量,用于接受反馈信息
  */	
void KEY_Scan(void)
{
	//反馈系统
	static uint8_t  Click_Buf = FALSE;  //第一次弹起标志,用与区分双击的第一次按下和第二次按下
	static uint8_t  KEY_flag= FALSE;//标志触发判断标志位,用于在反馈结束后统一清零
  	static uint8_t  Click   = FALSE;//单击判断标志位
	static uint8_t  Long_Press = FALSE; //长按判断标志位
  	static uint8_t  Double_Click  = FALSE;//双击判断标志位
	
	//计时系统
	//定时器10ms进入一次函数
    static uint8_t  Long_Cnt = 100;//长按计时时长1s
    static uint8_t  Twice_Cnt = 20;//双击间隔计时时长200ms
	Long_Cnt--;
    Twice_Cnt--;
	
	//状态系统
    switch(key_state)
    {
        /*状态1:空闲状态(单击)和按键弹起后(双击)*/
        case KEY_Up:
        {
    	  if(KEY == 0)
		  {
			key_state = KEY_Down;//切换到状态3
			Long_Cnt = 100;//长按计时开始
		  }
          else
          {
            //判断是否为按键弹起状态
            if(Click_Buf == TRUE)
            {
			  //弹起时间超过200ms,双击判定时间失效,且一定不为长按,直接判断为单击
              if(Twice_Cnt<=0)
              {
				KEY_flag = TRUE;
                Click = TRUE;
              }
            }
          }
        break;
    }
    
//    /*状态2:按下抖动(过渡状态)*/
//    case KEY_DownShake:
//    {
//      if(KEY == 0)
//        key_state = KEY_Down;//确认按下,切换到状态3
//      break;
//    } 
    
    /*状态3:按键按下到长按标志触发状态*/
    case KEY_Down:
    {
      if(KEY == 1)
      {
        key_state = KEY_Up;//切换到状态4
        //不是长按操作,则判断是不是双击操作
        if(Long_Press == FALSE)
        {
          //双击检测
          //前面已经单击一次,这次就判断为双击操作
          if(Click_Buf == TRUE)
          {
			KEY_flag = TRUE;
		    Double_Click  = TRUE;
          }
          else
          {
            //这是单击或双击的第一次点击,标志位置1
            Click_Buf = TRUE;
            //双击计时器开始计时
			Twice_Cnt = 20;
          } 
        }
      }
      else
      {
        //长按检测(一直在按下,第一次弹起不会触发)
        if(Long_Press == FALSE&&Click_Buf == FALSE)
        {
		  //1s时间到就判断为长按
          if(Long_Cnt<=0)
          {
			key_state = KEY_wait;//切换到状态4
			KEY_flag = TRUE;
            Long_Press = TRUE;
          }
        }
      }  
      break;  
    }
    
    /*状态4:标志触发到等待按键弹起状态*/
    case KEY_wait:
    {
      if(KEY == 1)
        key_state = KEY_Up;//完成一次按键动作,切换到状态1
      break;
    }
		
    default:
      key_state = KEY_Up;//默认情况都切换到状态1
      break;
  }
    //标志触发,反馈结果
    //PS:key_return属于外部全局变量,用于接受反馈信息
    if(KEY_flag == TRUE)
	{
		//单击动作
		if(Click == TRUE)
		    key_return = SHORT_KEY;
		//长按动作
		else if(Long_Press == TRUE)
			key_return = LONG_KEY;
		//双击动作
		else if(Double_Click == TRUE)
			key_return = DOUBLE_CLICK;
        //按键状态位清零,为下一次按下准备
        KEY_flag= FALSE;
        Click_Buf = FALSE;
        Click = FALSE;
        Long_Press = FALSE;
        Double_Click  = FALSE;
    }
}

三、代码讲解

为了使代码更加清晰,可读性更强,我将按键状态机的代码做了分区,分成了三个系统,分别是反馈系统,计时系统,状态系统。

理解要点:梳理好状态之间的切换关系,特别关注按键按下和弹起在状态机中是怎么检测的。

难点:1.Click_Buf的实际意义不是按键按下的标志,是按键弹起的标志。

           2.要区分状态和动作,按下既可以是状态也可以是动作,空闲是一种状态,弹起是一种动作。

在理解代码的时候可以把单击,双击,长按的路线走几遍,有助于理解。

四、作者的话

我们团队在学习状态机很痛苦,因为比较抽象难以理解,所以我们将学习经验分享,希望能对刚学习这方面内容的人有所帮助。

本人自学小白,如果有纰漏和错误,希望大佬们多多指教,欢迎大家一起交流。文章来源地址https://www.toymoban.com/news/detail-721949.html

到了这里,关于按键状态机(实现单击,长按,双击)的模块分享的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现

    Button拓展         今天来聊一下关于Button的事件拓展,这里只是拿Button来举例,Unity中其他的UI组件如Toggle、Slider等都也适用。         我们知道在Button中我们可以通过onClick的方式来添加点击事件,但在游戏开发过程中我们往往对Button有着更多的功能需求,比如说双击、

    2024年04月10日
    浏览(56)
  • Unity 单击、双击、长按事件处理

    想要一个工具,能够同时集成单击、双击、长按的功能 通过IPointerDownHandler, IPointerUpHandler, IPointerClickHandler这三个接口就可以监听点击状态,然后再通过不同的点击状态来处理相应的事件 由于可能同时存在多个事件,实际开发过程中会出现多余事件通知,如下: 同时拥有单击

    2024年02月11日
    浏览(56)
  • 用STM32单击按键实现LED闪烁和双击按键实现LED呼吸灯效果

    在嵌入式系统中,按键和LED是最常见的外设之一。本文将介绍如何使用STM32微控制器实现按键的单击和双击检测,并通过控制LED的闪烁和呼吸灯效果来呈现按键的触发效果。 第一部分:硬件准备 准备一块STM32开发板,如STM32F103C8T6。 连接一个按键到开发板上的GPIO引脚,并通过

    2024年02月05日
    浏览(80)
  • 【23物联网国赛样题第二套】单片机,CC2530单片机呼吸灯与按键控制--单击双击长按、呼吸灯与亮度维持,物联网竞赛今年历年国赛样题真题代码

    ZigBee节点盒通电或重置,节点盒的LED1、LED2灯都不亮。 长按SW1键不松开,LED1灯亮,LED2灯熄灭。 松开SW1键,LED1、LED2亮灯都常亮。 双击SW1可以控制LED1灯实现呼吸灯效果,LED2灯保持熄灭状态。 再次双击SW1可以控制LED1维持当前亮度不再发生变化,LED2继续保持熄灭状态。 将编写

    2024年02月08日
    浏览(54)
  • Unity3D实现UI的单击、双击、拖动状态判断

    这篇文章就来实现UI的单击、双击、按压、拖动的不同状态判断。不定时更新Unity开发技巧,觉得有用记得一键三连哦。 示例、 判断单击和双击,主要是判断点击的次数。 UI的点击事件,需要继承UI的点击事件接口,重写点击事件即可。 UI点击事件接口: 3-1-1 所引用的命名空

    2024年01月20日
    浏览(59)
  • 「Python|Selenium|场景案例」如何模拟鼠标单击、双击、右击、长按和拖拽等操作?

    本文主要介绍如何在使用selenium进行自动化测试的时候模拟各种鼠标操作。 在进行自动化测试的时候,我们可能会需要需要进行鼠标操作的场景,比如: 测试右击,查看是否网页是否屏蔽了右键菜单 面对滑块式登录验证方式,模拟拖拽 模拟前进或后退等鼠标扩展操作 ……

    2023年04月08日
    浏览(44)
  • 【虚拟仿真】Unity3D中实现UI的单击、双击、按压、拖动的不同状态判断

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 大家好,我是佛系工程师 ☆恬静的小魔龙☆ ,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 之前写了一篇在Unity中鼠标的单击、双击、拖动的文章:

    2024年02月06日
    浏览(66)
  • 微信小程序长按与单击事件触发

    方式一 wxml 片段 js 片段 解析 tap 触摸事件采用 catch 阻止事件冒泡 1.5.0之后支持 longpress 事件,手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 方式二(不推荐) longtap 事件,但在触发时会同时触发单击事件,需配合 touchstart 和

    2024年02月12日
    浏览(86)
  • 小程序更多的手势事件(左右滑动、放大缩小、双击、长按)

    微信小程序提供的原生事件有:触摸开始(bindtouchstart)、移动触摸点(bindtouchmove)、触摸结束(bindtouchend)以及长按事件(bindlongtap)和单击事件(bindtap)。通过以上原生事件可设计制作衍生出更多的手势事件; 文章记录小程序中组件 “左右滑动、放大缩小、双击” 事件

    2024年02月09日
    浏览(56)
  • 【FPGA零基础学习之旅#10】按键消抖模块设计与验证(一段式状态机实现)

    🎉欢迎来到FPGA专栏~按键消抖模块设计与验证 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ 🥝 模块设计: 🥝 按键消

    2024年02月12日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包