搜索
bottom↓
回复: 103

个人感觉最精炼的判键程序

[复制链接]

出0入0汤圆

发表于 2007-10-12 15:20:36 | 显示全部楼层 |阅读模式
typedef struct {
        unsigned char Name;
        void (*Func_CLOSE)(void);
        void (*Func_OPEN)(void);
        }BUTTON;

#define BUTTONmax 8
const BUTTON FunTab[BUTTONmax]={
         ~0x01,PA0_CLOSE,PA0_OPEN,
         ~0x02,PA1_CLOSE,PA1_OPEN,
         ~0x04,PA2_CLOSE,PA2_OPEN,
         ~0x08,PA3_CLOSE,PA3_OPEN,
         ~0x10,PA4_CLOSE,PA4_OPEN,
         ~0x20,PA5_CLOSE,PA5_OPEN,
         ~0x40,PA6_CLOSE,PA6_OPEN,
         ~0x80,PA7_CLOSE,PA7_OPEN,
         //可扩展组合键.
};

#define AllButtonOPEN 0xFF
unsigned char InputTimes,InputData=AllButtonOPEN,InputNew;
const BUTTON *pButton=FunTab;
void ScanInput(void)
{

if (InputData == PINA)
        {
        if (InputNew)
           {
           InputTimes++;
           if (InputTimes == 8) //判键的防抖动
                     {//确认一次按键.(包括按下和松开)
                  InputTimes = 0;
                  InputNew = 0;
                  if (InputData == AllButtonOPEN) pButton->Func_OPEN();
                  else
                            {
                          for (pButton = FunTab;pButton < FunTab+BUTTONmax;pButton++)
                                    {
                                  if (pButton->Name == InputData)
                                           {
                                         pButton->Func_CLOSE();
                                         break;
                                         }
                                  }
                          }
                  }
           }
        }
else
        {
        InputTimes = 0;
        InputData = PINA;
        InputNew = 1;
        }
}

在1ms的定时里扫描,效果还可以。在我编判键处理程序中,这个个人感觉最简单。代码量最少!漏洞自己暂时还没发现,路过的指点一二。呵呵,不要光看不说啊!

出0入0汤圆

发表于 2007-10-12 15:58:42 | 显示全部楼层
没用过struct.

出0入0汤圆

发表于 2007-10-12 16:03:26 | 显示全部楼层
只能用作单个键处理,组合键就没办法了。。。。。。
帮顶。

出0入0汤圆

发表于 2007-10-12 16:06:01 | 显示全部楼层
简单的东西复杂化了
你查看过没有,代码的时间与空间消耗估算过没有

出0入0汤圆

发表于 2007-10-12 16:25:18 | 显示全部楼层
组合键应该可以吧。。
个人觉得楼主的程序的确很精炼

出0入0汤圆

发表于 2007-10-12 16:39:25 | 显示全部楼层
帮顶
没有用过结构

出0入0汤圆

 楼主| 发表于 2007-10-12 17:16:42 | 显示全部楼层
组合键我没有用,但从我的原理上是可以实现的,有兴趣你自己添加。还有更好的思路,我洗耳恭听!

出0入0汤圆

发表于 2007-10-12 17:52:05 | 显示全部楼层
好文章,做个记号。

出0入0汤圆

发表于 2007-10-12 18:09:41 | 显示全部楼层
我的地盘我作主。?????????

出0入0汤圆

发表于 2007-10-12 18:17:42 | 显示全部楼层
抽象化不够,不应该在按键扫描时去做事件的处理

出10入120汤圆

发表于 2007-10-12 19:02:58 | 显示全部楼层
同意楼上的观点,很多时候是不应该立即响应处理的。

这样做程序结构会很差

出0入0汤圆

 楼主| 发表于 2007-10-12 19:28:11 | 显示全部楼层
我是这么想的,对于一些简单或者必须立即处理的事件,那必须在中断里处理掉。对于那些处理事件较长的,或者不是很要紧的,可在处理代码里做个标志,到主循环里来具体执行。我想对于工控项目,这么做应该是正常的了。以上尽代表个人意见,大家来发表自己的见解。

出10入120汤圆

发表于 2007-10-12 20:01:11 | 显示全部楼层
所有按键响应都没有必要是实时的,我一般用队列或者是邮箱来处理按键。

出0入0汤圆

发表于 2007-10-12 20:15:31 | 显示全部楼层
还可以了
不过有2个键先后按下,则只能认为是组合键,后一个按下的无法响应单键处理。
无法响应长按的情况。

出0入0汤圆

 楼主| 发表于 2007-10-12 20:35:17 | 显示全部楼层
楼上说的有道理,时间的控制还是没有办法的。
12楼makesoft说的我还不知道是怎么做的,能交流吗?

出10入120汤圆

发表于 2007-10-12 20:44:33 | 显示全部楼层
呵呵,很简单的,你去看看WINDOWS和DOS怎么处理按键的就可以了

出0入296汤圆

