zoukankan      html  css  js  c++  java
  • 基于状态机的按键扫描的实现

    一般的按键输入软件接口程序非常简单,在程序中一旦检测到按键输入口为低电平(有时可能为高),便采用软件延时的方 法来进行消抖,然后再次检测按键输入,如果再次确认为低电平则表示有按键按下,转入执行按键处理程序。如果延时后检测的电平为高电平则放弃本次按键检测, 重新开始一次按键检测过程。在简单的系统中这种方法比较可以用,但是在复杂的系统实时性要求较高的系统中这种方法的CPU利用率比较低,造成资源的浪费。 另外,由于在不同的产品系统中对按键功能的定义和使用方式也会不同,而且是多变的,加上在测试和按键处理的同时,MCU还要同时处理其他的任务(如显示、 计算、计时等),因此编写键盘和按键接口的处理程序需要掌握有效的分析方法,具备较高的软件设计能力和程序编写的技巧。而采用状态机的方法是一种比较好的 方法。


    何为状态机

        关于状态机的一个极度确切的描述是它是一个有向图形,由一组节点和一组相应的转移函数组成,状态机通过响应一系列 事件而“运行”。每个事件都在属于“当前”节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些 节点中至少有一个必须是终态。当到达终态,状态机停止。

    状态机是一种概念性机器,它能采取某种操作来响应一个外部事件。具体采取的操作不仅能取决于接收到的事件,还能取决于各个 事件的相对发生顺序。之所以能做到这一点,是因为机器能跟踪一个内部状态,它会在收到事件后进行更新。为一个事件而响应的行动不仅取决于事件本身,还取决 于机器的内部状态。另外,采取 的行动还会决定并更新机器的状态。这样一来,任何逻辑都可建模成一系列事件/状态组合。

    状态机是软件编程中的一个重要概念。比如在一个按键命令解析程序中,就可以看做状态机,其过程如下:本来在A状态下,触发一个按键后切换到B,再触发另一个键后就切换到C状态,或者返回A状态。这是最简单的例子。其他的很多的程序都可以当做状态机来处理。

    状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详细如下:

    现态:是指当前所处的状态。

    条件:又称为“事件”。当一个条件满足,将会触发一个动作,或者执行一次状态的迁移。

    动作:条件满足后执行动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

    次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变为新的“现态”了。

    按键的状态机实现

    一个按键从键按下到松开的过程如下如所示。从图中可以看出,按键的按下和松开的过程都有抖动的干扰问题,因此要将它们消除。


        可将将按键抽象为4个状态:

    (1)    未按下,假定为S0

    (2)    确认有键按下,假定为S1

    (3)    键稳定按下状态,假定为S2

    (4)    键释放状态,假定为S3。

    (有时也可以抽象为3个状态S0,S1,S3)。

    在一个系统中按键的操作是随机的,因此系统软件中要对按键进行循环查询。在按键检测过程中需要进行消抖处理,消抖的延时处 理一般要10ms或20ms,因此取状态机的时间序列为10或20ms,这样不仅可以跳过按键消抖的影响,同事也远小于按键0.3-0.5S的稳定闭合 其,不会将按键过程丢失。

    假定键按下时端口电平为0,未按下时为1(或者相反)。通过状态机实现按键检测的过程如下:

    首先,按键的初始态为S0,当检测到输入为1时,表示没有键按下,保持S0。当按键输入为0时,则有键按下,转入状态S1。

    在S1状态时,如果输入的信号为1,则表示刚才的按键操作为干扰,则状态跳转到S0;如果输入信号为0,则表示确实有键按下,此时可以读取键状态,产生相应的按键标志或者将该事件存入消息队列。同时状态机切换到S2状态。

    在S2状态,如果输入信号为1,则没有键按下,切换到S3;如果输入信号为0,则保持S2状态,并进行计数。如果计数值超过一定的门限值,则可以认为该按键为长按键事件或者键一直按下状态,如果未超过门限值,则认为是短按键事件,保持S2状态。

    在S3状态,如果输入信号为高电平,则切换到S0.

    上面就是采用状态机进行按键检测的过程。简单程序如下:

    1. enum key_states_e{  
    2.     KEY_S1,  
    3.     KEY_S2,  
    4.     KEY_S3,  
    5.     KEY_S4  
    6. };  
    7. void key_scan(void)  
    8. {  
    9.     static enum key_states_e key_state=KEY_S1;  
    10.     static int press=0;  
    11.   
    12.     switch(key_state)  
    13.     {  
    14.         case KEY_S1:  
    15.             if(GPIO_ReadInputDataBit(g_keys[0].port, g_keys[0].gpio)==1)  
    16.                 {key_state = KEY_S2;  
    17.             }  
    18.             else  
    19.                 key_state = KEY_S2;  
    20.             break;  
    21.   
    22.         case KEY_S2:  
    23.             if(GPIO_ReadInputDataBit(g_keys[0].port, g_keys[0].gpio)==1){  
    24.                 key_state = KEY_S3;  
    25.                 trace_notice(MID_KEY,"press ");//相应的键操作处理程序  
    26.             }else  
    27.                 key_state = KEY_S1;  
    28.   
    29.             break;  
    30.   
    31.         case KEY_S3:  
    32.             if(GPIO_ReadInputDataBit(g_keys[0].port, g_keys[0].gpio)==1){  
    33.                 key_state = KEY_S3;  
    34.                 press++;  
    35.                 if(press>20){  
    36.                     trace_notice(MID_KEY,"press2 ");//相应的计数操作,判断长短按键  
    37.                 }  
    38.             }  
    39.             else  
    40.                 key_state = KEY_S4;  
    41.   
    42.             break;  
    43.   
    44.         case KEY_S4:  
    45.             if(GPIO_ReadInputDataBit(g_keys[0].port, g_keys[0].gpio)==1){  
    46.                 key_state = KEY_S1;  
    47.                 press = 0;  
    48.             }  
    49.             break;  
    50.   
    51.         default:  
    52.             key_state = KEY_S1;  
    53.             press = 0;  
    54.             break;  
    55.     }  




           在定时器中,定时10ms,定时到后在中断服务程序中调用上述函数,每次执行的间隔10ms,可以有效的消除消抖,提高CPU的利用率。

    同时可以将状态机应用于其他的程序中,一个串行通信的时序(不管它是遵循何种协议,标准串口也好、I2C也好;也不管它是 有线的、还是红外的、无线的)也都可以看做由一系列有限的状态构成。显示扫描程序也是状态机;通信命令解析程序也是状态机;甚至连继电器的吸合/释放控 制、发光管(LED)的亮/灭控制又何尝不是个状态机。

  • 相关阅读:
    Digital Video Stabilization and Rolling Shutter Correction using Gyroscope 论文笔记
    Distortion-Free Wide-Angle Portraits on Camera Phones 论文笔记
    Panorama Stitching on Mobile
    Natural Image Stitching with the Global Similarity Prior 论文笔记 (三)
    Natural Image Stitching with the Global Similarity Prior 论文笔记(二)
    Natural Image Stitching with the Global Similarity Prior 论文笔记(一)
    ADCensus Stereo Matching 笔记
    Efficient Large-Scale Stereo Matching论文解析
    Setting up caffe on Ubuntu
    Kubernetes配置Secret访问Harbor私有镜像仓库
  • 原文地址:https://www.cnblogs.com/alanfeng/p/4819887.html
Copyright © 2011-2022 走看看