假设我要显示四个不同的界面状态,分别给变量DisplayMode赋相应的值表示:
DisplayMode=0;
DisplayMode=1;
DisplayMode=2;
DisplayMode=3;
同一个按键(Key1),当 短按 的时候进入(DisplayMode=1)界面,
当 长按 的时候进入(DisplayMode=3)界面;
但是如果已经进入了(DisplayMode=1或者DisplayMode=2)界面,则长按按键(Key1)也不能进入(DisplayMode=3)界面;
如果进入(DisplayMode=1)界面则按下确认键(Key4)时,切换到(DisplayMode=2)界面;再次按下确认键(Key4)时,切换到(DisplayMode=0)界面;
我参照的是网友的状态机程序,但是感觉总是不对劲,因为每次都是得进入短按才能进入长按。所以实现上面的要求似乎很不和逻辑,想请教一下,给个思路如何处理上面的按键功能,谢谢!
#include<reg51.h>
unsigned int KeyValue;//键盘值全局变量
unsigned int DisplayMode=0;
bit flag=1;
//根据按键接口定义的按键键值(P1口接了5个按键,目前只用到Key1和key4)
#define Key1 0X17 //0001 0111
#define Key2 0X1E //0001 1110
#define Key3 0X1D //0001 1101
#define Key4 0X1B //0001 1011
#define Key5 0X0F //0000 1111
#define Key6 0x1C //0001 1100
#define KeyNull 0x1F //0001 1111
//按键状态
#define KEY_INIT 0 //初始状态
#define KEY_WOBBLE 1 //消抖状态
#define KEY_PRESS 2 //按下
#define KEY_LONG 3 //长按
#define KEY_CONTINUE 4 //连发
#define KEY_RELEASE 5 //释放
//定义长按键的计数,以及连发间隔的计数
#define KEY_LONG_COUNT 350
#define KEY_CONTINUE_COUNT 10
//定义按键返回值状态(按下,长按,连发,释放)
#define KEY_DOWN_PRESS 0X80 //按下
#define KEY_LONG_PRESS 0X40 //长按
#define KEY_CONTINUE_PRESS 0X20 //连发
#define KEY_UP 0X10 //释放
//读键盘值
void GetKey(unsigned int *pKeyValue)
{
static unsigned int KeyState = KEY_INIT;
static unsigned int KeyTimeCount=0;
static unsigned int LastKey=KeyNull;//保存按键释放时候的键值
unsigned int KeyTemp=KeyNull;
KeyTemp=P1;//读取P1口的状态
switch(KeyState)
{
case KEY_INIT:
{
if(KeyNull != (KeyTemp))
{
KeyState=KEY_WOBBLE;
}
}
break;
case KEY_WOBBLE://消抖
{
KeyState=KEY_PRESS;
}
break;
case KEY_PRESS://按下
{
if(KeyNull != (KeyTemp))//确实有按键按下
{
//保存键值
LastKey=KeyTemp; //
KeyTemp |= KEY_DOWN_PRESS;//按键按下
KeyState=KEY_LONG;
}
else
{
KeyState=KEY_INIT;
}
}
break;
case KEY_LONG://长按
{
if(KeyNull != (KeyTemp))
{
if(++KeyTimeCount>KEY_LONG_COUNT)
{
KeyTimeCount=0;
//长按键事件发生
LastKey=KeyTemp;//
KeyTemp |= KEY_LONG_PRESS;
KeyState=KEY_CONTINUE;
}
}
else
{
KeyState=KEY_RELEASE;
}
}
break;
case KEY_CONTINUE://连发
{
if(KeyNull != (KeyTemp))
{
if(++KeyTimeCount>KEY_CONTINUE_COUNT)
{
KeyTimeCount=0;
LastKey=KeyTemp;//
KeyTemp |= KEY_CONTINUE_PRESS;
}
}
else
{
KeyState=KEY_RELEASE;
}
}
break;
case KEY_RELEASE://释放
{
LastKey|=KEY_UP;
KeyTemp=LastKey;
KeyState=KEY_INIT;
}
break;
default:
break;
}
*pKeyValue=KeyTemp;//返回键值
}
//键盘值处理
void Key_Process(void)
{
switch(KeyValue)
{
case Key1|KEY_DOWN_PRESS: //短按设置键
DisplayMode=1;
break;
case Key1|KEY_LONG_PRESS: //长按设置键
if(flag)
{
DisplayMode=3;
}
break;
case Key4|KEY_DOWN_PRESS://确认键
DisplayMode++;
if(DisplayMode==3){DisplayMode=0;}
break;
default:
break;
}
if(DisplayMode==1||DisplayMode==2||DisplayMode==3)
{
flag=0;
}
else
{
flag=1;
}
}
void main(void)
{
while(1)
{
GetKey(&KeyValue);
Key_Process();
}
} |