发表于 2007-10-12 20:52:01 | 显示全部楼层
我认为,应该把按键状态函数、按键的处理函数、按键的消息处理三个部分分开。
其中,按键的状态函数仅仅根据电平状态返回扫描码,不做任何去抖处理,这样可以使程序的编写更简单。
第二部分,按键的处理,包括缓冲区、长按键的判定、等等功能用一个统一的模块来处理——制作成库函数。该库函数需要第一部分的按键状态函数返回的扫描码信息作为输入。
第三部分,就是消息的处理,这个就因人而异了,你可以使用消息地图的方法,也可以简单用if来判断。总之,都是从缓冲区里面取数据。至于组合按键的问题,其实有很多种解决方案。有采用按键位图的KeyBitMap,有采取给组合按键独立的扫描码的。总之,方法很多,您可以根据实时性要求选择。

后面,我就粘贴一个我编写的按键处理模块(也就是前面所说的第二部分)。该模块需要外界通过宏的方式提供一个扫描码输入接口,最终,处理后的按键信息会被放置到队列中。

出0入296汤圆

发表于 2007-10-12 20:52:52 | 显示全部楼层
RD_UseKey.h
--------------------------------------------------------------




#ifndef _USE_KEY_H_
#define _USE_KEY_H_
/***********************************************************
*   声明库说明:按键处理声明库                             *
*   版本:      v2.00                                      *
*   作者:      傻孩子                                     *
*   创建日期:  2005年11月27日                             *
* -------------------------------------------------------- *
*  [支 持 库]                                              *
*   支持库名称:LIB_Config.h                               *
*   需要版本:  ----                                       *
*   支持库说明:库函数配置声明库                           *
* -------------------------------------------------------- *
*  [版本更新]                                              *
*   修改:      傻孩子                                     *
*   修改日期:  2006年4月15日                              *
*   版本:      v1.3                                       *
*                                                          *
*   修改:      傻孩子                                     *
*   修改日期:  2006年4月23日                              *
*   版本:      v1.31                                      *
*                                                          *
*   修改:      傻孩子                                     *
*   修改日期:  2006年5月5日                               *
*   版本:      v1.32                                      *
*                                                          *
*   修改:      王卓然                                     *
*   修改日期:  2007年2月25日                              *
*   版本:      v2.00                                      *
* -------------------------------------------------------- *
*  [版本历史]                                              *
*     v1.3以下  1、提供了对键盘缓冲区的支持。              *
*               2、支持长按键处理。                        *
*               3、需要外部提供一个毫秒级的延时计数器。    *
*               4、需要外部提供一个有返回值得键盘扫描      *
*                  函数,该函数需要做基本的去抖。          *
*               5、可以外部定义缓冲区大小,空键值。        *
*               6、增加了一个入口键盘扫描码的噪声抑制参    *
*                 KEY_PRESS_DELAY,该值为毫秒级的单向      *
*                 递减数值,即如果值不为零,则减到0为。    *
*                 如果键盘响应过于迟钝,可以适当改小该     *
*                 参数值。                                 *
*     v1.3      修改了头文件的组织形式,对外的接口模式     *
*               对一些时间计数器进行了分类和统一宏定义     *
*               允许外部通过宏定义将这些接口连接到实际     *
*               的计数器上。同时兼容从前的版本。           *
*     v1.31     修正了按键去抖计数器会干扰外部单向计数     *
*               器的错误。                                 *
*     v1.32     允许选择自动刷新按键和手动刷新按键两种模式 *
*     v2.00     支持长按键以重复的间隔触发。               *
* -------------------------------------------------------- *
*  [说    明]                                              *
*            1、在外部合适的位置(毫秒中断程序)增加         *
*               USEKEY_INSERT_MS_TIMER_OVF_ISR_CODE来保证  *
*               头文件的正常使用。                         *
*            2、可以通过定义KEY_BUFF_SIZE来设置键盘缓冲区  *
*               的大小。                                   *
*            3、可以通过定义KEY_PRESS_DELAY来设置去抖得    *
*               时间常数。                                 *
*            4、可以通过_USE_KEY_PRESS_SCAN_FUNC_INTERFACE *
*               来连接用于键盘扫描的函数。该函数必须返回   *
*               扫描码。                                   *
*            5、通过GetKeyCode()函数来获得缓冲区状态,当   *
*               该函数返回True时,可以从ReturnKeyNum和     *
*               ReturnLongPressKeyNum中分别获取按键和长    *
*               按键的扫描码,两个值不能同时不为KeyNull    *
*            6、允许通过_USE_KEY_MANUL_REFRESH来选择自动刷 *
*               新按键缓冲区的模式。                       *
*            7、可以通过宏_USE_KEY_LONG_PRESS_DELAY_TIME来 *
*               定义长按键的最小判定时间。                 *
*            9、可以通过宏_USE_KEY_LONG_PRESS_REPEAT来打开 *
*               长按键重复触发功能。                       *
*            8、宏_USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL可  *
*               以用来设定长按键时重复触发的最小时间间隔等 *
*               级。取值范围是0至4,数值越大,时间间隔越小 *
*               默认情况下为2,即一秒钟重复4次。           *
***********************************************************/


/********************
* 头 文 件 配 置 区 *
********************/
# include "RD_MacroAndConst.h"

/********************
*   系 统 宏 定 义  *
********************/

/*------------------*
*   常 数 宏 定 义  *
*------------------*/

