打印

比武招更牛的按键扫描程序,大家都来试一试!!!

[复制链接]
4794|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
linfuchi|  楼主 | 2010-1-21 11:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 linfuchi 于 2010-1-22 09:53 编辑

没有最牛,只有更牛!
菜鸟需要写个键盘扫描程序提供如下几个接口参数,写了一份觉得啰嗦,没有“安全感”,很没自信,所以发了此贴。
有三个按键需要扫描,命名为SET,UP,DOWN吧。约定P0.0,P0.1,P0.2分别对应UP,SET,DOWN吧。对了,添加一条,不用判断按键释放。
要求是程序简洁,逻辑清晰正确,占用资源少,通用性强。
被拍了才能进步,大家都试试。

需要通过按键扫描提供如下几个接口参数
typedef enum
{
KEY_SET,
KEY_UP,   
KEY_DOWN,
KEY_SETTHREESECOND,     //SET键按住3秒以上
KEY_TIMEOUT,        // 检的按键之后,一分内再无任何按键按下
NOKEY                  //无按键记录,包括无按键按下,或者按键按下处理之后清除掉了
}KEY_TYPE;

嘿嘿,这是菜鸟前几天看到一个键盘扫描的帖子,按照那个思路做的,现学现卖,学的不好的话,还请前面的师傅原谅。哈哈。不过菜鸟不会调试程序,语法上没错误了,逻辑上的错误不知道怎么查。有愿意指点一下这么弱的问题的没有?有的话请详细一点。
我自己写的程序往往不知道好坏,的缺点在那,有什么BUG,请大家拍砖,我是大菜鸟,不怕砖头。听武林高手说要成为高手,要先学会挨揍。哈哈。

每20MS中断一次,执行按键扫描程序以及其他操作。

KEY_TYPE keyscan(void)
{
P0=0x07;       //p0跟LED显示复用,所以每次扫描之前重新初始化
KeyTemp=P0&0x07;
if(KeyTemp==0x07)
{
  if(LastKey==0x05)    //若SET键有作案记录,说明SET键未到3秒就释放了,嘿嘿
  {
   counttime=0;
   LastKey=0x07;
   return  KEY_SET;
  }
  count++;
  if(count==3000)
                {
                        count=0;
          return KEY_TIMEOUT;
                }
  else return NOKEY;
}
else
{
  if(KeyTemp==0x05)     //SET键被按下
  {
   if(counttime==150)
   {
    counttime=0;
    LastKey=0x07;
    return KEY_SETTHREESECOND;
   }
   counttime++;
   LastKey=KeyTemp;
  }
  else       //不是SET键
  {
   if(LastKey==KeyTemp)  //不是第一次检测到按下
   {
    if(KeyTemp==0x60)
    {
     LastKey=0x07;
     return KEY_UP;
    }
    else   
    {
     LastKey=0x07;
     return KEY_DOWN;
    }
   }
   else                         //第一次按下
   {
    LastKey=KeyTemp;
    return NOKEY;
   }
  }
}
}

相关帖子

沙发
wirus| | 2010-1-21 12:15 | 只看该作者
沙发?

使用特权

评论回复
板凳
红金龙吸味| | 2010-1-21 12:29 | 只看该作者
呼叫冷漠大侠。

使用特权

评论回复
地板
linfuchi|  楼主 | 2010-1-21 12:32 | 只看该作者
我昨天拜读了你的按键扫描程序,小弟受益匪浅!如何呼叫,我是刚来这论坛的新人,指点一二。

使用特权

评论回复
5
linfuchi|  楼主 | 2010-1-21 12:47 | 只看该作者
为什么没人试试呢?我的还没全做好,不然即使是砖也不是,也要拿出来引引玉。

使用特权

评论回复
6
mohanwei| | 2010-1-21 13:12 | 只看该作者
不过什么按键程序,状态机才是王道……

使用特权

评论回复
7
linfuchi|  楼主 | 2010-1-21 13:15 | 只看该作者
大虾止步,给晚辈上一课。

使用特权

评论回复
8
zhoujt| | 2010-1-21 15:02 | 只看该作者
看看学习一下,,

使用特权

评论回复
9
algr| | 2010-1-21 15:55 | 只看该作者
破按键 有啥好研究的
呵呵。。。

