找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 8204|回復: 4
打印 上一主題 下一主題
收起左側

單片機多級菜單編程 用鏈表實現(xiàn)樹狀的菜單結構源碼介紹

[復制鏈接]
跳轉到指定樓層
樓主
ID:305925 發(fā)表于 2018-4-12 17:20 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
單片機多級菜單編程實現(xiàn)(ZT)建立一個樹狀的菜單結構,用鏈表實現(xiàn)
鏈表中包含:
1、指向同級左右菜單和指向父菜單、子菜單的四個菜單結構體指針;
2、進入該菜單時需要執(zhí)行的初始化函數(shù)指針
3、退出該菜單時需要執(zhí)行的結束函數(shù)指針
4、該菜單內(nèi)的按鍵處理函數(shù)指針數(shù)組的指針操作菜單模塊需要的按鍵操作有:左、右、確
認、退出。
采用這種辦法,可以方便的添加或刪減菜單。并且只需要在其頭文件中修改初始變量就可
以實現(xiàn),完全無須修改C文件中的任何函數(shù)。

具體結構定義
我的定義,做個參考:
#define MENU_HLP_EN //菜單幫助信息使能
typedef struct

void (*pMenuTaskInit)(void); //指向菜單任務初始化函數(shù)的指針
void (*pMenuTaskEnd)(void); //指向菜單任務結束函數(shù)的指針
}MENU_TASK_TYP;
typedef struct MenuTyp

INT8U *MenuName; //菜單名稱字符串
WORK_MOD WorkMod; //工作狀態(tài)編號
MENU_TASK_TYP *pMenuTask; //指向菜單任務的指針
void (**pTaskKeyDeal)(void); //指向菜單任務按鍵處理函數(shù)數(shù)組的指針
#ifdef MENU_HLP_EN
INT8U *MenuHlp; //菜單幫助字符串
#endif
struct MenuTyp *pParent; //指向上層菜單的指針
struct MenuTyp *pChild; //指向子菜單的指針
struct MenuTyp *pRight; //指向右菜單的指針
struct MenuTyp *pLeft; //指向左菜單的指針
}MENU_TYP;