/*------------------*
*   动 作 宏 定 义  *
*------------------*/
#ifndef _USE_KEY_MANUL_REFRESH
    # define USEKEY_INSERT_MS_TIMER_OVF_ISR_CODE  do\
             {\
                Add_Key_Code();\
                g_wKeyPressTimeCounter++;\
                if (g_wKeyPressDelayCounter) g_wKeyPressDelayCounter--;\
             }while(0);
#else
    # define USEKEY_INSERT_MS_TIMER_OVF_ISR_CODE
#endif

/********************
*   函 数 引 用 区  *
********************/
extern void Add_Key_Code(void);
extern unsigned char Get_Key_Code(void);

/********************
*   全局变量引用区  *
********************/
extern unsigned char g_cReturnKeyNum;
extern unsigned char g_cReturnLongPressKeyNum;

extern unsigned int g_wKeyPressTimeCounter;
extern unsigned int g_wKeyPressDelayCounter;

#endif

出0入296汤圆

发表于 2007-10-12 20:53:25 | 显示全部楼层
RD_UseKey.c
------------------------------------------------------------------------


/********************
* 头 文 件 配 置 区 *
********************/
# include "RD_MacroAndConst.h"
# include "LIB_Config.h"
# include "RD_UseKey.h"

/********************
*   系 统 宏 定 义  *
********************/


/*------------------*
*   常 数 宏 定 义  *
*------------------*/
#ifndef KEY_BUFF_SIZE
    # define KEY_BUFF_SIZE     8
#endif
#ifndef KEY_NULL
    # define KEY_NULL         0xff
#endif

#ifndef KEY_PRESS_DELAY
    # define KEY_PRESS_DELAY  50
#endif

#ifndef _USE_KEY_LONG_PRESS_DELAY_TIME
    # define _USE_KEY_LONG_PRESS_DELAY_TIME     1000
#endif
#ifndef _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL
    # define _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL 2
#endif

#if _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL == 0
    # define _USE_KEY_LONG_PRESS_FASTEST_SPEED 0x03ff
#elif _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL == 1
    # define _USE_KEY_LONG_PRESS_FASTEST_SPEED 0x01ff
#elif _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL == 2
    # define _USE_KEY_LONG_PRESS_FASTEST_SPEED 0x00ff
#elif _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL == 3
    # define _USE_KEY_LONG_PRESS_FASTEST_SPEED 0x007f
#elif _USE_KEY_LONG_KEY_FASTEST_SPEED_LEVEL == 4
    # define _USE_KEY_LONG_PRESS_FASTEST_SPEED 0x003f
#else
    # define _USE_KEY_LONG_PRESS_FASTEST_SPEED 0x00ff
#endif

/********************
*   函 数 声 明 区  *
********************/
static void _Key_Scan(void);

/********************
*   函 数 声 明 区  *
********************/
void Add_Key_Code(void);
unsigned char Get_Key_Code(void);

/********************
*   函 数 引 用 区  *
********************/
#ifndef _USE_KEY_PRESS_SCAN_FUNC_INTERFACE
    # error Need for _USE_KEY_PRESS_SCAN_FUNC_INTERFACE
#else
    extern unsigned char _USE_KEY_PRESS_SCAN_FUNC_INTERFACE(void);
#endif

/********************
*   全局变量声明区  *
********************/
unsigned char g_cReturnKeyNum = KEY_NULL;
unsigned char g_cReturnLongPressKeyNum = KEY_NULL;
unsigned int g_wKeyPressTimeCounter = 0;
unsigned int g_wKeyPressDelayCounter = 0;

/********************
*   模块变量声明区  *
********************/
static unsigned char s_cKeyBUFF[KEY_BUFF_SIZE][2];
static unsigned char s_cKeyBUFFCounter = 0;
static unsigned char s_cKeyBUFFHeadPoint = 0;
static unsigned char s_cKeyBUFFTailPoint = 0;

static unsigned char s_cLongKeyPressNum = KEY_NULL;
static unsigned char s_cKeyNum = KEY_NULL;


/***********************************************************
*   函数说明:按键扫描码处理函数                           *
*   输入:    无                                           *
*   输出:    无                                           *
*   调用函数:_USE_KEY_PRESS_SCAN_FUNC_INTERFACE()         *
* -------------------------------------------------------- *
*   [说    明]                                             *
*            按下一个键以后,1s以内松开返回短按键键值      *
*            1s以上返回长按键键值。键值只保存一个周期      *
***********************************************************/
static void _Key_Scan(void)
{
    static unsigned char OldKeyCode = KEY_NULL;
    static unsigned char IfLongKeyPress = FALSE;
    static unsigned int  LongPressAcceleration = 0;
         
    unsigned char NowKeyCode = _USE_KEY_PRESS_SCAN_FUNC_INTERFACE();
    s_cKeyNum = KEY_NULL;
       
    if ((OldKeyCode != NowKeyCode) && (g_wKeyPressDelayCounter == 0))
    {
        g_wKeyPressTimeCounter = 0;
        LongPressAcceleration = 0x03ff;
         
        if ((NowKeyCode == KEY_NULL) && (IfLongKeyPress == FALSE))
        {
            s_cKeyNum = OldKeyCode;
        }
                  
        g_wKeyPressDelayCounter = KEY_PRESS_DELAY;
                  
        OldKeyCode = NowKeyCode;
        IfLongKeyPress = FALSE;
    }
    else
    {
        s_cKeyNum = KEY_NULL;
        if ((g_wKeyPressTimeCounter > _USE_KEY_LONG_PRESS_DELAY_TIME) && (IfLongKeyPress == FALSE))
        {
            #ifdef _USE_KEY_LONG_PRESS_REPEAT
            if (LongPressAcceleration > _USE_KEY_LONG_PRESS_FASTEST_SPEED)
            {
                LongPressAcceleration >>= 1;
            }
            #endif
            s_cLongKeyPressNum = NowKeyCode;
            IfLongKeyPress = TRUE;
        }
        else
        {
            #ifdef _USE_KEY_LONG_PRESS_REPEAT
            if (!(g_wKeyPressTimeCounter & LongPressAcceleration))
            {
                IfLongKeyPress = FALSE;
            }
            else
            {
                s_cLongKeyPressNum = KEY_NULL;
            }
            #else
            s_cLongKeyPressNum = KEY_NULL;   
            #endif
        }
    }
         
}