使用特权

评论回复
10
一只小绵羊| | 2010-1-21 16:01 | 只看该作者
吃饱了没事啊

使用特权

评论回复
11
linfuchi|  楼主 | 2010-1-21 16:23 | 只看该作者
9楼,其实你是感兴趣的,你是女的吧,不然怎么口是心非?

使用特权

评论回复
12
algr| | 2010-1-21 16:41 | 只看该作者
我是男的
咂啦
怎么口是心非了
口是心非怎么一定就是女的了。。。。

使用特权

评论回复
13
mohanwei| | 2010-1-21 16:57 | 只看该作者
远离是非贴……

参考这个:凑热闹我也发个使用状态机的键盘程序,支持单键和双键
https://bbs.21ic.com/icview-154761-1-1.html

使用特权

评论回复
14
IC_99| | 2010-1-21 17:43 | 只看该作者
嘿嘿,还没写过这样的键盘检测程序...

使用特权

评论回复
15
IRF9640| | 2010-1-21 18:52 | 只看该作者
.......

使用特权

评论回复
16
sedatefire| | 2010-1-21 22:12 | 只看该作者
typedef unsigned char UINT8;
typedef unsigned int UINT16;
static const KEY_TYPE keyTab[]=        // P.0        P0.1        P0.2
{
        NOKEY,                        // 0        0        0
        KEY_DOWN,                // 0        0        1
        KEY_SET,                // 0        1        0       
        NOKEY,                        // 0        1        1       
        KEY_UP,                        // 1        0        0       
        NOKEY,                        // 1        0        1       
        NOKEY,                        // 1        1        0       
        NOKEY                        // 1        1        1       
               
};

static UINT8 keyMap=0x00;
static UINT8 preKeyEvt=NOKEY;
static UINT16 keyHoldTmot=0;

vodi keyInit(void)
{
        // 设置p0.0 p0.1 p0.2内部上拉
        // 或者你外部有上拉电阻,按下接地
}

//  In 10ms Timer 请挂10ms定时器
void KeyScan(void)
{
        UINT8 map;
        // 1.采样且去抖动
        map = ~(P0&0x07);        // 取反使高位代表有按键,方便后面事件转换
        if (map != keyMap)       
        {//去抖动
                keyMap = map;
                return;
        }
        // 事件翻译
        if (preKeyEvt == NOKEY)
        {// 0==> x
                if (keyTab[keyMap] != NOKEY)
                {// 0-->1        keydown
                        EvtPost(keyTab[keyMap]);                               
                }
                else       
                {// 0-->0

                }
        }
        else
        {// 1==> x
                if (keyTab[keyMap] != NOKEY)
                {// 1-->1        keyHold       
                        if (++keyHoldTmot > (3000/10) )        // 3000ms/10ms
                        {
                                keyHoldTmot -= 500/10;        // 连续按键事件
                                if (preKeyEvt == KEY_SETTHREESECOND)
                                {
                                        EvtPost(preKeyEvt);                               
                                }       
                        }
                }
                else       
                {// 1-->0        keyup
                }               
        }                                       
}
void main(void)
{
        KeyInit();
        TimerInit();
        EvtQueInit();
        while(1)
        {
                __watchdog_reset();
                switch(EvtPend())
                {
                        case KEY_DOWN:
                                break;
                        case KEY_DOWN:
                                break;
                        case KEY_DOWN:
                                break;
                        //..........
                        default:
                                break;
                }
        }
}

使用特权

评论回复
17
sedatefire| | 2010-1-21 22:13 | 只看该作者
事件队列和10ms定时器自己写吧...

使用特权

评论回复
18
sedatefire| | 2010-1-21 22:17 | 只看该作者
// filename:         KeyScan.c
// author:           SedateFire
// date:         2010.01.21       
// Email:linuxhru@126.com         QQ:1047112716
typedef unsigned char UINT8;
typedef unsigned int UINT16;
static const KEY_TYPE keyTab[]=        // P.0        P0.1        P0.2
{
        NOKEY,                        // 0        0        0
        KEY_DOWN,                // 0        0        1
        KEY_SET,                // 0        1        0       
        NOKEY,                        // 0        1        1       
        KEY_UP,                        // 1        0        0       
        NOKEY,                        // 1        0        1       
        NOKEY,                        // 1        1        0       
        NOKEY                        // 1        1        1       
               
};

