打印

谁能提供好点的分层的按键检测程序!

[复制链接]
2415|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
快乐小小鱼|  楼主 | 2013-1-7 15:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
ayb_ice| | 2013-1-7 15:18 | 只看该作者
是你自己搞错了,按键扫键和按键解释本来就应该分开,程序上和逻辑上都应该分开

使用特权

评论回复
板凳
快乐小小鱼|  楼主 | 2013-1-7 16:55 | 只看该作者
#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的值来判断按键的操作,用状态机省去传统按键的延时去抖,也不在在按键的死等待,对程序时间的利用有很大的帮助,根据按键返回的状态值,事件可以在按键按下响应,也可以在按键弹起来响应,也可以实现连发、长按等功能。

使用特权

评论回复
地板
ZOUWEN1| | 2013-1-11 13:05 | 只看该作者
快乐小小鱼 发表于 2013-1-7 16:55
#define KEY0_PORT           PORTD
#define KEY0_DDR            DDRD
#define KEY0_PIN               PI ...

此处也可定义一个键盘的枚举类型,它是Key_State的取值,这样表达更合理,将程序中的case 0,case 1用枚举中的定义量来代替,增加它的物理意义。

使用特权

评论回复
5
chenyu988| | 2013-1-11 13:34 | 只看该作者
MARK

使用特权

评论回复
6
loveme1949| | 2013-1-11 16:29 | 只看该作者
我也是用的状态机,10ms定时器扫描一次,虽然有点占用资源,但是具有不重复等优点
        switch(flag_shuiwen)
          {
                   case 0        :
                 {
                        if(S_shuiwen==0)
                        {
                                 flag_shuiwen=1;
                                break;       
                        }
                        break;
                 }
                 case 1        :
                 {
                         if(S_shuiwen==0)
                         {
                                flag_shuiwen=2;       
                                 /*此处存放can发送程序 水温警报*/
                                 CAN_oder(can_shuiwen,open);
                                 flag_bug++;
                                break;
                         }
                        else
                        flag_shuiwen=0;
                        break;
                 }
                 case 2         :
                 {
                          if(S_shuiwen==1)
                        {
                          flag_shuiwen=0;
                          CAN_oder(can_shuiwen,off);
                          flag_bug--;
                        }

                 }
     }

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

14

主题

190

帖子

8

粉丝