/***********************************************************
*   函数说明:键盘缓冲处理函数                             *
*   输入:    无                                           *
*   输出:    无                                           *
*   调用函数:_Key_Scan()                                  *
***********************************************************/
void Add_Key_Code(void)
{
    _Key_Scan();
   
        if ((s_cKeyNum == KEY_NULL) && (s_cLongKeyPressNum == KEY_NULL))
        {
            return ;
        }
       
        if ((s_cKeyBUFFHeadPoint == s_cKeyBUFFTailPoint) && (s_cKeyBUFFCounter != NULL))
        {
            return ;
        }
       
        s_cKeyBUFF[s_cKeyBUFFTailPoint][0] = s_cKeyNum;
        s_cKeyBUFF[s_cKeyBUFFTailPoint][1] = s_cLongKeyPressNum;
       
        s_cKeyBUFFTailPoint ++;
        if (s_cKeyBUFFTailPoint == KEY_BUFF_SIZE)
        {
            s_cKeyBUFFTailPoint = 0;
        }
        s_cKeyBUFFCounter ++;
}

/***********************************************************
*   函数说明:从键盘缓冲区中获得一个按键扫描码             *
*   输出:    返回操作是否成功TRUE / FALSE                 *
*   输入:    无                                           *
*   调用函数:Add_Key_Code()                               *
* -------------------------------------------------------- *
*   [说    明]                                             *
*             将按键扫描码放到专门的临时缓冲变量中         *
***********************************************************/
unsigned char Get_Key_Code(void)
{
    g_cReturnKeyNum = KEY_NULL;
    g_cReturnLongPressKeyNum = KEY_NULL;
       
        #ifdef _USE_KEY_MANUL_REFRESH
            Add_Key_Code();
        #endif
       
        if ((s_cKeyBUFFHeadPoint == s_cKeyBUFFTailPoint) && (s_cKeyBUFFCounter == NULL))
        {
            return FALSE;
        }

    g_cReturnKeyNum = s_cKeyBUFF[s_cKeyBUFFHeadPoint][0];
        g_cReturnLongPressKeyNum = s_cKeyBUFF[s_cKeyBUFFHeadPoint][1];
                       
        s_cKeyBUFFCounter--;
        s_cKeyBUFFHeadPoint++;
        if (s_cKeyBUFFHeadPoint == KEY_BUFF_SIZE)
        {
            s_cKeyBUFFHeadPoint = 0;
        }
                       
    return TRUE;
}

出0入296汤圆

发表于 2007-10-12 20:57:34 | 显示全部楼层
使用范例1:

void main(void)
{
    ……
    while(1)
    {
         if (Get_Key_Code())      //判断缓冲区中是否有按键
         {
              switch (g_cReturnKeyNum)   //处理普通按键
              {
                   ……
              }
              
              switch (g_cReturnLongPressKeyNum)  //处理长按键
              {
                   ……
               }
         }
    }
}


使用范例2:


//片上调试时候,用于实现断点功能

/*在这里输出某些信息,并暂停,便于观察*/
while(!Get_Key_Code());              //所谓的按任意键继续

出0入0汤圆

发表于 2007-10-12 21:04:17 | 显示全部楼层
我的跟傻孩子的处理方式类似

但在对长短按的处理上使用了映射,所以空间和时间上会更省一些资源……

出0入296汤圆

发表于 2007-10-12 21:19:54 | 显示全部楼层
代码粘贴出来看看哈^_^

出0入0汤圆

 楼主| 发表于 2007-10-12 21:24:45 | 显示全部楼层
还是内容多的好啊,我完全不在一个级别上。学习下先......

出0入0汤圆

发表于 2007-10-12 21:34:31 | 显示全部楼层
传说中的键盘得呢。。。。
期待什么是映射

小系统。。。 专职专用。。中断->keycode->程序->返回主程序。简单

此帖学习。以后用。。。

出0入0汤圆

发表于 2007-10-13 02:04:00 | 显示全部楼层
简单说一下吧,代码不在这台电脑上

使用映射的话,需要建立一个数组存储按键本身的属性,然后再建立一个枚举来定义各种事件,一个按键长按和短按分别就是一个事件

这样就无需再去判断按键到底是处于什么状态了,更改按键的时候也只需要更改按键属性数组和按键事件定义枚举就可以了

