zoukankan      html  css  js  c++  java
  • 按键的状态机方法实现

      按键的状态机方法实现 为什么要使用状态机?使用状态机有啥好处?是不是装13? 要我说,很简单的一个按键,可以不必使用,要是你有很多按键,或者需要判断长按,短按,双击666,那么,状态机方法可以让你设计简洁,功能稳定,不会出现你自己测试好了,别人测试就会出问题;或者今天测试没有问题,第二天不稳定了,是不是很糟心?功能复杂势必会声明很多个变量一大丢,然后把功能也 写进按键处理里面,是不是很乱,不好读懂?按键识别就是按键部分,不要有任何功能上面的处理,要通过接口去传递。这么说,本文主要就是两个思想:状态机和接口。懂得人自然懂。下面详细说说,实例上菜。 开局一张图,内容全靠编。

    正确,合理的状态划分是做好任何功能的前提,根据按键全生命周期的发生顺序,我划分了上面4个状态。去抖大家都清楚,按键值持续2-30Ms才进入正式的识别按键值状态,否则退回idle状态。我说的是持续,不是间隔2--30Ms再次去确认一次。好了,我把程序里面需要用到的一些数据类型都贴出来吧:

      1 enum KEYDOWNSTATE
      2 {//按键状态机
      3 MKEY_IDLE, ///<待机状态
      4 MKEY_DELAY, ///<去抖状态
      5 MKEY_GETVALUE,///<取值状态
      6 MKEY_UNFIX ///<取值成功状态
      7 };
      8 typedef struct
      9 {
     10 unsigned char modeKey : 1;
     11 unsigned char levelKey : 1;
     12 unsigned char powerKey : 1;
     13 unsigned char datb3 : 1;
     14 unsigned char datb4 : 1;
     15 unsigned char datb5 : 1;
     16 unsigned char datb6 : 1;
     17 unsigned char datb7 : 1;
     18 }datbit; //使用位段
     19 typedef union {
     20 unsigned char bytedat;
     21 datbit data_bits;
     22 }ByteChar; //非常方便采集数据和取值的一个联合体
     23 enum EKEYVALUE
     24 {//按键值
     25 MMODE = 0XFE,
     26 MLEVEL = 0XFD,
     27 MREUSE = 0XFC,
     28 MPOWERON = 0XFB,
     29 MTEST = 0X07
     30 }; //无论是独立式按键还是adc方式,都会有个值或者范围
     31 enum EKEYTYPE
     32 {
     33 MNONE,
     34 MSHORTKEY = 0X13, //短按,随意定的一个值
     35 M2SKEY, //长按
     36 M10KEY, //复位按
     37 }; //代表着按键长按,短按,复位 
     38 typedef struct {
     39 bit getkeyFlag; //按键值获取成功
     40 ByteChar gkeyValueIn; //按键值
     41 UINT8 gDelayType; //根据按键delay长短确定的类型
     42 }keyInterface_t; 
     43 keyInterface_t keyInterface; //按键驱动模块与外部的接口
     44 /************************************************************************************************************
     45 * void keyDriver(void)
     46 * 注意:间隔10ms左右调用一下本函数
     47 * 本函数采用状态机方式编程,适合于独立按键,可以识别出长按,短按,超长10S按。
     48 ************************************************************************************************************/
     49   static void keyDriver(void)
     50 {
     51  ByteChar keyValueIn;
     52  keyValueIn.bytedat = 0xFF;
     53  keyValueIn.data_bits.modeKey = MODEKEY;
     54  keyValueIn.data_bits.levelKey = LevelKEY;
     55  keyValueIn.data_bits.powerKey = PowerKEY;
     56  switch (keyState)
     57  {
     58  case MKEY_IDLE: /* constant-expression */
     59  keyDownConts = 0;
     60  keyInterface.gDelayType = MNONE;
     61  if (keyValueIn.bytedat != 0xFF)
     62  {
     63  keyInterface.gkeyValueIn.bytedat = keyValueIn.bytedat;
     64  keyState = MKEY_DELAY;
     65  keyDownConts = 0;
     66  }
     67  break;
     68  case MKEY_DELAY: /* 去抖动 */
     69  if (keyInterface.gkeyValueIn.bytedat ==keyValueIn.bytedat)
     70  {
     71  keyDownConts++;
     72  }
     73  else
     74  {
     75  keyDownConts = 0;
     76  keyState = MKEY_IDLE;
     77  }
     78  if (keyDownConts > 3)
     79  {
     80  keyState = MKEY_GETVALUE;
     81  }
     82  break;
     83  case MKEY_GETVALUE: /* 进入判断按键 */
     84  keyDownConts++;
     85  if (keyDownConts > KEY10s) //如果是复原按,则无需等待松开按键
     86  {
     87  keyInterface.gDelayType = M10KEY; //复位按
     88  keyState = MKEY_UNFIX;
     89  }
     90  if (keyDownConts > KEY2s) //如果是长按,则无需等待松开按键
     91  {
     92  keyInterface.gDelayType = M2SKEY; //长按
     93  keyState = MKEY_UNFIX;
     94  }
     95  if (keyValueIn.bytedat == 0xFF)
     96  {
     97  keyUpConts++;
     98  }
     99  else
    100  {
    101  keyUpConts = 0;
    102  }
    103  if (keyUpConts > 2)
    104  {
    105  if (keyDownConts > KEYSHORTMIN &&keyDownConts < KEYSHORTMAX) //如果是短按,则需等待松开按键
    106  {
    107  keyInterface.gDelayType = MSHORTKEY; //短按
    108  keyState = MKEY_UNFIX;
    109  }
    110  else
    111  {
    112  keyState = MKEY_IDLE;
    113  }
    114  }
    115  break;
    116  case MKEY_UNFIX: /* 此状态代表按键可以正常取值 */
    117  _nop_();
    118  break;
    119  default:
    120  _nop_();
    121  break;
    122  }
    123 }

    再次总结一下,keyState变量就是交际花,在不同的状态切换;按键驱动模块与外部的接口keyInterface_t keyInterface ,使用一个结构体变量,实现了模块化。

    针对本文中所有的错误和不足,欢迎交流,交流技术和项目合作均可。等你来撩我哦!加我请说明来意,谢谢。

  • 相关阅读:
    Vue.js之Vue计算属性、侦听器、样式绑定
    Vue之初识Vue
    JS对象与Dom对象与jQuery对象之间的区别
    JavaScript之JS的数据类型
    JS中toString()、toLocaleString()、valueOf()的区别
    【开源】基于 Flink 1.10.1 的 SQL 提交程序
    Flink 1.10 UDF 的一个小问题
    Flink 1.10 SQL 写 Hbase 数据无法写入hbase问题
    Flink SQL 双流 join demo
    Flink SQL 解析复杂(嵌套)JSON
  • 原文地址:https://www.cnblogs.com/zhihui-3669/p/13525383.html
Copyright © 2011-2022 走看看