static UINT8 keyMap=0x00;
static UINT8 preKeyEvt=NOKEY;
static UINT16 keyHoldTmot=0;

vodi keyInit(void)
{
        // 设置p0.0 p0.1 p0.2内部上拉
        // 或者你外部有上拉电阻,按下接地
}

//  In 10ms Timer 请挂10ms定时器
void KeyScan(void)
{
        UINT8 map;
        // 1.采样且去抖动
        map = ~(P0&0x07);        // 取反使高位代表有按键,方便后面事件转换
        if (map != keyMap)       
        {//去抖动
                keyMap = map;
                return;
        }
        // 事件翻译
        if (preKeyEvt == NOKEY)
        {// 0==> x
                if (keyTab[keyMap] != NOKEY)
                {// 0-->1        keydown
                        EvtPost(keyTab[keyMap]);                               
                }
                else       
                {// 0-->0

                }
        }
        else
        {// 1==> x
                if (keyTab[keyMap] != NOKEY)
                {// 1-->1        keyHold       
                        if (++keyHoldTmot > (3000/10) )        // 3000ms/10ms
                        {
                                keyHoldTmot -= 500/10;        // 连续按键事件
                                if (preKeyEvt == KEY_SETTHREESECOND)
                                {
                                        EvtPost(KEY_SETTHREESECOND);                               
                                }       
                        }
                }
                else       
                {// 1-->0        keyup
                }               
        }                                       
}
void main(void)
{
        KeyInit();
        TimerInit();
        EvtQueInit();
        while(1)
        {
                __watchdog_reset();
                switch(EvtPend())
                {
                        case KEY_DOWN:
                                break;
                        case KEY_DOWN:
                                break;
                        case KEY_DOWN:
                                break;
                        //..........
                        default:
                                break;
                }
        }
}

使用特权

评论回复
19
sedatefire| | 2010-1-21 22:19 | 只看该作者
switch(EvtPend())
                {
                        case KEY_SET:
                                break;
                        case KEY_UP:
                                break;
                        case KEY_DOWN:
                                break;
                        //..........
                        default:
                                break;
                }

使用特权

评论回复
20
sedatefire| | 2010-1-21 22:35 | 只看该作者
要细纠起来的话bug还是很多的,这只是一个大体框架,你可以即兴发挥...
按键转移,跳键,切换,会造成误判,你可以再想想...
我改了一些bug,再放下程序..
//  In 10ms Timer 请挂10ms定时器
void KeyScan(void)
{
        UINT8 map;
        // 1.采样且去抖动
        map = ~(P0&0x07);        // 取反使高位代表有按键,方便后面事件转换
        if (map != keyMap)       
        {//去抖动
                keyMap = map;
                return;
        }
        // 2. 事件判断翻译
        if (preKeyEvt == NOKEY)
        {// 0 ==> x
                if (keyTab[keyMap] != NOKEY)
                {// 0-->1        keydown
                        EvtPost(keyTab[keyMap]);
                        preKeyEvt = keyTab[keyMap];                               
                }
                else       
                {// 0-->0
                }
        }
        else
        {// 1==> x

                if (keyTab[keyMap] != NOKEY)
                {// 1-->1        keyHold       
                        if (preKeyEvt == keyTab[keyMap])
                        { // the same key hold

                                if (preKeyEvt == KEY_SET)
                                {
                                        if (++keyHoldTmot > (3000/10) )        // 3000ms/10ms
                                        {
                                                keyHoldTmot -= 500/10;        // 连续按键事件
                                                EvtPost(KEY_SETTHREESECOND);                               
                                        }       
                                }
                                else
                                {
                                        keyHoldTmot = 0;
                                }
                        }
                        else
                        {// 快速切换按键  normal impossible
                                EvtPost(keyTab[keyMap]);        // keydown
                                preKeyEvt = keyTab[keyMap];
                        }
                }
                else       
                {// 1-->0        keyUp
                        keyHoldTmot = 0;
                        preKeyEvt = NOKEY;
                }               
        }                                       
}

使用特权

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

本版积分规则

43

主题

474

帖子

1

粉丝