久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

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

[復制鏈接]
跳轉到指定樓層
樓主
ID:305925 發表于 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顯示,可以反顯最新選定的選項,正常顯示原來的選項。

評分

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

查看全部評分

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美一区二区三区在线视频 | 久久成人免费视频 | 国产精品99久久久久 | 亚洲视频精品 | av在线免费不卡 | 国内精品久久久久 | 久久成人精品视频 | 午夜影院视频 | 国产福利在线 | 欧美日本韩国一区二区三区 | gav成人免费播放视频 | 日韩久久久久久 | 国产亚洲一区二区三区在线 | 国产精品免费一区二区 | 免费的日批视频 | а天堂中文最新一区二区三区 | 先锋资源网 | 欧美日本韩国一区二区三区 | 日韩日韩日韩日韩日韩日韩日韩 | 免费在线观看黄网站 | 亚洲乱码一区二区三区在线观看 | 日韩精品一区二区三区中文字幕 | 亚洲一区欧美一区 | 中文字幕一区在线 | 99re视频在线免费观看 | 综合一区二区三区 | 久久精品天堂 | 男人天堂99 | 五月天婷婷久久 | 永久看片 | 九九九视频在线 | 欧美一二三四成人免费视频 | 国产露脸对白88av | 国产99精品| 久久久青草婷婷精品综合日韩 | 精品久久久久久久久久久下田 | 观看av| 欧美精品一区免费 | 二区久久| 精品国产乱码久久久久久丨区2区 | 亚洲人成人一区二区在线观看 |