<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 單片機多級菜單編程實(shí)現

單片機多級菜單編程實(shí)現

作者: 時(shí)間:2016-11-27 來(lái)源:網(wǎng)絡(luò ) 收藏
建立一個(gè)樹(shù)狀的菜單結構,用鏈表實(shí)現

鏈表中包含:

本文引用地址:http://dyxdggzs.com/article/201611/322426.htm

1、指向同級左右菜單和指向父菜單、子菜單的四個(gè)菜單結構體指針;

2、進(jìn)入該菜單時(shí)需要執行的初始化函數指針

3、退出該菜單時(shí)需要執行的結束函數指針

4、該菜單內的按鍵處理函數指針數組的指針操作菜單模塊需要的按鍵操作有:左、右、確

認、退出。

采用這種辦法,可以方便的添加或刪減菜單。并且只需要在其頭文件中修改初始變量就可

以實(shí)現,完全無(wú)須修改C文件中的任何函數。

具體結構定義

我的定義,做個(gè)參考:

#defineMENU_HLP_EN//菜單幫助信息使能

typedef struct

{

void (*pMenuTaskInit)(void);//指向菜單任務(wù)初始化函數的指針

void (*pMenuTaskEnd)(void);//指向菜單任務(wù)結束函數的指針

}MENU_TASK_TYP;

typedef struct MenuTyp

{

INT8U*MenuName;//菜單名稱(chēng)字符串

WORK_MODWorkMod;//工作狀態(tài)編號

MENU_TASK_TYP*pMenuTask;//指向菜單任務(wù)的指針

void (**pTaskKeyDeal)(void);//指向菜單任務(wù)按鍵處理函數數組的指針

#ifdef MENU_HLP_EN

INT8U*MenuHlp;//菜單幫助字符串

#endif

struct MenuTyp*pParent;//指向上層菜單的指針

struct MenuTyp*pChild;//指向子菜單的指針

struct MenuTyp*pRight;//指向右菜單的指針

struct MenuTyp*pLeft;//指向左菜單的指針

}MENU_TYP;

我根據網(wǎng)上的資料做的一個(gè)菜單:

struct KeyTabStruct{

uint8MenuIndex;//當前狀態(tài)索引號

uint8MaxItems;//本級菜單最大條目數

uint8ShowLevel;//菜單顯示內容

uint8PressOk;//按下"回車(chē)"鍵時(shí)轉向的狀態(tài)索引號

uint8PressEsc;//按下"返回"鍵時(shí)轉向的狀態(tài)索引號

uint8PressDown;//按下"向下"鍵時(shí)轉向的狀態(tài)索引號

uint8PressUp;//按下"向上"鍵時(shí)轉向的狀態(tài)索引號

void(*CurrentOperate)();//當前狀態(tài)應該執行的功能操作

};

uint8MenuID;//菜單ID號

uint8MenuNextID;//下級菜單ID號

//CurMenuID=本菜單ID

//MaxMenuItem=同級菜單最大項數

//OkMenuID=子菜單層所對應的菜單ID,ID=999為菜單已經(jīng)到底了

//EscMenuID=父菜單層所對應的菜單ID,ID=999為菜單已經(jīng)到頂了

//DownMenuID=弟菜單層所對應的菜單ID,ID=999為菜單是獨生子

//UpMenuID=兄菜單層所對應的菜單ID,ID=999為菜單是獨生子

//CurFunction=本菜單所對應的菜單函數指針