出0入0汤圆

发表于 2007-10-14 08:49:20 | 显示全部楼层
学习!学习!

出0入4汤圆

发表于 2007-10-15 11:13:31 | 显示全部楼层
Gorgon Meducer 傻孩子,是做那个行业的,代码非常优美

出0入0汤圆

发表于 2007-10-15 12:25:15 | 显示全部楼层
标记一下,以后需要时再研究

出0入0汤圆

发表于 2007-10-15 13:17:09 | 显示全部楼层
Gorgon Meducer 傻孩子 的程序真不错

出0入0汤圆

发表于 2007-10-15 14:32:51 | 显示全部楼层
建设使用switch--case来处理.选优化模式时编译器会为它们产生散列,效率很高,可读性也好.

出0入0汤圆

发表于 2007-10-15 22:16:49 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-4-23 19:57:13 | 显示全部楼层
Gorgon Meducer 傻孩子 这个不错啊,学习了

出0入0汤圆

发表于 2010-4-23 20:53:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-23 21:01:01 | 显示全部楼层
都很精彩,谢谢~

出0入4汤圆

发表于 2010-4-23 21:05:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-23 21:07:31 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-4-23 21:08:45 | 显示全部楼层
学习

出0入264汤圆

发表于 2010-4-23 21:09:14 | 显示全部楼层
学习了。

出0入0汤圆

发表于 2010-4-23 21:12:55 | 显示全部楼层
学习一下

出0入0汤圆

发表于 2010-4-23 21:15:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-23 21:37:59 | 显示全部楼层
学习.

出0入0汤圆

发表于 2010-4-23 21:45:38 | 显示全部楼层
其实楼主是在创建一个 OnKeydown 和 OnKeyup 事件,和傻孩子所给出的代码完全不是一个概念....
从思路上讲,LZ是采用了上位机面向对象编程的理念。
不可否认,这种方式占用极少的代码量,在某种意义上来讲,傻孩子的代码是达不到这种效果的。
但LZ在处理OnKeydown事件时,代码还不够精减,既然用了查表的方式,就直接由按键锁定到函数吧,为什么还要再用循环去查找呢,有点画蛇添足了,我觉得改为以下处理方式比较妥当:也顺便顶一下楼主;

typedef struct
{
   unsigned char Name;
   void (*Func_CLOSE)(void);
   void (*Func_OPEN)(void);
} BUTTON;

#define BUTTONmax 8                   //最多响应按键个数;
#define dfStructLEN sizeof(BUTTON)    //按键结构长度;新增加的,便于直接定位到OnKeydown函数;
const BUTTON FunTab[BUTTONmax]={      //键值及 事件入口
     ~0x01,PA0_CLOSE,PA0_OPEN,
     ~0x02,PA1_CLOSE,PA1_OPEN,
     ~0x04,PA2_CLOSE,PA2_OPEN,
     ~0x08,PA3_CLOSE,PA3_OPEN,
     ~0x10,PA4_CLOSE,PA4_OPEN,
     ~0x20,PA5_CLOSE,PA5_OPEN,
     ~0x40,PA6_CLOSE,PA6_OPEN,
     ~0x80,PA7_CLOSE,PA7_OPEN
     //可扩展组合键.
};
#define AllButtonOPEN 0xFF   //无按键时的键值
unsigned char InputTimes,InputData=AllButtonOPEN,InputNew;
const BUTTON *pButton=FunTab;   //先将函数默认到第一个按键-----其实符值完全多余;
void ScanInput(void)
{
    if (InputData == PINA)
    {
        if (InputNew)
        {
            InputTimes++;
            if (InputTimes == 8) //判键的防抖动
            {//确认一次按键.(包括按下和松开)
                InputTimes = 0;
                InputNew = 0;
                if (InputData == AllButtonOPEN) //处理OnKeyup事件
                {
                    pButton->Func_OPEN();                 //键盘松开事件;
                }
                else           //处理 OnKeydown事件;
                {                 //键盘事件;  
                    pButton=FunTab+(dfStructLEN*InputData);       
                    pButton->Func_CLOSE();
                 }
             }
        }
    }
    else
    {
        InputTimes = 0;
        InputData = PINA;
        InputNew = 1;
    }
}

出0入0汤圆

发表于 2010-4-23 23:02:58 | 显示全部楼层
刚才笔误,还要对键值进行处理,让它与入口地址对应, 应该是  
unsigned char chKeyP(unsigned char InpuData)
{
    unsigned char i;
    for(i=0;i<8;i++)            //晕了,还得用循环.....
    {                           //我平时在键扫函数内直接返回0,1,2~XXX包括组合键功能码,那样可以直接省去些处转换....
       if(InpuData&(1<<i))
       {
           return i;
       }
    }
    return 0;
}
pButton=FunTab+(dfStructLEN*(chKeyP(InputData))); 才能执行出正确结果,

又是挖坟挖出来的.......

其实这种思路要与鼠标和触屏相结合,其效果才能得到更好的发挥,可以做出复杂的各式各样的响应事件来(不过这些现在都交给操作系统做了)。
虽然只这些代码还远远不够,但这已是一个事件处理的雏形,和只检测是否有键按下然后做相应处理已是完全不同的概念....

出0入0汤圆

