Board logo

标题: 状态机做独立按键检测 [打印本页]

作者: bdxw0001    时间: 2010-5-27 14:55     标题: 状态机做独立按键检测

人机界面最重要的就是按键了,觉得按键做的最好的就是手机的按键了,有长按、敌探、连发等功能。还有组合等。一个好的按键程序用书本上学的按键检测方法已经不能适应工程的需要了,为此人们设计出一种状态机检测按键的方法。 在一个系统中按键是随机的,因此系统软件对按键要一直循环查询,由于按键检测过程需要进行消抖处理,因此取状态机的时间序列为10ms,这样不仅可以跳过按键抖动的影响,同时也小于0.3-0.5秒的稳定闭合期,不会将按键的操作过程丢失。 程序实现方法,用定时器定时10ms,每隔10ms检测一次按键,将一个按键的检测过程分为几个不同的状态,最简单的分为 初使状态-按键闭合确认状态-按键释放状态,如果要求按键实现的功能越多,状态也就越多 ,比如还有常用的长按状态。以下是一个状态机按键程序,仅供参考。 程序基于AVR单片机, key.h文件的一部分(文本转自IC网 )
#define KEY0_PORT           PORTD#define KEY0_DDR            DDRD#define KEY0_PIN               PIND#define KEY0                        PD0#define KEY1_PORT           PORTD#define KEY1_DDR             DDRD#define KEY1_PIN                PIND#define KEY1                        PD1#define KEY2_PORT           PORTD#define KEY2_DDR              DDRD#define KEY2_PIN                    PIND#define KEY2                   PD2#define KEY3_PORT           PORTD#define KEY3_DDR          DDRD#define KEY3_PIN                    PIND#define KEY3                   PD3#define KEY0_STATUS    (BIT_STATUS(KEY0_PIN,KEY0))#define KEY1_STATUS     (BIT_STATUS(KEY1_PIN,KEY1))#define KEY2_STATUS    (BIT_STATUS(KEY2_PIN,KEY2))#define KEY3_STATUS   (BIT_STATUS(KEY3_PIN,KEY3))#define KEY_SERIES_FLAG     200      //按键连发开始所需时间长度#define KEY_SERIES_DELAY    5       //按键连发的时间间隔长度//按键属性#define KEY_DOWN        0xA0#define KEY_LONG        0xB0#define KEY_LIAN        0xC0#define KEY_UP          0xD0#define KEY_LONG        0xB0#define KEY_LIAN        0xC0#define KEY_UP          0xD0#define NO_KEY          0x00#define KEY0_DOWN       0X01#define KEY1_DOWN       0X02#define KEY2_DOWN       0X03#define KEY3_DOWN       0X04#define KEY0_PRESS      (KEY_DOWN|KEY0_DOWN)#define KEY1_PRESS      (KEY_DOWN|KEY1_DOWN)#define KEY2_PRESS      (KEY_DOWN|KEY2_DOWN)#define KEY3_PRESS      (KEY_DOWN|KEY3_DOWN)key.c文件一部分static uchar Get_Key(void){    if (KEY0_STATUS==0) return KEY0_DOWN;    if (KEY1_STATUS==0) return KEY1_DOWN;    if (KEY2_STATUS==0) return KEY2_DOWN;    if (KEY3_STATUS==0) return KEY3_DOWN;    return NO_KEY;}uchar Key_Scan(void){    static uchar Key_State   = 0;        //按键状态    static uchar Key_Prev    = 0;        //上一次按键    static uchar Key_Delay   = 0;        //按键连发时间    static uchar Key_Series  = FALSE;    //标志连发开始    uchar Key_Press  = NO_KEY;           //按键值    uchar Key_Return = NO_KEY;           //按键返回值    Key_Press = Get_Key();    switch (Key_State)    {    case 0://按键初始态00        if (Key_Press !=NO_KEY)//有按键按下        {            Key_State = 1;//转到按键确认            Key_Prev  = Key_Press;//保存按键状态        }        break;    case 1://按键确认态01        if ( Key_Press ==Key_Prev )//确认和上次按键相同        {            Key_State = 2;//判断按键长按            //返回按键按下键值,按键按下就响应,如果想弹起来再响应            //可以在弹起来后再返回按键值            Key_Return = KEY_DOWN | Key_Prev;        }        else//按键抬起,是抖动,不响应按键        {            Key_State = 0;        }        break;    case 2://按键释放态10        if (Key_Press == NO_KEY )//按键释放了        {            Key_State = 0;            Key_Delay = 0;            Key_Series  = FALSE;            Key_Return  = KEY_UP | Key_Prev;      //返回按键抬起值            break;        }        if ( Key_Press ==Key_Prev )        {            Key_Delay++;            if ((Key_Series==TRUE) && (Key_Delay>KEY_SERIES_DELAY))            {                Key_Delay  = 0;                Key_Return = KEY_LIAN | Key_Press;  //返回连发的值                Key_Prev   = Key_Press;      //记住上次的按键.                break;            }            if (Key_Delay>KEY_SERIES_FLAG)            {                Key_Series = TRUE;                Key_Delay  = 0;                Key_Return = KEY_LONG | Key_Prev;   //返回长按后的值                break;            }        }    default :        break;    }    return Key_Return;}每10ms调用一次按键检测,根据Key_Return的值来判断按键的操作,用状态机省去传统按键的延时去抖,也不在在按键的死等待,对程序时间的利用有很大的帮助,根据按键返回的状态值,事件可以在按键按下响应,也可以在按键弹起来响应,也可以实现连发、长按等功能。
作者: ceetop518    时间: 2010-5-28 13:47

比较高深艾美特
作者: liliang9554    时间: 2010-6-2 14:48

开始还以为假的,原来是真的啊
http://www.21ic.com/invad/invad.htm
作者: 示波器探头    时间: 2010-6-23 19:15

不错不错,如果帖子的格式可以稍加编排就更方便阅读了
作者: 唯茹独尊    时间: 2010-6-24 03:56

马老师,这个状态图还不会怎么看?谢谢
作者: 清秋娃娃    时间: 2010-6-25 05:51

直接调用有阻塞的延时函数的确不可取.浪费CPU资源不说,更重要的是不好扩充功能.




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0