const struct KeyTabStruct KeyTab[MAX_KEYTABSTRUCT_NUM]={

//CurMenuID,axMenuItem,MenuShowLevel,OkMenuID,EscMenuID,DownMenuID,UpMenuID,CurFunction

{MENU_EDIT,0,0,MENU_DATA_VIEW,MENU_NO,MENU_NO,MENU_NO,*MenuEdit},

{MENU_DATA_VIEW,3,1,MENU_DATA_VIEW_FIRE,MENU_EDIT,MENU_SYS_EDIT,MENU_PRINT_DATA,*MenuEdit},

{MENU_DATA_VIEW_FIRE,5,MENU_NO,MENU_NO,MENU_DATA_VIEW,MENU_DATA_VIEW_TROUBLE, MENU_STEP_FOLLOW, *MenuDataViewIn},

{MENU_DATA_VIEW_TROUBLE, 5,MENU_NO,MENU_NO,MENU_DATA_VIEW,MENU_DATA_VIEW_REPEAT,MENU_DATA_VIEW_FIRE,*MenuDataViewIn},

{MENU_DATA_VIEW_REPEAT,5,MENU_NO,

MENU_NO,MENU_DATA_VIEW,MENU_FACE_CHECK,

MENU_DATA_VIEW_TROUBLE,*MenuDataViewIn},

{MENU_FACE_CHECK,5,MENU_NO,

MENU_NO,MENU_DATA_VIEW,MENU_STEP_FOLLOW,

MENU_DATA_VIEW_REPEAT,*MenuFaceCheck},

{MENU_STEP_FOLLOW,5,MENU_NO,

MENU_NO,MENU_DATA_VIEW,MENU_DATA_VIEW_FIRE,MENU_FACE_CHECK,

*MenuStepFollow},

{MENU_SYS_EDIT,3,

2,MENU_SUM_SET,MENU_EDIT,

MENU_PRINT_DATA,MENU_DATA_VIEW,*MenuEdit},

{MENU_SUM_SET,6,MENU_NO,

MENU_NO,MENU_SYS_EDIT,MENU_EDIT_INSULATE,

MENU_TIME_SET,*MenuSumSet},

{MENU_EDIT_INSULATE,6,MENU_NO,

MENU_NO,MENU_SYS_EDIT,MENU_EDIT_HZ,MENU_SUM_SET,

*MenuEditInsulate},

{MENU_EDIT_HZ,6,MENU_NO,

MENU_NO,MENU_SYS_EDIT,MENU_LD_CONTROL,

MENU_EDIT_INSULATE,*MenuEditHZ},

{MENU_LD_CONTROL,6,

MENU_NO,MENU_NO,MENU_SYS_EDIT,MENU_LD_DELAY,

MENU_EDIT_HZ,*MenuLDControl},

{MENU_LD_DELAY,6,

MENU_NO,MENU_NO,MENU_SYS_EDIT,MENU_TIME_SET,

MENU_LD_CONTROL,*MenuLDDelay},

{MENU_TIME_SET,6,MENU_NO,

MENU_NO,MENU_SYS_EDIT,MENU_SUM_SET,MENU_LD_DELAY,

*MenuTimeSet},

{MENU_PRINT_DATA,3,3,

MENU_PRINT_DATA_FIRE,MENU_EDIT,MENU_DATA_VIEW,

MENU_SYS_EDIT,*MenuEdit},

{MENU_PRINT_DATA_FIRE,4,

MENU_NO,MENU_NO,MENU_PRINT_DATA,

MENU_PRINT_DATA_TROUBLE,MENU_PRINT_SET,*MenuPrintDataIn},

{MENU_PRINT_DATA_TROUBLE,4,MENU_NO,

MENU_NO,MENU_PRINT_DATA,MENU_PRINTER_CHECK,

MENU_PRINT_DATA_FIRE,*MenuPrintDataIn},

{MENU_PRINTER_CHECK,4,MENU_NO,

MENU_NO,MENU_PRINT_DATA,MENU_PRINT_SET,

MENU_PRINT_DATA_TROUBLE,*MenuPrintDataIn},

{MENU_PRINT_SET,4,MENU_NO,

MENU_NO,MENU_PRINT_DATA,MENU_PRINT_DATA_FIRE,

MENU_PRINTER_CHECK,*MenuPrintSet},

};

const struct MenuDispDataMenuEditShow[][MENU_MAX] = {

{{MENU_NO, 0, 0, "選擇:消音→退出"},//主菜單

{MENU_DATA_VIEW, 1, 6, "⒈數據查看"},

{MENU_SYS_EDIT, 2, 6, "⒉系統編程"},

{MENU_PRINT_DATA, 3, 6, "⒊數據打印"}},

{{MENU_NO, 0, 0, "數據查看:消音→退出"},//數據查

{MENU_DATA_VIEW_FIRE, 1, 4, "⒈火警"},

{MENU_DATA_VIEW_TROUBLE, 2, 4, "⒉故障"},

{MENU_DATA_VIEW_REPEAT , 3, 4, "⒊重碼"},

{MENU_FACE_CHECK, 1,12, "⒋面板檢測"},

{MENU_STEP_FOLLOW, 2,12, "⒌單步跟蹤"}},

{{MENU_NO, 0, 0, "系統編程:消音→退出"},//系統編程

{MENU_SUM_SET, 1, 0, "⒈容量設置"},

{MENU_EDIT_INSULATE, 2, 0, "⒉隔離點(diǎn)"},

{MENU_EDIT_HZ, 3, 0, "⒊漢字描述"},

{MENU_LD_CONTROL, 1,12, "⒋聯(lián)動(dòng)控制"},

{MENU_LD_DELAY, 2,12, "⒌模塊延時(shí)"},

{MENU_TIME_SET, 3,12, "⒍時(shí)鐘調整"}},

{{MENU_NO, 0, 0, "數據打印:消音→退出"},//數據打印

{MENU_PRINT_DATA_FIRE, 1, 0, "⒈火警數據"},

{MENU_PRINT_DATA_TROUBLE,2, 0, "⒉故障數據"},

{MENU_PRINTER_CHECK, 3, 0, "⒊打印機自檢"},

{MENU_PRINT_SET, 1,12, "⒋打印設置"}},

};