发表于 2010-4-23 23:16:58 | 显示全部楼层
mark~

出0入0汤圆

发表于 2010-4-24 08:24:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-24 08:58:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-24 09:23:51 | 显示全部楼层
【41楼】 flywater 落叶
积分:265
派别:
等级:------
来自:天堂

解释的很好啊。

我觉得这是一个多功能按键处理核。。。。。。。。。。。。。。。。
结构体中还可定义其他元素,实现更多控制,如长按多长时间。。。。。

出0入0汤圆

发表于 2010-4-24 09:56:02 | 显示全部楼层
学习下

出0入0汤圆

发表于 2010-4-24 12:52:33 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-4-24 14:32:41 | 显示全部楼层
回复【46楼】jishanlaike 阿弱
-----------------------------------------------------------------------

嗯,只结构体稍做修改,再增加对InputTimes的判断,就可以轻松实现长按,双击,三击,键按下,键弹起等多种按键触发事件的处理,
如果上述这些功能用傻孩子所给代码去实现的话,要费的就不只是代码空间的事了....

出0入0汤圆

发表于 2010-4-24 17:30:47 | 显示全部楼层
记号!

出0入0汤圆

发表于 2010-4-24 19:33:49 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-24 19:40:25 | 显示全部楼层
好动许

出0入0汤圆

发表于 2010-4-24 21:14:04 | 显示全部楼层
按键随用随写就行了,没必要做大而全。

出0入0汤圆

发表于 2010-4-24 21:20:51 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-4-24 21:47:47 | 显示全部楼层
咋高手这么多呢,越看越自卑了,虚心学习,傻孩子键盘扫描

出0入0汤圆

发表于 2010-4-24 23:05:14 | 显示全部楼层
谢啦~~~

出0入0汤圆

发表于 2010-4-25 00:43:45 | 显示全部楼层
学习中

出0入0汤圆

发表于 2010-4-25 00:47:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-25 01:17:18 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-25 11:23:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-25 13:53:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-25 14:45:42 | 显示全部楼层
很好,学习了~

出0入0汤圆

发表于 2010-4-25 15:16:57 | 显示全部楼层
回复【楼主位】stud1 江南孤舟
-----------------------------------------------------------------------

dddddddd

出0入0汤圆

发表于 2010-4-25 16:49:06 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-4-25 17:05:30 | 显示全部楼层
标记下

出0入0汤圆

发表于 2010-4-30 21:39:32 | 显示全部楼层
我想请问一下LZ的程序里
pButton->Name == InputData 这里这个“->”是什么运算符?
谢谢了!

出0入0汤圆

发表于 2010-4-30 22:40:50 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-4-30 23:18:24 | 显示全部楼层
挖坟党

出0入0汤圆

发表于 2010-5-1 00:58:23 | 显示全部楼层
dff

出0入0汤圆

发表于 2010-5-1 11:40:53 | 显示全部楼层
学习 MARK

出0入0汤圆

发表于 2010-5-1 13:54:53 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-1 16:02:18 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-1 17:08:09 | 显示全部楼层
mark ,按键处理

出0入0汤圆

发表于 2010-5-1 22:43:16 | 显示全部楼层
都是强人啊,记号之。。。。。

出0入0汤圆

发表于 2010-5-4 21:29:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-4 22:26:57 | 显示全部楼层
这个要学习,一直觉得按键部分不是很清楚,

出0入0汤圆

发表于 2010-5-5 10:32:24 | 显示全部楼层
kk

出0入0汤圆

发表于 2010-5-5 10:52:52 | 显示全部楼层

出0入0汤圆

发表于 2010-5-5 12:47:16 | 显示全部楼层
ding

出0入0汤圆

发表于 2010-5-5 13:01:38 | 显示全部楼层
标记一下 回家学习去

出0入0汤圆

发表于 2010-5-5 13:02:52 | 显示全部楼层

出0入0汤圆

发表于 2010-5-5 13:20:54 | 显示全部楼层
回复【49楼】flywater 落叶
回复【46楼】jishanlaike 阿弱
-----------------------------------------------------------------------
嗯,只结构体稍做修改,再增加对inputtimes的判断,就可以轻松实现长按,双击,三击,键按下,键弹起等多种按键触发事件的处理,
如果上述这些功能用傻孩子所给代码去实现的话,要费的就不只是代码空间的事了....
----------------------------------------------------------------------

能否再辛苦一下, 增加一个 “长按,双击”的示范代码?

出0入0汤圆

发表于 2010-5-5 14:14:10 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-5 16:01:51 | 显示全部楼层
ding!

出0入0汤圆

发表于 2010-5-5 16:13:48 | 显示全部楼层
好。。。

出0入0汤圆

发表于 2010-5-5 16:31:23 | 显示全部楼层
#define  TK                                20                        //主程序执行时间8ms  //8
#define  timer20ms          (100/TK)                //延时时间20ms       //(30/TK)
#define  timer100ms          (1000/TK)        //延时时间100ms      //(1000/TK)
#define  timer200ms         (1200/TK)        //延时时间3S         //(1200/TK)
KEY                KeyDat;                   //定义数据结构





