標題: 單片機多級菜單編程 用鏈表實現樹狀的菜單結構源碼介紹 [打印本頁]
作者: zhang-student 時間: 2018-4-12 17:20
標題: 單片機多級菜單編程 用鏈表實現樹狀的菜單結構源碼介紹
單片機多級菜單編程實現(ZT)建立一個樹狀的菜單結構,用鏈表實現
鏈表中包含:
1、指向同級左右菜單和指向父菜單、子菜單的四個菜單結構體指針;
2、進入該菜單時需要執行的初始化函數指針
3、退出該菜單時需要執行的結束函數指針
4、該菜單內的按鍵處理函數指針數組的指針操作菜單模塊需要的按鍵操作有:左、右、確
認、退出。
采用這種辦法,可以方便的添加或刪減菜單。并且只需要在其頭文件中修改初始變量就可
以實現,完全無須修改C文件中的任何函數。
具體結構定義
我的定義,做個參考:
#define MENU_HLP_EN //菜單幫助信息使能
typedef struct
{
void (*pMenuTaskInit)(void); //指向菜單任務初始化函數的指針
void (*pMenuTaskEnd)(void); //指向菜單任務結束函數的指針
}MENU_TASK_TYP;
typedef struct MenuTyp
{
INT8U *MenuName; //菜單名稱字符串
WORK_MOD WorkMod; //工作狀態編號
MENU_TASK_TYP *pMenuTask; //指向菜單任務的指針
void (**pTaskKeyDeal)(void); //指向菜單任務按鍵處理函數數組的指針
#ifdef MENU_HLP_EN
INT8U *MenuHlp; //菜單幫助字符串
#endif
struct MenuTyp *pParent; //指向上層菜單的指針
struct MenuTyp *pChild; //指向子菜單的指針
struct MenuTyp *pRight; //指向右菜單的指針
struct MenuTyp *pLeft; //指向左菜單的指針
}MENU_TYP;
我根據網上的資料做的一個菜單:
/****************菜單數據結構**********************/
struct KeyTabStruct{
uint8 MenuIndex; //當前狀態索引號
uint8 MaxItems; //本級菜單最大條目數
uint8 ShowLevel; //菜單顯示內容
uint8 PressOk; //按下"回車"鍵時轉向的狀態索引號
uint8 PressEsc; //按下"返回"鍵時轉向的狀態索引號
uint8 PressDown; //按下"向下"鍵時轉向的狀態索引號
uint8 PressUp; //按下"向上"鍵時轉向的狀態索引號
void (*CurrentOperate)(); //當前狀態應該執行的功能操作
};
uint8 MenuID; //菜單ID號
uint8 MenuNextID; //下級菜單ID號
//CurMenuID=本菜單ID
//MaxMenuItem=同級菜單最大項數
//OkMenuID=子菜單層所對應的菜單ID,ID=999為菜單已經到底了
//EscMenuID=父菜單層所對應的菜單ID,ID=999為菜單已經到頂了
//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 MenuDispData MenuEditShow[][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, "⒉隔離點"},
{MENU_EDIT_HZ , 3, 0, "⒊漢字描述"},
{MENU_LD_CONTROL , 1,12, "⒋聯動控制"},
{MENU_LD_DELAY , 2,12, "⒌模塊延時"},
{MENU_TIME_SET , 3,12, "⒍時鐘調整"}},
{{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<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;
}
/******************************系統編程*******************************/
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; //退出編程狀態
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)
return SYS_RESET;
else{
return 0;
}
}
關于這個菜單的說明:
1.我用的是ARM處理器,所以51的時候把const改成code,uint32改成unsigned char。
2.在網上的資料中,結構體數組是存在RAM中的,我把它放在也flash中了,然后再定義一個
結構體變量,就樣就可以省很多RAM,比較適合51.
3.在網上資料中,因為保存了原來的選擇,當你離開編程狀態重新進行后,會發現選擇上會
是原來進行的順序,我改動之后,退出上一級菜單還是你選的那一項,但重新進入后就是第
一個指定項。
4.增加UP和DOWN顯示,可以反顯最新選定的選項,正常顯示原來的選項。
作者: yekai_yh 時間: 2018-8-31 12:01
有具體的項目沒,分享一下
作者: tianqi911 時間: 2020-4-28 17:47
贊。就是看著格式太累。
作者: jovew 時間: 2020-4-30 10:44
高大上的代碼。
可以分享一下具體的項目代碼嗎?
作者: 木子三 時間: 2024-6-17 10:55
可以分享一下具體的項目代碼嗎?非常感謝!!!
歡迎光臨 (http://www.zg4o1577.cn/bbs/) |
Powered by Discuz! X3.1 |
主站蜘蛛池模板:
国产精品一区二区在线
|
国产福利91精品一区二区三区
|
亚洲欧美国产视频
|
色婷婷综合网
|
国产精品久久久久久久一区探花
|
国产精品一码二码三码在线
|
91视频免费黄
|
国产激情视频在线免费观看
|
日韩天堂av
|
一区二区三区免费
|
中文字幕亚洲欧美日韩在线不卡
|
久久国内精品
|
成人精品鲁一区一区二区
|
久久久久久免费毛片精品
|
国产99久久
|
午夜免费成人
|
2019天天操
|
免费在线性爱视频
|
国产一区二区在线视频
|
免费在线国产视频
|
国产精品人人做人人爽
|
一区精品国产欧美在线
|
久久在视频
|
亚洲激情在线观看
|
91精品国模一区二区三区
|
91麻豆精品国产91久久久久久
|
国产精品欧美一区二区三区不卡
|
欧美电影免费观看
|
最近中文字幕免费
|
久久专区
|
av看看
|
欧美一级艳情片免费观看
|
99精品欧美一区二区三区综合在线
|
国产精品永久久久久久久www
|
免费h在线|
夜夜骑首页
|
中文字幕精品一区二区三区精品
|
亚洲二区视频
|
午夜精品久久久
|
夜夜草天天草
|
亚洲高清在线观看
|