最近有位兄台写了篇 单片机C语言下LCD多级菜单的一种实现方法
大致如下
typedef struct
{
uchar KeyStateIndex ; / / 当前状态索引号
uchar KeyDnState ; / / 按下“向下”键时转向的状态索引号
uchar KeyUpState ; / / 按下“向上”键时转向的状态索引号
uchar KeyCrState ; / / 按下“回车”键时转向的状态索引号
uchar KeyBackState ; / / 按下“退回”键时转向的状态索引号
void (*CurrentOperate)( ) ; / / 当前状态应该执行的功能操作
} KbdTabSt ruct ;
# define SIZE - OF KEYBD - MENU 55 / / 菜单总长度
KbdTabSt ruct code KeyTab[ SIZE - OF - KEYBD - MENU ] =
{
{0 ,0 ,0 ,1 ,0 , MainJob1 } ,
{1 ,7 ,2 ,8 ,0 , Dsp Point} , / / 第一层
{2 ,1 ,3 ,8 ,0 , DspCurve}, / / 第一层
{3 ,2 ,4 ,36 ,0 ,Dsp Kout} , / / 第一层
{4 ,3 ,5 ,50 ,0 , DisCloseDown } , / / 第一层
{5 ,4 ,6 ,8 ,0 , ModifyPoint} , / / 第一层
{6 ,5 ,7 ,52 ,0 , SetCloseDown } , / / 第一层
{7 ,6 ,1 ,0 ,0 , Cancel} , / / 第一层
…
…
{52 ,53 ,53 ,0 ,1 , OkSetCloseDown1} ,
{53 ,52 ,52 ,0 ,1 , OkSetCloseDown2} ,
{54 ,0 ,0 ,0 ,0 , Disable} ,
…
…
} ;
void Get Keylnput (void)
{
switch ( status &0xf0)
{
case 0xe0 :/ / 回车键,找出新的菜单状态编号
…
KeyFuncIndex = KeyTab[ KeyFuncIndex ] . KeyCrState ;
…
break ;
case 0xb0 :/ / 向下键,找出新的菜单状态编号
…
KeyFuncIndex = KeyTab [ KeyFuncIndex ] . KeyDn2State ;
…
break ;
case 0xd0 :/ / 向上键,找出新的菜单状态编号
…
KeyFuncIndex = KeyTab [ KeyFuncIndex ] . KeyUp2State ;
…
break ;
case 0x70 :/ / 回退键,找出新的菜单状态编号
…
KeyFuncIndex = KeyTab [ KeyFuncIndex ] . KeyBack2State ;
…
break ;
case 0 ;
return ; / / 错误的处理
break ;
}
KeyFuncPt r = KeyTab[ KeyFuncIndex ] . CurrentOperate ;
( * KeyFuncPt r) () ; / / 执行当前按键的操作
}
但是如果采用触摸屏,并且有多个界面需要切换,那么这种结构就大打折扣。
我要设计的界面是基于这个结构体的:
typedef struct _window_d{
void (*draw)();//每个界面的画界面函数
TKEY (*key_map)(unsigned int x, unsigned int y);//每个界面的所有按键(触摸按键)
void (*key_process)(TKEY_EVENT *event);//每个界面的按键处理函数
}TBasicWindow;
下面是按键识别:
#define UP 0 //按键弹起
#define DOWN 1 //按键按下
typedef enum _key_enum_{
KEY_NULL,
MAIN_REVIEW,//第一个界面三个按键
MAIN_PRINT,
MAIN_SAVE,
PATIENT_OK,//第二个界面三个按键
PATIENT_BACK,
PATIENT_NAME_ZONE,
..........
}TKEY;
typedef struct _key_{
TKEY key;
unsigned int TouchStatus;
}TKEY_EVENT;
void GetKey(TKEY_EVENT *event)
{
unsigned int Y = 0;
unsigned int X = 0;
unsigned short c[3]={0};
unsigned int TouchStatus = DOWN;
get_coord(c);
if(c[0] && !send)
{
X = c[1];
Y = c[2];
TouchStatus = DOWN;
}
if(!c[0])
{
X = c[1];
Y = c[2];
TouchStatus = UP;
}
event->key = CurrentWin->key_map(X, Y);
event->TouchStatus = TouchStatus;
}
写完上面的框架就是每个界面的函数了,我拿一个界面来说,其它都是这个框架:
TBasicWindow MainWin = {
draw: MainDraw,
key_map: MainKeyMap,
key_process: MainKeyProcess,
};
void MainDraw(){
...
}
TKEY MainKeyMap(unsigned int x, unsigned int y)
{
if((x > 95*0&& x <= 95*0) && (y > 685 && y < 790)) return MAIN_REVIEW;
if((x > 95*1&& x <= 95*1) && (y > 685 && y < 790)) return MAIN_PRINT;
if((x > 95*2&& x <= 95*2) && (y > 685 && y < 790)) return MAIN_SAVE;
}
void MainKeyProcess(TKEY_EVENT *event)
{
static TKEY PressKey = KEY_NULL;//记录第一次按下的按键
switch(event->key){
case MAIN_REVIEW:
if(event->TouchStatus){//按键按下
PressKey = MAIN_REVIEW;//记录第一次按下触摸屏的按键
MainKeyDisplay(PressKey, DOWN);//按键按下
}
else{//按键弹起
MainKeyDisplay(PressKey, UP);//弹起先前一次按下的按键,不一定是MAIN_PATIENT
if(PressKey != MAIN_REVIEW) break;//两次按键不一致则不执行
//begin (按下和弹起都是PATIENT,则执行PATIENT的按键处理)
CurrentWin = &ManagementWin;
CurrentWin->draw();
//end
}
break;
...
}
其它的界面都是这样写的,然后主函数只要这样就行了:
TBasicWindow *CurrentWin = &MainWin;
void main(void)
{
TKEY_EVENT event;
while(1){
GetKey(&event);
CurrentWin->key_process(&event);
}
}
最后贴两张界面照片