/***************************
【函数】:HC166_read(void)
【功能】:HC166驱动与硬件相关
【参数】:无
***************************/
unsigned char HC166_read(void)//HC166_read
{
  unsigned char i,set,k;
  H595_CP_L;        //L cp底电平   
  H595_PCLK_L;  //L PCLK时钟低电平
  H595_PCLK_H;  //H PCLK//时钟高电平,上升沿有效
  H595_CP_H;        //H cp高电平   
  for(i = 0, set = 0; i < 8;i ++)//依次读取锁存的8位数据
  {
    set <<= 1;
          if (!HC66_GET)set ++;
    H595_PCLK_L;//L PCLK时钟低电平
    H595_PCLK_H;//H PCLK//时钟高电平,上升沿有效
  }
  switch(set) //读取扫描值
  {
    case 0x00:      k=0x00;  break; //
    case K_Run:     k=0x01;  break; //GetRun
    case K_Stop:    k=0x02;  break; //GetStop
    case K_Down:    k=0x03;  break; //GetDown
    case K_Up:      k=0x06;  break; //GetUp
    case K_Enter:   k=0x07;  break; //GetEnter
    case K_Enter+K_Up:      k=0x09;  break; //组合键K_Enter+K_Up
    case K_Enter+K_Down:    k=0x10;  break; //组合键K_Enter+K_Down
    default:        k=0x00;  break; //点亮LED2
  }
  return k;
}


/***************************
【函数】:GetKey(void)
【功能】:判断是否有按键
【参数】:无
***************************/
void GetKey(void)
{
  if(HC166_read()!=0)       //读按键
  {
    KeyDat.KeyDog=timer20ms;  //给延时计数器赋值
    KeyDat.KeyPower++;              //进入下个函数Key_Dog(void)
  }
}

/***************************
【函数】:KeyDog(void)
【功能】:按键延时
【参数】:无
***************************/
void Key_Dog(void)
{
  if(0==--KeyDat.KeyDog)        //延时
  {
    KeyDat.KeyData=HC166_read();
    KeyDat.KeyTemp=KeyDat.KeyData;//备份键值 判断组合健
    if(HC166_read()!=0)                        //2次读键盘
    {
      KeyDat.KeyPower++;        //进入下个函数KeyOffShort(void)
      KeyDat.KeyDog=timer200ms; //给延时计数器再次赋值
    }
    else
    {
      KeyDat.KeyPower=0;                //按键无效返回重新扫描
      KeyDat.KeyData=0;         //按键无效按键数据清0
    }       
  }
}

/***************************
【函数】:KeyOffShort(void)
【功能】:判断按键是否松开
【参数】:无
***************************/
void KeyOffShort(void)
{
  if(HC166_read()==0)       //判断按键松开
  {
    KeyDat.KeyData|=HaveKey;//定义短击标记
    KeyDat.KeyPower=0;                //按键确认返回重新扫描
  }
  else
  {
          if(0==--KeyDat.KeyDog)     //延时 是上次延时的叠加
          {
      KeyDat.KeyDog=timer100ms;//给延时计数器再次赋值
      KeyDat.KeyPower++;       //进入下个函数KeyOffLong(void)
          }
  }
}

/***************************
【函数】:KeyOffLong(void)
【功能】:判断按键长击
【参数】:无
***************************/
void KeyOffLong(void)
{
    if(0==--KeyDat.KeyDog)//延时 是上次延时的叠加
          {
            if(KeyDat.KeyTemp==HC166_read())//校验数据(判断组合键用)
            {
                    KeyDat.KeyData|=DubClick;//DubClick|HaveKey;//长击标记
              KeyDat.KeyDog=timer20ms;
            }
            else     
      {
        KeyDat.KeyData|=HaveKey;//定义短击标记
            KeyDat.KeyPower=0;                //按键确认返回重新扫描
      }
          }
}
/***************************
【函数】:void(*SubKey[])()
【功能】:函数指针定义
【参数】:无
***************************/
void(*SubKey[4])()=
{
  GetKey,Key_Dog,KeyOffShort,KeyOffLong       
};

/***************************
【函数】:void KeyBoard(void)
【功能】:主循环或者定时中断调用
【参数】:无
***************************/
void KeyBoard(void)//扫描键盘
{
  (*SubKey[KeyDat.KeyPower])();       
}

/***************************
【函数】:unsigned char JB_KeyData(void)()
【功能】:用户功能函数调用
【参数】:无
***************************/
unsigned char JB_KeyData(void)
{
  unsigned char i=0;
  if(KeyDat.KeyData>DubClick)//DubClick=0x40
  {
    i=KeyDat.KeyData;
    KeyDat.KeyData=0;       
  }
  return i;
}

出0入0汤圆

发表于 2010-5-5 19:02:40 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-5-5 23:59:59 | 显示全部楼层
回复【82楼】ldj7501
----------------------------------------------------------------------
能否再辛苦一下, 增加一个 “长按,双击”的示范代码?
-----------------------------------------------------------------------

其实实现起来很简单,代码量也很少,而且不占太多资源.....
我就根据你所提要求写一下,代码未做优化,限于篇幅,只写了3个键,相信你会增加到N个键及增加组合键。
事件函数没写,那些就是你要实现的功能了,不过你不能省,否则会编译错误...