我根據(jù)網(wǎng)上的資料做的一個菜單:
/****************菜單數(shù)據(jù)結構**********************/
struct KeyTabStruct{
uint8 MenuIndex; //當前狀態(tài)索引號
uint8 MaxItems; //本級菜單最大條目數(shù)
uint8 ShowLevel; //菜單顯示內(nèi)容
uint8 PressOk; //按下"回車"鍵時轉向的狀態(tài)索引號
uint8 PressEsc; //按下"返回"鍵時轉向的狀態(tài)索引號
uint8 PressDown; //按下"向下"鍵時轉向的狀態(tài)索引號
uint8 PressUp; //按下"向上"鍵時轉向的狀態(tài)索引號
void (*CurrentOperate)(); //當前狀態(tài)應該執(zhí)行的功能操作
};
uint8 MenuID; //菜單ID號
uint8 MenuNextID; //下級菜單ID號
//CurMenuID=本菜單ID
//MaxMenuItem=同級菜單最大項數(shù)
//OkMenuID=子菜單層所對應的菜單ID,ID=999為菜單已經(jīng)到底了
//EscMenuID=父菜單層所對應的菜單ID,ID=999為菜單已經(jīng)到頂了
//DownMenuID=弟菜單層所對應的菜單ID,ID=999為菜單是獨生子
//UpMenuID=兄菜單層所對應的菜單ID,ID=999為菜單是獨生子
//CurFunction=本菜單所對應的菜單函數(shù)指針
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},
};
/**************************************編程菜單顯示數(shù)據(jù)
******************************/
const struct MenuDispData MenuEditShow[][MENU_MAX] = {
{{MENU_NO , 0, 0, "選擇: 消音→退出"}, //主菜單
{MENU_DATA_VIEW , 1, 6, "⒈數(shù)據(jù)查看"},
{MENU_SYS_EDIT , 2, 6, "⒉系統(tǒng)編程"},
{MENU_PRINT_DATA , 3, 6, "⒊數(shù)據(jù)打印"}},
{{MENU_NO , 0, 0, "數(shù)據(jù)查看: 消音→退出"}, //數(shù)據(jù)查

{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, "系統(tǒng)編程: 消音→退出"}, //系統(tǒng)編程
{MENU_SUM_SET , 1, 0, "⒈容量設置"},
{MENU_EDIT_INSULATE , 2, 0, "⒉隔離點"},
{MENU_EDIT_HZ , 3, 0, "⒊漢字描述"},
{MENU_LD_CONTROL , 1,12, "⒋聯(lián)動控制"},
{MENU_LD_DELAY , 2,12, "⒌模塊延時"},
{MENU_TIME_SET , 3,12, "⒍時鐘調(diào)整"}},
{{MENU_NO , 0, 0, "數(shù)據(jù)打印: 消音→退出"}, //數(shù)據(jù)打印
{MENU_PRINT_DATA_FIRE , 1, 0, "⒈火警數(shù)據(jù)"},
{MENU_PRINT_DATA_TROUBLE,2, 0, "⒉故障數(shù)據(jù)"},
{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<KeyTab[MenuNextID].MaxItems+1;i++)
ShowString(MenuEditShow[j][ i].Lin,MenuEditShow[j]
[i ].Column,MenuEditShow[j][ i].Pdata,0); //初始化顯示
oldid =
0;
//沒有原先選擇的項
}else{
if(WhichKey == KEY_UP)
oldid = KeyTab[MenuNextID].PressDown;
else
oldid = KeyTab
[MenuNextID].PressUp;
//指示原先的項

for(i=1;i<KeyTab[MenuNextID].MaxItems+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;

/******************************系統(tǒng)編程*******************************/
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)
(); //執(zhí)行當前按鍵的操作
break;
case KEY_UP : if((MenuNextID != MENU_NO) &&
(KeyTab[MenuNextID].PressUp != MENU_NO)){
NowKeyTab.PressOk =
KeyTab[MenuNextID].PressUp;
MenuNextID = KeyTab
[MenuNextID].PressUp;

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

break;
case KEY_DOWN: if((MenuNextID != MENU_NO) &&
(KeyTab[MenuNextID].PressDown != MENU_NO)){
NowKeyTab.PressOk =
KeyTab[MenuNextID].PressDown;
MenuNextID = KeyTab
[MenuNextID].PressDown;

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

break;
case KEY_RESET: ResetFlag = TRUE;
break;
default : break;

}while(!ResetFlag && !EscFlag&& !escflag);
if(ChangeFlag && !EscFlag && !ResetFlag)
EditDataChange();
if(ResetFlag)
return SYS_RESET;
else{
return 0;


關于這個菜單的說明:
1.我用的是ARM處理器,所以51的時候把const改成code,uint32改成unsigned char。
2.在網(wǎng)上的資料中,結構體數(shù)組是存在RAM中的,我把它放在也flash中了,然后再定義一個
結構體變量,就樣就可以省很多RAM,比較適合51.
3.在網(wǎng)上資料中,因為保存了原來的選擇,當你離開編程狀態(tài)重新進行后,會發(fā)現(xiàn)選擇上會
是原來進行的順序,我改動之后,退出上一級菜單還是你選的那一項,但重新進入后就是第
一個指定項。
4.增加UP和DOWN顯示,可以反顯最新選定的選項,正常顯示原來的選項。

評分

參與人數(shù) 2黑幣 +80 收起 理由
songhetai + 30
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏5 分享淘帖 頂 踩
回復

使用道具 舉報

沙發(fā)
ID:387860 發(fā)表于 2018-8-31 12:01 | 只看該作者
有具體的項目沒,分享一下
回復

使用道具 舉報

板凳
ID:275111 發(fā)表于 2020-4-28 17:47 | 只看該作者
贊。就是看著格式太累。
回復

使用道具 舉報

地板
ID:97678 發(fā)表于 2020-4-30 10:44 | 只看該作者
高大上的代碼。
可以分享一下具體的項目代碼嗎?
回復

使用道具 舉報

5#
ID:1124238 發(fā)表于 2024-6-17 10:55 | 只看該作者
可以分享一下具體的項目代碼嗎?非常感謝。!
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表