搜索
bottom↓
回复: 63

状态机按键程序原来判定1个键,如何改成判定8个键呢?

[复制链接]

出0入0汤圆

发表于 2008-3-2 19:54:08 | 显示全部楼层 |阅读模式
马老师书中第283页的例题。原来判定PD7键是否按下,我现在在PD0-PD7上接了8个按键,请教如何修改程序使他能判断8个键中是哪个键按下了呢?谢谢。

define key_input        PIND.7                        // 按键输入口
#define key_state_0        0
#define key_state_1        1
#define key_state_2        2

unsigned char read_key(void)
{
        static unsigned char key_state = 0;
        unsigned char key_press, key_return = 0;

        key_press = key_input;                        // 读按键I/O电平
        switch (key_state)
        {
                case key_state_0:                        // 按键初始态
                        if (!key_press) key_state = key_state_1;        // 键被按下,状态转换到键确认态
                        break;
                case key_state_1:                        // 按键确认态
                        if (!key_press)
                        {
                                key_return = 1;        // 按键仍按下,按键确认输出为"1" (1)
                                key_state = key_state_2;        // 状态转换到键释放态
                        }
                        else
                                key_state = key_state_0;        // 按键已抬起,转换到按键初始态
                        break;
                case key_state_2:
                        if (key_press) key_state = key_state_0;        //按键已释放,转换到按键初始态
                        break;
                }       
            return key_return;
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2008-3-3 23:21:02 | 显示全部楼层
请参考P342页中的读键程序,这个是读2个按键的.

出0入0汤圆

发表于 2008-3-15 14:05:25 | 显示全部楼层
这是我写的四个按键的程序如下:

#define key_input        PINC                        // 按键输入口
#define key_mask        0b11110000              // 按键输入屏蔽码
#define key_no                0
#define key_k1                1
#define key_k2                2
#define key_k3          3
#define key_k4          4
#define key_state_0        0
#define key_state_1        1
#define key_state_2        2

unsigned char read_key(void)              //按键扫描程序
{
        static unsigned char key_state = 0,key_press;
        unsigned char key_return = key_no;

        key_press = key_input & key_mask;        // 读按键I/O电平
        switch (key_state)
        {
                case key_state_0:                                // 按键初始态
                        if (key_press != key_mask) key_state = key_state_1;       
                        break;                                            // 键被按下,状态转换到键确认态
                case key_state_1:                                // 按键确认态
                        if (key_press == (key_input & key_mask))
                        {
                                if (key_press == 0b01110000) key_return = key_k1;
                                else if (key_press == 0b10110000) key_return = key_k2;
                                     else if (key_press == 0b11010000) key_return = key_k3;
                                           else if (key_press == 0b11100000) key_return = key_k4;
                                key_state = key_state_2;        // 状态转换到键释放态
                        }
                        else
                                key_state = key_state_0;        // 按键已抬起,转换到按键初始态
                        break;
                case key_state_2:
                        if (key_press == key_mask) key_state = key_state_0;
                        break;                                                //按键已释放,转换到按键初始态
        }
           return key_return;
}


按键用起来没问题,可是我有一点不明白,请马老师解答,在程序中定义了key_press为局部静态变量,我觉得没必要,因为key_press中跟本就不会保留住上一次的值并且用于10ms后的本次程序执行中,因为每隔10ms都会执行 key_press = key_input & key_mask;这样以来key_press == (key_input & key_mask)始终为真,不知这样说对不?请马老师指教

出0入0汤圆

发表于 2008-3-15 15:38:53 | 显示全部楼层
楼上,此程序已经做了勘误修改,见上面的"《AVR单片机嵌入式系统原理与应用实践》一书勘误与修正"一帖.

出0入0汤圆

发表于 2008-3-15 20:25:57 | 显示全部楼层
我看了,这样看起来就容易理解了,谢谢马老师,原先老看不懂,呵呵,不过原先好像也能实现吧

出0入0汤圆

发表于 2008-3-16 07:03:04 | 显示全部楼层
哥哥们,这样的程序还是自己写写吧.纯逻辑的问题.
按状态机的思想,用IF ELSE语句写.感觉比马老师的程序量小.
抄他们的程序你记不住,回头维护的时候也麻烦.自己写的体会比较深.

出0入0汤圆

发表于 2008-6-6 00:48:28 | 显示全部楼层
实践出真不真知,我们要站在巨人肩膀上,而不是一定踩着他们脚印走

出0入0汤圆

发表于 2008-6-6 00:49:34 | 显示全部楼层
同意五楼的,要学会钓鱼,而不是等人送鱼

出0入0汤圆

发表于 2008-6-6 07:48:17 | 显示全部楼层
这是我写的状态机按键扫描,请指教。
/* --------------- filename: key.h -------------------*/
#ifndef _KEY_LXF_H_
#define        _KEY_LXF_H_

#include <avr/io.h>

/* *******************************************************************************
* keycode格式:   D7 D6 D5 D4 D3 D2 D1 D0
*                M1 M0 K5 K4 K3 K2 K1 K0
*  M1:M0 表示按键类型, 01 普通  10 长按键  11 连_发按键
*  K5:K0 按键编号 总共可以支持2^6 - 1 = 63个按键
* *******************************************************************************/
#define KTYPE_NO        0x00
#define KTYPE_NORMAL    (1<<6)
#define KTYPE_LONG      (2<<6)
#define KTYPE_LIANFA    (3<<6)

#define KTYPE_MASK        0xC0
#define KCODE_MASK        0x3f

/* 改为你所接的IO口,使用的是高4位,如果有不同的接法,需要修改key_read函数 */
#define KEY_PIN     PINC
#define        KEY_PORT    PORTC
#define        KEY_DDR     DDRC

extern void key_init(void);
extern unsigned char key_scan(void);
/* 获取按键类型 */
#define GET_KTYPE(k)        ((k)&KTYPE_MASK)
/* 获取按键值 */
#define GET_KCODE(k)        ((k)&KCODE_MASK)

#endif

/* --------------- filename: key.h -------------------*/

/* --------------- filename: key.c -------------------*/
#include "key.h"

enum kscan_state{
    KSCAN_START = 0,        /* 无键按下, 键盘扫描初始状态 */
    KSCAN_PRESS,            /* 键按下,判断抖动, >0.1s */
    KSCAN_LONGPRESS,        /* 非抖动,判断是否长按键,>0.8s */
    KSCAN_PDLF,             /* 判断连_发,得到一次长按键后1s开始连_发 */
    KSCAN_LIANFA,           /* 连_发,每0.2s产生一次连_发按键 */
};

struct kstate_fsm{
    enum kscan_state kpress_next;       /* 键按下,下一个状态 */
    enum kscan_state nokey_next;        /* 键抬起,下一个状态 */
    unsigned char kpress_time;          /* 键按下需持续的时间, 10ms的倍数 */
    unsigned char kpress_type;          /* 键按下满足条件,输出按键类型 */       
};

/* 保证状态编号值与在数组中的位置相同  */
struct kstate_fsm kstate_fsm_table[] = {
    /* kpress_next,     nokey_next,     time,   type   */
    { KSCAN_PRESS,      KSCAN_START,    0,      KTYPE_NO},      /* KSCAN_START: 0 */
    { KSCAN_LONGPRESS,  KSCAN_START,    5,      KTYPE_NORMAL},  /* KSCAN_PRESS: 1 */
    { KSCAN_PDLF,       KSCAN_START,    80,     KTYPE_LONG},    /* KSCAN_LONGPRESS: 2 */
    { KSCAN_LIANFA,     KSCAN_START,    100,    KTYPE_NO},      /* KSCAN_PDLF: 3 */
    { KSCAN_LIANFA,     KSCAN_START,    20,     KTYPE_LIANFA}   /* KSCAN_LIANFA: 4*/
};

void key_init(void)
{
    KEY_PORT |= 0xf0;       
    KEY_DDR  |= 0x0f;
}

/*
    功能描述:读取按键状态
    入口参数:无
    出口参数:按键编号
*/
unsigned char key_read(void)
{
    unsigned char kmask = ((KEY_PIN & 0xf0) ^ 0xf0) >> 4;   /* 高四位取反,并移到低4位 */
    unsigned char kcode = 0;

    while( kmask ){
        kmask >>= 1;
        kcode++;
    }
        return kcode;
}

/*
    使用说明:为了得到该函数提供的功能,必须每10ms调用1次
    功能描述:按键扫描,根据状态表的设置,返回当前按键状态
    入口参数:无
    出口参数:按键编号和按键种类,格式如下
        D7 D6 D5 D4 D3 D2 D1 D0
        M1 M0 K5 K4 K3 K2 K1 K0
        M1:M0 表示按键类型, 01 普通  10 长按键  11 连_发按键
        K5:K0 按键编号 1~63, 总共可以支持2^6 - 1 = 63个按键   
*/
unsigned char key_scan(void)
{
    static enum kscan_state keystate = KSCAN_START;
    static unsigned char oldkey;
    static unsigned char ktime_counter = 0;
   
    unsigned char keyreturn = 0;
    unsigned char currkey = key_read();             /* (PINA & 0x0f) ^ 0x0f; */

    if( (currkey != 0) && (currkey == oldkey) )
    {
        if(++ktime_counter >= kstate_fsm_table[keystate].kpress_time )
        {
            ktime_counter = 0;
            keyreturn = kstate_fsm_table[keystate].kpress_type | oldkey;
            keystate = kstate_fsm_table[keystate].kpress_next;
        }
    }       
    else
    {
        keystate = kstate_fsm_table[keystate].nokey_next;
        oldkey = currkey;
    }
    return keyreturn;
}
/* --------------- filename: key.c -------------------*/

出0入0汤圆

 楼主| 发表于 2008-6-6 22:35:36 | 显示全部楼层
这下有学习实例了,谢谢。

出0入0汤圆

发表于 2008-6-6 23:07:59 | 显示全部楼层
谢谢【8楼】 ifree64 的代码

这个结构不错,学习了。
和菜单差不多的结构。

出0入0汤圆

发表于 2008-6-7 15:28:15 | 显示全部楼层
在我的教材中谈到过,看似简单的按键,实际上并不简单.因为实际上在每一个系统中,按键的功能和处理是不同的,比如是否使用组合键(需要辨别双键或多键),是否使用连_发键(需要判断按键按下时间的长短)等.按键功能越复杂,处理程序也随之复杂.

根据我的经验,建议如下:

1.首先要根据系统总体要实现的功能,确定按键的功能.能够使用简单的方式,尽量使用简单的方式,如不使用组合键等.当然,这样可能需要更多的按键,硬件上要多花费些,但是对于实际操作人员的使用确简单多了.实际使用者一般不喜欢使用所谓"多功能"按键,因为他们往往记不住过多的组合方式和功能,操作上也不容易掌握,如"先"按哪个,"再"按哪个等(实际操作中,很难做到"同时"按下的).我通常不主张使用组合键,用的比较多的是某几个键的连_发(参考P287).

2.按键处理部分的程序结构最好是将读键和判别键值做处理分成两个部分,这样既方便调试,程序结构好,同时也便于底层硬件变化后的移植.

3.尽管AVR等新型单片机提供了片内比较充足的程序和数据储存器,但还是有限的,尽量要根据实际需要编写按键处理程序,而不是放上一个全功能的处理程序,这样会浪费资源.6楼的意见是对的,掌握和使用状态机的思想非常重要,不仅对处理按键,在其它方面也是非常实用的方法.在我的书中,是借按键的例子引出状态机的思想和方法,在后面的例子中实际有很多地方都采用了该方法(比如USART的中断接收).

下面根据LZ的出题,给出我的答卷(cvavr).当然,LZ的题目并没有详细说明8个按键具体的操作要求,所以我代码实现的是最简单的判定.

假定:无连_发,无组合键,仅是单键的简单操作,按下去(不管多长时间)算一次按键,其它按键方式做无效处理.

#define key_input  PINA
#defien key_1      0b11111110
#defien key_2      0b11111101
#defien key_3      0b11111011
#defien key_4      0b11110111
#defien key_5      0b11101111
#defien key_6      0b11011111
#defien key_7      0b10111111
#defien key_8      0b01111111
#defien key_no     0b11111111
#define key_state_0        0
#define key_state_1        1
#define key_state_2        2

unsigned char read_key(void)                        //读键状态机,每10-20ms执行一次
{  
    static unsigned char key_state = 0,key_old;  
    unsigned char key_press,key_return = key_no;  

    key_press = key_input;        // 读按键I/O电平  
    switch (key_state)  
    {  
        case key_state_0:                    // 按键初始态  
            if (key_press != key_no)  key_state = key_state_1;    // 键被按下,状态转换到键确认态   
            break;   
        case key_state_1:                    // 按键确认态  
            if (key_press == key_old)        // 与原电平比较(消抖处理)
            {  
                key_return = key_press;  
                key_state = key_state_2;        // 状态转换到判键释放态  
            }  
            else  
                key_state = key_state_0;        // 按键已抬起,转换到按键初始态(消抖)  
            break;  
        case key_state_2:  
            if (key_press != key_old)
                key_state = key_state_0;        //按键已释放(或转按其它键),转换到按键初始态  
            break;
    }
    key_old = key_press;  
    return key_return;  
}

main()
{
     unsigned char key_value;
     ......
     key_value = read_key();                   //注意控制10-20ms执行一次.
     if (key_value != key_no)                  //判别键值并做相应的处理
     {
          switch (key_value)
          {
               case key_1:
                   //do samething
                    break;
               case key_2:
                   // do ....
                   break;

               .........
               case key_8:
                   // do .....
                   break;
           }
      }
    ............
}

出0入296汤圆

发表于 2008-6-7 15:54:27 | 显示全部楼层
<>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 UINT8 Get_Key_Code(void);
extern void Clear_Key_Buffer(void);

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

extern UINT16 g_wKeyPressTimeCounter;
extern UINT16 g_wKeyPressDelayCounter;

#endif



<>RD_UseKey.c

/***********************************************************
*   函数库说明:按键处理函数库                             *
*   版本:      v2.00                                      *
*   作者:      傻孩子                                     *
*   创建日期:  2005年11月27日                             *
* -------------------------------------------------------- *
*  [支 持 库]                                              *
*   支持库名称:RD_MacroAndConst.h                         *
*   需要版本:  v0.01 &abv                                 *
*   支持库说明:系统常用宏定义库                           *
*                                                          *
*   支持库名称:RD_UseKey.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"
# 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);
UINT8 Get_Key_Code(void);
void Clear_Key_Buffer(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

/********************
*   全局变量声明区  *
********************/
UINT8 g_cReturnKeyNum = KEY_NULL;
UINT8 g_cReturnLongPressKeyNum = KEY_NULL;
UINT16 g_wKeyPressTimeCounter = 0;
UINT16 g_wKeyPressDelayCounter = 0;

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

static UINT8 s_cLongKeyPressNum = KEY_NULL;
static UINT8 s_cKeyNum = KEY_NULL;

/***********************************************************
*   函数说明:  清除键盘缓冲区                             *
*   输入:      无                                         *
*   输出:      无                                         *
*   调用函数:  无                                         *
***********************************************************/
void Clear_Key_Buffer(void)
{
    s_cKeyBUFFCounter = 0;
    s_cKeyBUFFCounter = 0;
    s_cKeyBUFFHeadPoint = 0;
    s_cKeyBUFFTailPoint = 0;
}

/***********************************************************
*   函数说明:按键扫描码处理函数                           *
*   输入:    无                                           *
*   输出:    无                                           *
*   调用函数:_USE_KEY_PRESS_SCAN_FUNC_INTERFACE()         *
* -------------------------------------------------------- *
*   [说    明]                                             *
*            按下一个键以后,1s以内松开返回短按键键值      *
*            1s以上返回长按键键值。键值只保存一个周期      *
***********************************************************/
static void _Key_Scan(void)
{
    static UINT8 OldKeyCode = KEY_NULL;
    static UINT8 IfLongKeyPress = FALSE;
    static UINT16  LongPressAcceleration = 0;
         
    UINT8 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()                               *
* -------------------------------------------------------- *
*   [说    明]                                             *
*             将按键扫描码放到专门的临时缓冲变量中         *
***********************************************************/
UINT8 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入0汤圆

发表于 2008-6-7 18:25:13 | 显示全部楼层
#defien --->#define

出0入0汤圆

发表于 2008-10-21 16:23:21 | 显示全部楼层
D

出0入0汤圆

发表于 2008-10-26 01:01:51 | 显示全部楼层
傻孩子的库

值得研究

本贴被 Avenue 编辑过,最后修改时间:2008-10-26,01:02:22.

出0入0汤圆

发表于 2008-10-26 08:02:55 | 显示全部楼层
楼主位的状态机的意思是不是就是连续两次检测到按键倍按下,则确认此按键为1?然后一旦确认此按键为1,则只要检测到一次按键被放开,立即确认此按键为0?并且一旦确认为1,那么将不再执行&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;key_state_1:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;按键确认态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!key_press)&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key_return&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;按键仍按下,按键确认输出为"1"&nbsp;(1)&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key_state&nbsp;=&nbsp;key_state_2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;状态转换到键释放态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key_state&nbsp;=&nbsp;key_state_0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;按键已抬起,转换到按键初始态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;

此段,那么如果需要连加连减按键效果,怎样实现呢?

还有个问题,就是按键按下时有一个两次的消抖动,那么按键一直按着只被执行一次的程序,在按住不动时有一次断开的抖动的话,是不是又会被执行一次呢?如此消抖动的意义不是打了折扣?

第一次看马老师的程序,请指教。我这里有汇编的书,不过买来也没看,直接上了C。

出0入0汤圆

发表于 2008-10-29 15:47:13 | 显示全部楼层
是我的问题太幼稚了?还是怎么了?我的程序也有这样问题,不过采用比较好的开关再并联一个电容就不明显了,不知道大家是否也有这个问题

出0入0汤圆

发表于 2008-10-29 16:21:17 | 显示全部楼层
请参考我编写的教程,里面有长按键连加的例子。

出0入0汤圆

发表于 2008-12-5 14:43:55 | 显示全部楼层
今天我仔细看了一睛【2楼】&nbsp;mfm123&nbsp;的贴子,以下不明白

unsigned&nbsp;char&nbsp;read_key(void)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//按键扫描程序&nbsp;

{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;unsigned&nbsp;char&nbsp;key_state&nbsp;=&nbsp;0,key_press;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;char&nbsp;key_return&nbsp;=&nbsp;key_no;&nbsp;



----------key_press&nbsp;=&nbsp;key_input&nbsp;&&nbsp;key_mask;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;读按键I/O电平&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(key_state)&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;key_state_0:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;按键初始态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(key_press&nbsp;!=&nbsp;key_mask)&nbsp;key_state&nbsp;=&nbsp;key_state_1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;键被按下,状态转换到键确认态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;key_state_1:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;按键确认态&nbsp;

------------------------if&nbsp;(key_press&nbsp;==&nbsp;(key_input&nbsp;&&nbsp;key_mask))&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(key_press&nbsp;==&nbsp;0b01110000)&nbsp;key_return&nbsp;=&nbsp;key_k1;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(key_press&nbsp;==&nbsp;0b10110000)&nbsp;key_return&nbsp;=&nbsp;key_k2;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(key_press&nbsp;==&nbsp;0b11010000)&nbsp;key_return&nbsp;=&nbsp;key_k3;&nbsp;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(key_press&nbsp;==&nbsp;0b11100000)&nbsp;key_return&nbsp;=&nbsp;key_k4;&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key_state&nbsp;=&nbsp;key_state_2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;状态转换到键释放态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key_state&nbsp;=&nbsp;key_state_0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;按键已抬起,转换到按键初始态&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;

其中我标记有一条线的两句话可能是不对,不理解,好象没有实际意义,就是说先赋值再判相等,意义不大,但是这个程序有可能还可以正常工作的。

出330入0汤圆

发表于 2008-12-23 14:51:32 | 显示全部楼层
收藏【8楼】&nbsp;ifree64&nbsp;和【11楼】&nbsp;machao&nbsp;的思想和代码

出0入0汤圆

发表于 2008-12-23 16:48:52 | 显示全部楼层
蛮好的

出210入8汤圆

发表于 2008-12-23 17:10:19 | 显示全部楼层
留个脚印,好好学习。

出0入0汤圆

发表于 2009-1-8 00:37:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-1-8 08:42:08 | 显示全部楼层
thank&nbsp;you&nbsp;

出0入0汤圆

发表于 2009-3-17 11:49:46 | 显示全部楼层
Gorgon Meducer 傻孩子,你的程序到处都是宏定义,看得头都大了,没有马老师的按键“状态机”程序,看得清析。

出0入0汤圆

发表于 2009-3-17 13:13:28 | 显示全部楼层
Gorgon Meducer 傻孩子,你的程序基本上都没有注释,对于新手来说很难看懂。晕……

出0入0汤圆

发表于 2009-3-17 16:07:18 | 显示全部楼层
留个脚印,学习

出0入0汤圆

发表于 2009-4-6 13:31:38 | 显示全部楼层
都是常州的,上来顶楼主

出0入0汤圆

发表于 2009-4-24 00:18:17 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-5-8 11:53:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-5-25 15:58:56 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-6-8 15:50:32 | 显示全部楼层
好贴子,学习中

出0入0汤圆

发表于 2009-9-23 00:10:44 | 显示全部楼层
留名

出0入0汤圆

发表于 2009-9-23 02:07:30 | 显示全部楼层
Mark

出0入0汤圆

发表于 2009-9-23 19:30:37 | 显示全部楼层

出0入0汤圆

发表于 2009-11-29 10:20:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-11-29 20:59:04 | 显示全部楼层
我用老师一个键的程序,为每个键定义一个状态,然后处理哪个键就在按键程序里用个switch选择。
挖坟了。。

出0入0汤圆

发表于 2009-11-29 22:31:24 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-11-30 00:19:59 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-12-14 13:50:02 | 显示全部楼层
这个值得研究一下

出0入0汤圆

发表于 2010-3-18 10:11:29 | 显示全部楼层
回复【8楼】ifree64
-----------------------------------------------------------------------

弱弱的问一句:kmask >>= 1; 中 >>= 是什么运算符??

出0入0汤圆

发表于 2010-3-25 12:06:30 | 显示全部楼层
帮助很大,谢谢

出0入0汤圆

发表于 2010-3-25 19:33:17 | 显示全部楼层
mark

出0入0汤圆

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

出0入0汤圆

发表于 2010-5-31 10:27:45 | 显示全部楼层
回复【11楼】machao  
-----------------------------------------------------------------------

马老师您好,感谢您提供这么多资料,我在学习状态机的时候,参考了您的这段函数,不过也出现了和一些网友一样的问题,就是判断多键的时候,无法返回函数。而对一个键判断的时候就正常。我使用的是51。。实在没想清楚问题出现在哪。

出0入0汤圆

发表于 2010-6-27 17:18:16 | 显示全部楼层
mark~~~~~~~~~~~~~~~~这个相当牛。

出0入0汤圆

发表于 2010-7-13 15:11:15 | 显示全部楼层
一个集所有按键的专题

出0入0汤圆

发表于 2010-9-11 15:33:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-29 11:43:27 | 显示全部楼层
严重记号!!

出0入0汤圆

发表于 2011-2-23 08:49:27 | 显示全部楼层
8楼写得不错,学习了!

出0入0汤圆

发表于 2011-7-5 16:23:20 | 显示全部楼层
记号

出0入0汤圆

发表于 2011-7-7 20:27:53 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-10-5 20:31:30 | 显示全部楼层
unsigned char read_key(void)  
{  
    static unsigned char key_state = 0,key_old;  
    unsigned char key_press,key_return = key_no;  

    key_press = key_input & key_mask;        // 读按键I/O电平  
    switch (key_state)  
    {  
        case key_state_0:                    // 按键初始态  
            if (key_press != key_mask)  
            {  
                 key_old = key_press;        // 记录原电平                    
                 key_state = key_state_1;    // 键被按下,状态转换到键确认态   
            }               
            break;   
        case key_state_1:                    // 按键确认态  
            if (key_press == key_old)        // 与原电平比较(消抖处理)
            {  
                if (key_press == 0b01000000) key_return = key_k1;  
                else if (key_press == 0b10000000) key_return = key_k2;   
                key_state = key_state_2;        // 状态转换到键释放态  
            }  
            else  
                key_state = key_state_0;        // 按键已抬起,转换到按键初始态  
            break;  
        case key_state_2:  
            if (key_press == key_mask) key_state = key_state_0;  //按键已释放,转换到按键初始态  
            break;
    }  
    return key_return;  
}

出0入0汤圆

发表于 2011-10-12 08:32:04 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-2 21:59:07 | 显示全部楼层
mark!!!

出0入0汤圆

发表于 2011-11-22 20:50:47 | 显示全部楼层
收下!

出0入0汤圆

发表于 2012-2-27 16:51:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-27 16:58:19 | 显示全部楼层

出0入0汤圆

发表于 2012-3-1 15:17:36 | 显示全部楼层
回复【25楼】ba_wang_mao
-----------------------------------------------------------------------

同感

出0入0汤圆

发表于 2012-3-25 18:26:43 | 显示全部楼层
学习了mark

出0入0汤圆

发表于 2012-6-13 21:51:20 | 显示全部楼层
本帖最后由 detail2012 于 2012-6-13 21:54 编辑

小弟愚以为
三楼的代码可以稍加修改

#define key_input        PINC                        // 按键输入口
#define key_mask        0b11110000              // 按键输入屏蔽码
#define key_no                0
#define key_k1                1
#define key_k2                2
#define key_k3          3
#define key_k4          4
#define key_state_0        0
#define key_state_1        1
#define key_state_2        2

unsigned char read_key(void)              //按键扫描程序
{
        static unsigned char key_state = 0;
        unsigned char key_press;
        unsigned char key_return = key_no;

        key_press = key_input & key_mask;        // 读按键I/O电平
        switch (key_state)
        {
                case key_state_0:                                // 按键初始态
                        if (key_press != key_mask) key_state = key_state_1;        
                        break;                                            // 键被按下,状态转换到键确认态
                case key_state_1:                                // 按键确认态
                        if (key_press == key_input&key_mask) {
                                        switch (key_press) {
                                        case "按键状态1":key_return = key_1;break;
                                        case "按键状态2":key_return = key_2;break;
                                        case "按键状态XX":key_return = key_x;break;
                                        default:key_return = key_no;
                                        }
                                        key_state = key_state_2;
                        } else {
                                        key_state = key_state_0;
                        }
                        break;
                case key_state_2:
                        if (key_press == key_mask) key_state = key_state_0;
                        break;                                                //按键已释放,转换到按键初始态
        }
           return key_return;
}

出0入0汤圆

发表于 2012-6-27 14:32:19 | 显示全部楼层
mark               

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-24 19:55

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

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