优化一个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;
}
} |