vincent0319 发表于 2012-2-23 11:21:41

一个按键思路,大侠们给点建议。

优化一个4*4的按键程序,要返回长按键和短按键,大体思路如下:
1、功能函数key_scan 放while(1)里跑,不让系统有任何等待
2、通过状态机的方式实现
3、判断三次状态,有按键,消抖确定有按键,短按键或者长按键

看了很多种按键代码,消抖基本都用等待方式实现,效率不高,所以写了个这样的代码,全当练习。具体思路可以体现,但#define的不全。望高手指点二三。


type enum{
        KEY_SCAN_FIRST;
        KEY_SCAN_SECOND;
        KEY_SCAN_THIRD;
}KEY_SCAN_STATE;

typedef unsigned long long TICK_TYPE;

TICK_TYPE systick=0;
void Systick(void) //系统定时器中断 ,1ms 间隔
{
        systick++;
}

TICK_TYPE GET_currentTimetick() //获得当前TICK
{
        return systick;
}

struct KEY_BODY{
        unsigned char keynum;//哪个按键
        unsigned char keytype;//按键状态
        KEY_SCAN_STATE scan_status;//扫描状态
        TICK_TYPE scan_starttime; //扫描开始tick
        int keyshake_delay;//消抖tick
}key;



//KEYtype defines
#define KEY_DOWN_L 1
#define KEY_DOWN_S 2
#define KEY_UP   3








void key_init(struct KEY_BODY *key)
{
        key->keynum=key->keytype=0;
        key->scan_status = KEY_SCAN_FIRST;
        key->scan_starttime=0;
        key->keyshake_delay=25;//按键消抖时间
       
}
int key_on(void)
{
        ROWPORT_IN;//行,4 IO 入,低电平:下拉
        ROW_OUTPUT_LOW;
        LINEPORT_OUT; //列:4 IO 出,高电平
        LINE_OUTPUT_HING;
        if(ROW_PIN1 != ROW_LOW_MASK) //行 4IO 不全为低 有按键发生
                return KEY_ACTION;
        else
                return NO_KEY_ACTION;       
}

void key_scan (struct KEY_BODY *key)
{
                unsigned char i;
                unsigned char keymask=0;
                switch(key->scan_status)
                {
                        case KEY_SCAN_FIRST:
                                if(key_on()==KEY_ACTION) //有按键,记录时间TICK,状态变换
                                {
                                        key->scan_status = KEY_SCAN_SECOND;
                                        key->scan_starttime=GET_currentTimetick();
                                }
                                break;
                               
                                case KEY_SCAN_SECOND:
                                        if(key_on()==KEY_ACTION) //继续有按键
                                        {
                                                if(GET_currentTimetick()- key->scan_starttime > keyshake_delay) //消抖间隔25ms
                                                {
                                                        for(i=0;i<4;i++) //判按键 i是列
                                                        {
                                                                keymask|=(1<<i); //0000 0001 ,0000 0010,0000 0100,......
                                                                LINE_PIN=keymask;
                                                                switch(ROW_PIN) //判断行 IO 电平
                                                                {
                                                                        case 0x01: //第一行
                                                                        key->keynum = i+1; //第一行四个按键,键值:1,2,3,4
                                                                        break;
                                                                        case 0x02://第二行
                                                                        key->keynum = i+5; //第二行四个按键,键值:5,6,7,8
                                                                        break;
                                                                        case 0x04://第三行
                                                                        key->keynum = i+9;//第三行四个按键,键值:9,10,11,12
                                                                        break;
                                                                        case 0x08://第四行
                                                                        key->keynum = i+13;//第死行四个按键,键值:13,14,15,16
                                                                        break;
                                                                }                       
                                                        }
                                                        key->scan_status = KEY_SCAN_THIRD;
                                                }
                                                else return;                                       
                                        }
                                        else
                                                key->scan_status = KEY_SCAN_FIRST;
                                break;
                               
                                case KEY_SCAN_THIRD:
                                        key->scan_status = KEY_SCAN_FIRST;
                                        key->scan_starttime=GET_currentTimetick(); //获得当前tick
                                        do{ //等待按键释放
                                                if(GET_currentTimetick()- key->scan_starttime > 2000) //按键持续2s,跳出,长按键
                                                {
                                                        key->keytype=KEY_DOWNL;
                                                        return;
                                                }               
                                        }while(key_on()==KEY_ACTION)       
                                       
                                        key->keytype=KEY_DOWN; //释放,短按键
                                                                       
                                break;
                               
                                default:
                                break;
                }
       

}
页: [1]
查看完整版本: 一个按键思路,大侠们给点建议。