- xwj优化的通用菜单程序
- //呵呵,都在讨论菜单啊?那我也来优化一个! //
- //大家多提意见哦:-) //
- // //
- //--------------------------------------------------------------------------//
- // //
- // (c) Copyright 2007-2008 xuwenjun //
- // All Rights Reserved //
- // V1.00 //
- //--------------------------------------------------------------------------//
- //标 题: xwj优化的通用菜单程序 //
- //文件名: xwj_menu.c //
- //版 本: V1.00 //
- //修改人: xwj E-mail:xuwenjun[url=home.php?mod=space&uid=329077]@21cn.com[/url] //
- //日 期: 07-10-25 //
- //描 述: xwj优化的通用菜单程序 //
- //声 明: //
- // 以下代码仅免费提供给学习用途,但引用或修改后必须在文件中声明出处. //
- // 如用于商业用途请与作者联系. E-mail:xuwenjun[url=home.php?mod=space&uid=329077]@21cn.com[/url] //
- // 有问题请mailto xuwenjun[url=home.php?mod=space&uid=329077]@21cn.com[/url] 欢迎与我交流! //
- //--------------------------------------------------------------------------//
- //老版本: 无 老版本文件名: //
- //创建人: xwj E-mail:xuwenjun[url=home.php?mod=space&uid=329077]@21cn.com[/url] //
- //日 期: 03-11-06 //
- //--------------------------------------------------------------------------//
- //描 述: //
- // xwj优化的通用菜单程序 //
- // MCU 型号: 任意 //
- // 开发环境: ANSI C任意平台 //
- // 开发日期: 2007.10.25 //
- // 程序编写: XWJ //
- //--------------------------------------------------------------------------//
- // 程序特点: //
- //1、程序和数据的分离,菜单可任意定义,甚至放在RAM里 //
- //2、定义好链表和菜单条目后,即可自动显示菜单、自动循环、跳转、执行, //
- // 自动控制程序流向,不需任何额外的判断和switch //
- //3、保留菜单路径,可原路返回(当然,也可直接跳回去啦:-) ) //
- //4、可任意定义菜单层数,每层菜单可以任意组织,多一层菜单仅需增加1字节RAM //
- //5、节省内存,仅需2字节+菜单层数个RAM //
- //--------------------------------------------------------------------------//
- #include <stdio.h>
- #include “my_displays.h” //my_displays.c中包含char putchar (char)的实体
- //和 液晶显示模块(点、线、填充...)
- //以及printat(x,y,char*),有此足以实现任何界面显示
- #define MENU_MAX_LAYER 16 //菜单链最大层数,示例只用到4层
- #define MENU_NUM_OF_PAGE 4 //每页可以显示菜单数目
- unsigned char Menu_tree[MENU_MAX_LAYER]; //菜单按键树,类似堆栈
- unsigned char Menu_tree_ptr; //当前菜单按键树所在层数
- unsigned char Menu_item_ptr; //当前菜单项在本层中位置
- typedef struct
- {
- unsigned char code *Menu_NextTab; //本级菜单菜单链表
- char code *Menu_Name; //当前菜单名称
- void (*CurrentOperate)(); //当前状态应该执行的功能操作
- }Menustruct;
- void (*KeyFuncPtr)(); //按键功能指针
- void refur_Menu(void); //刷新菜单层,就是依次打印总标题、各个条目,
- void refur_Menu_item(void); //刷新本层菜单项,就是恢复原来项颜色,反显当前项
- //则两个函数和界面布局有关,自己写吧
-
- extern void ScanKey(void); //键盘扫描
- void Menu_Key_Func(unsigned char NowKey); //菜单按键功能
- {
- switch(NowKey)
- {
- case KEY_UP:
- if(*(KeyTab[Menu_tree][Menu_tree_ptr]].Menu_NextTab)) //Menu_NextTab[0]不为0,是菜单
- // 也可以判断函数指针是否是NULL,写成下面这样:
- // if(KeyTab[Menu_tree][Menu_tree_ptr]].CurrentOperate == NULL)) //Menu_NextTab[0]不为0,是菜单
- {
- Menu_item_ptr--; //菜单项上移
- if(Menu_tree_ptr== -1) //菜单项上移到顶翻转了,修正到最后一项
- Menu_item_ptr=sizeof(*(KeyTab[Menu_tree][Menu_tree_ptr]].Menu_NextTab))-1; //菜单循环
- refur_Menu_item(); //刷新本层菜单项
- }
- else
- Error_Beep(); //否则不是菜单,上下移无效,蜂鸣警告
- break;
- case KEY_doWN:
- if(*(KeyTab[Menu_tree][Menu_tree_ptr].Menu_NextTab)) //Menu_NextTab[0]不为0,是菜单
- {
- Menu_item_ptr++; //菜单项下移
- if(Menu_item_ptr==sizeof(*(KeyTab[Menu_tree][Menu_tree_ptr]].Menu_NextTab))-1) //菜单项下移到底
- Menu_item_ptr=0; //菜单项下移到底,循环上去
- refur_Menu_item(); //刷新本层菜单项
- }
- else
- Error_Beep(); //否则不是菜单,上下移无效,蜂鸣警告
- break;
- case KEY_OK://KEY_OK, KEY_UP, KEY_ESC,
- if(*(KeyTab[Menu_tree][Menu_tree_ptr]].Menu_NextTab)) //Menu_NextTab[0]不为0,是菜单
- {
- Menu_tree[Menu_tree_ptr+1]=KeyTab[Menu_tree][Menu_tree_ptr]].Menu_NextTab[Menu_item_ptr]);
- //下一级菜单压进菜单树,能看懂吗?
- Menu_tree_ptr++; //菜单又多了一级
- refur_Menu(); //刷新菜单层,当前菜单当然是在Menu_tree[Menu_tree_ptr]中啦
- }
- else //不是菜单,执行当前菜单项的操作
- {
- KeyFuncPtr=KeyTab[Menu_tree][Menu_tree_ptr]].CurrentOperate;
- (*KeyFuncPtr)(); //执行当前菜单项的操作
- }
- break;
- case KEY_ESC:
- //
- if(Menu_tree_ptr) //当前菜单位置不是顶层(主界面)
- {
- Menu_tree_ptr--; //则返回上一层
- refur_Menu(); //刷新菜单层,当前菜单当然是在Menu_tree[Menu_tree_ptr]中啦
- }
- else
- Error_Beep(); //否则蜂鸣警告
- break;
- //
- //case Other:
- //....
- } //
- }
- //************************************************************************
- //Menu struct: //菜单示例,共4层19项
- //************************************************************************
- // First Bmp--------------------->(MenuID_0)
- // ---+
- // |View--------------------->(MenuID_1)
- // +---+
- // | |About Recorde-------->(MenuID_2)
- // | +--------------
- // | |HandSet Clock-------->(MenuID_3)
- // | +--------------
- // |Operation---------------->(MenuID_4)
- // +---+
- // |Set Position--------->(MenuID_5)
- // +---+
- // | |Rd Zj To Flash------->(MenuID_6)
- // | +--------------
- // | |Rd Zl To Ram--------->(MenuID_7)
- // | +--------------
- // | |Del Given Zl--------->(MenuID_8)
- // | +--------------
- // | |Del All Zl----------->(MenuID_9)
- // | +--------------
- // |Test--------------------->(MenuID_10)
- // +---+
- // | |Ram Test------------->(MenuID_11)
- // | +--------------
- // | |Flash Test----------->(MenuID_12)
- // | +--------------
- // |System Set--------------->(MenuID_13)
- // +---+
- // |Debug---------------->(MenuID_14)
- // +---+
- // | |PassWord--------->(MenuID_15)
- // | +--------------
- // | |See Picture------>(MenuID_16)
- // | +--------------
- // |Set Hand Clk--------->(MenuID_17)
- // +--------------
- //************************************************************************
- //菜单链表,每项菜单一条,共19项
- unsigned char code Tab_First_Bmp[]=
- {1,4,0x00
- };
- unsigned char code Tab_View[]=
- {2,3,0x00
- };
- unsigned char code Tab_About_Recorde[]=
- {0x00
- };
- unsigned char code Tab_HandSet[]=
- {0x00
- };
- unsigned char code Tab_Operation[]=
- {5,10,13,14,17,0x00
- };
- unsigned char code Tab_Set_Position[]=
- {6,7,8,9,0x00
- };
- unsigned char code Tab_Rd_Zj_To_Flash[]=
- {0x00
- };
- //...
- //每项菜单一条,共19项
- //菜单结构,每项菜单一条,,共19项
- KeyTabstruct code KeyTab[]=
- {
- //Menu_NextTab, Menu_Name, CurrentOperate
- //本级菜单菜单链表, 当前菜单名称, 当前状态应该执行的功能操作
- {Tab_First_Bmp,"First_Bmp",*First_Bmp}, //实际上菜单功能可以为NULL,由refur_Menu()统一操作;
- {Tab_View,"View",*View}, //不是菜单则用实际功能函数
- {Tab_About_Recorde,"About Recorde",*About_Recorde}, //非菜单
- {Tab_HandSet Clock,"HandSet Clock",*HandSet_Clock}, //非菜单
- {Tab_Operation,"Operation",*NULL}, //菜单
- {Tab_Set_Position,"Set Position",*NULL}, //菜单
- {Tab_Rd_Zj_To_Flash,"Rd Zj To Flash",*Rd_Zj_To_Flash}, //非菜单
- //...
- //每项菜单一条,共19项
- };
- //使用方法:
- //1、定义好链表和菜单条目,写好每个功能函数
- //2、主循环中不停的读按键,然后Menu_Key_Func();即可自动显示菜单、自动循环、跳转、执行
- //比如:
- void main(void)
- {
- Menu_tree_ptr=0; //当前菜单按键树所在层数
- Menu_item_ptr=0; //当前菜单项在本层中位置
- refur_Menu(); //刷新顶层菜单
- refur_Menu_item(); //刷新本层菜单项
-
-
- while(1)
- {
- ScanKey(); //键盘扫描
- if(KeyOk)
- Menu_Key_Func(); //有按键则执行按键功能
- }
- }
研究和使用过一段时间ucosII.
感谢 @ayb_ice 的耐心指教。
再后来又涉及一些电路的问题,有一段时间来得少,那段时间主要做嵌入式linux下的应用和驱动。
后来我又经常来了,而且还参与了版块的管理。
又认识了很多新朋友,包括 @yyy71cj 等。
21ic伴随了我职业的成长,给我很多帮助,我也非常乐意和大家分享。实在是不可或缺的精神家园。
感谢21ic,感谢各位坛友。