新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 單片機多級菜單編程實現

        單片機多級菜單編程實現

        作者: 時間:2016-11-27 來源:網絡 收藏
        建立一個樹狀的菜單結構,用鏈表實現

        鏈表中包含:

        本文引用地址:http://www.104case.com/article/201611/322426.htm

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

        2、進入該菜單時需要執行的初始化函數指針

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

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

        認、退出。

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

        以實現,完全無須修改C文件中的任何函數。

        具體結構定義

        我的定義,做個參考:

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

        typedef struct

        {

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

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

        }MENU_TASK_TYP;

        typedef struct MenuTyp

        {

        INT8U*MenuName;//菜單名稱字符串

        WORK_MODWorkMod;//工作狀態編號

        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{

        uint8MenuIndex;//當前狀態索引號

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

        uint8ShowLevel;//菜單顯示內容

        uint8PressOk;//按下"回車"鍵時轉向的狀態索引號

        uint8PressEsc;//按下"返回"鍵時轉向的狀態索引號

        uint8PressDown;//按下"向下"鍵時轉向的狀態索引號

        uint8PressUp;//按下"向上"鍵時轉向的狀態索引號

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

        };

        uint8MenuID;//菜單ID號

        uint8MenuNextID;//下級菜單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 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, "⒉隔離點"},

        {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

        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

        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)

        returnSYS_RESET;

        else{

        return0;

        }

        }

        關于這個菜單的說明:

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

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

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

        3.在網上資料中,因為保存了原來的選擇,當你離開編程狀態重新進行后,會發現選擇上會

        是原來進行的順序,我改動之后,退出上一級菜單還是你選的那一項,但重新進入后就是第

        一個指定項。

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



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 岳阳市| 长汀县| 龙江县| 长沙市| 辽宁省| 山阴县| 漯河市| 大英县| 潞城市| 珲春市| 龙井市| 广丰县| 阿拉善盟| 安福县| 鄂托克旗| 阿鲁科尔沁旗| 云浮市| 上虞市| 兴和县| 陇川县| 湘潭县| 兰溪市| 乌审旗| 盐源县| 开鲁县| 襄城县| 兴义市| 汾西县| 万宁市| 大名县| 南汇区| 合川市| 塔城市| 偏关县| 锡林浩特市| 临清市| 仙居县| 青浦区| 平顺县| 环江| 湄潭县|