void WaitKey(void)

{

uint32 time;

time = RTCFlag;

WhichKey = KEY_NONE;

while(!EscFlag){

if(RTCFlag - time >= EDIT_TIME)

EscFlag = TRUE;

if(WhichKey != KEY_NONE){

KeySound(300);//按鍵音

return;

}

}

}

void MenuEdit()

{

uint32 i,j=0;

uint32 oldid;

j = KeyTab[MenuID].ShowLevel;

if(WhichKey == KEY_ESC || WhichKey == KEY_OK){

ClearScreen();

for(i=0;i

ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j]

[i].Column,MenuEditShow[j][i].Pdata,0);//初始化顯示

oldid =

0;

//沒(méi)有原先選擇的項

}else{

if(WhichKey == KEY_UP)

oldid = KeyTab[MenuNextID].PressDown;

else

oldid = KeyTab

[MenuNextID].PressUp;

//指示原先的項

}

for(i=1;i

if(MenuEditShow[j][i].Id == oldid)

ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j]

[i].Column,MenuEditShow[j][i].Pdata,0);//正常顯示原先的項

else{

if(MenuEditShow[j][i].Id == MenuNextID)

ShowString(MenuEditShow[j][i].Lin,MenuEditShow

[j][i].Column,MenuEditShow[j][i].Pdata,1);//反顯當前選擇的項

}

}

WhichKey = KEY_NONE;

}

uint32 Edit(void)

{

struct KeyTabStruct NowKeyTab;//指示當前的菜單值

uint32 escflag = FALSE;

ResetFlag = FALSE;

ChangeFlag = FALSE;

EscFlag = FALSE;

MenuID = MENU_EDIT;

NowKeyTab = KeyTab[MenuID];

MenuNextID = NowKeyTab.PressOk;

(*NowKeyTab.CurrentOperate)();//顯示主菜單

do{

if(WhichKey == KEY_NONE)

WaitKey();//等待按鍵

switch(WhichKey){

case KEY_ESC : if(NowKeyTab.PressEsc != MENU_NO)

{

MenuID =

NowKeyTab.PressEsc;

MenuNextID =

NowKeyTab.MenuIndex;

NowKeyTab = KeyTab

[MenuID];

NowKeyTab.PressOk =

MenuNextID;

(*NowKeyTab.CurrentOperate)

();//顯示當前菜單

}else

escflag =

TRUE;//退出編程狀態(tài)

break;

case KEY_OK:if(NowKeyTab.PressOk != MENU_NO)

{

MenuID =

NowKeyTab.PressOk;

NowKeyTab = KeyTab

[MenuID];

MenuNextID =

NowKeyTab.PressOk;

}

(*NowKeyTab.CurrentOperate)

();//執行當前按鍵的操作

break;

case KEY_UP:if((MenuNextID != MENU_NO) &&

(KeyTab[MenuNextID].PressUp != MENU_NO)){

NowKeyTab.PressOk =

KeyTab[MenuNextID].PressUp;

MenuNextID = KeyTab

[MenuNextID].PressUp;

(*NowKeyTab.CurrentOperate)();//執行當前按鍵的操作

}

break;

case KEY_DOWN:if((MenuNextID != MENU_NO) &&

(KeyTab[MenuNextID].PressDown != MENU_NO)){

NowKeyTab.PressOk =

KeyTab[MenuNextID].PressDown;

MenuNextID = KeyTab

[MenuNextID].PressDown;

(*NowKeyTab.CurrentOperate)();//執行當前按鍵的操作

}

break;

case KEY_RESET: ResetFlag = TRUE;

break;

default: break;

}

}while(!ResetFlag && !EscFlag && !escflag);

if(ChangeFlag && !EscFlag && !ResetFlag)

EditDataChange();

if(ResetFlag)

returnSYS_RESET;

else{

return0;

}

}

關(guān)于這個(gè)菜單的說(shuō)明:

1.我用的是ARM處理器,所以51的時(shí)候把const改成code,uint32改成unsigned char。

2.在網(wǎng)上的資料中,結構體數組是存在RAM中的,我把它放在也flash中了,然后再定義一個(gè)

結構體變量,就樣就可以省很多RAM,比較適合51.

3.在網(wǎng)上資料中,因為保存了原來(lái)的選擇,當你離開(kāi)編程狀態(tài)重新進(jìn)行后,會(huì )發(fā)現選擇上會(huì )

是原來(lái)進(jìn)行的順序,我改動(dòng)之后,退出上一級菜單還是你選的那一項,但重新進(jìn)入后就是第

一個(gè)指定項。

4.增加UP和DOWN顯示,可以反顯最新選定的選項,正常顯示原來(lái)的選項。



評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>