#define BUTTONmax 8
#define dfStructLEN sizeof(BUTTON)
#define AllButtonOPEN 0xFF
unsigned char InputTimes,InputData=AllButtonOPEN,InputNew;
unsigned char LDNTimer=0;                //长按定时;
unsigned char IfDbClk=0;                 //双击标志;
unsigned char KeyUpTimer=0;              //键抬起记时;
unsigned char DbClkKeyBuf=0xff;

typedef struct
{
    unsigned char Name;
    void (*Func_CLOSE)(void);            //键按下事件,
    void (*Func_OPEN)(void);             //键弹起事件,
    void (*Func_DBCLK)(void);            //双击事件,
    void (*func_LDN)(void);              //长按事件,
} BUTTON;
const BUTTON FunTab[BUTTONmax]={
    ~0x01,PA0_CLOSE,PA0_OPEN,PA0_DBCLK,PA0_LDN,
    ~0x02,PA1_CLOSE,PA1_OPEN,PA1_DBCLK,PA1_LDN,  
    ~0x04,PA2_CLOSE,PA2_OPEN,PA2_DBCLK,PA2_LDN  
    //只处理3个键,其它的自己发挥吧......
    //可扩展组合键.
};
const BUTTON *pButton=FunTab;

//将键值直接定位到按键函数入口处;
unsigned char chKeyP(unsigned char InpuData)
{
    unsigned char i;
    for(i=0;i<8;i++)            
    {                           //平时在键扫函数内直接返回0,1,2~XXX包括组合键功能码,那样可以直接省去些处转换....
      if(InpuData&(1<<i))
      {
         return i;
      }
    }
    return 0;
}


void ScanInput(void)
{
    if (InputData == PIND)
    {
      if (InputNew)
      {
          InputTimes++;
          if (InputTimes == 8)                            //判键的防抖动
          {   //确认一次按键
              InputTimes = 0;
              InputNew = 0;
              if (InputData == AllButtonOPEN)             //处理OnKeyup事件
              {
                  pButton->Func_OPEN();                   //键盘松开事件;
                  IfDbClk=1;                              //等待双击事件标志;
              }
              else      //处理 OnKeydown事件;
              {        
                  //先检查双击事件,处理双击事件;
                    if((IfDbClk)&&(KeyUpTimer>10)&&(KeyUpTimer<50))  //卡双击的生命周期,记数要根据实际情况确定;
                    {
                        if(InputData==DbClkKeyBuf)      //真正双击;
                        {
                            pButton->Func_DBCLK();
                            DbClkKeyBuf=0xff;
                            IfDbClk=0;                        //双击已触发;
                        }
                    }
                    else   //处理键按下事件;
                    {
                        pButton=FunTab+(dfStructLEN*(chKeyP(InputData)));
                        pButton->Func_CLOSE();
                        DbClkKeyBuf=InputData;
                    }
                                       
                }
            }
         
        }
        else        //处理长按键事件;
        {
            LDNTimer++;
            if(LDNTimer>200)                            //长按事件  --具体值要根据键扫调用频率确定
            {
                pButton->func_LDN();
            }
        }
    }
    else
    {
        InputTimes = 0;
        InputData = PIND;
        InputNew = 1;
        LDNTimer=0;
        if(KeyUpTimer<255)
        {
                KeyUpTimer++;
        }
    }
}

出0入0汤圆

发表于 2010-5-6 00:08:07 | 显示全部楼层
以上代码可以再做一下优化,将变量替换成BOOL型及记数器合并,占资源更少及运行速度会更快。
记数器的值要根据程序实际调用键扫的频度来调整,当然,也可以用定时器记时,增加程序的可移植性。

出0入0汤圆

发表于 2010-5-6 00:40:39 | 显示全部楼层
嗯。。。。按键。。。。。。。。。

出0入0汤圆

发表于 2010-5-6 01:01:39 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-5-6 07:53:33 | 显示全部楼层
回复【88楼】flywater 落叶
---------------------------------------------------------------------

辛苦了,感谢!

出0入0汤圆

发表于 2010-5-6 08:37:02 | 显示全部楼层
MARK一下,过段时间空了再研究

出0入0汤圆

发表于 2010-5-6 08:46:43 | 显示全部楼层
ding

出0入0汤圆

 楼主| 发表于 2010-5-6 08:56:23 | 显示全部楼层
这么老的东西都翻出来了,这些东西只能在简单场合,不用系统的用户可看看。

出0入0汤圆

发表于 2010-5-6 10:03:33 | 显示全部楼层
回复【95楼】stud1 江南孤舟
这么老的东西都翻出来了,这些东西只能在简单场合,不用系统的用户可看看。
-----------------------------------------------------------------------

是呀,大家还在学习前辈N年前的东西...现在很少见您在坛子里出没,换马夹了?

按键事件这些工作操作系统现在都代劳了,如果不是开发操作系统,这种方法不并太适合单片机,因为单片机很少用得上双击、键弹起事件,更复杂的如三击等就更别说了,长按倒还实用些。
不过即使是只用其中的键按下,长按键,也是比传统的按键程序要省代码的。

出0入0汤圆

发表于 2010-5-6 10:25:27 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-5-6 13:10:09 | 显示全部楼层
手机上网,标记,稍后再来详看

出0入0汤圆

发表于 2010-5-6 13:36:43 | 显示全部楼层
帮你顶
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 03:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表