你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

一种简易菜单的思考  

[复制链接]
huangxuejia-292 发布时间:2018-6-24 11:52
声明:本处所说的菜单是用在128*64这种小屏幕的菜单,不是彩屏上的GUI。例如下面这种


1.jpg


作为一个底层驱动工程师,驱动写完了,是要写硬件测试程序的。
这个测试程序,一般给测试部/硬件工程师用来测试硬件,
也会给工厂产线测试准成品。

开始的人偷懒,不想一秒就直接上,所有菜单都这样做,一层套一层
  1. void test_main(void)
  2. {
  3.         while(1)
  4.         {
  5.                 get_key(&key);

  6.                 switch(key)
  7.                 {
  8.                         case 1:
  9.                                 test_key();
  10.                                 break;

  11.                         case 2:
  12.                                 test_lcd();
  13.                                 break;

  14.                         ....

  15.                        
  16.                        
  17.                 }
  18.        
  19.         }
  20. }
复制代码
当菜单越来越多,就开始纠结了,,,,
这样写维护不便,看起来也不美,还浪费程序空间。

作为一个天天看《编程之美》的码农,决定改变现状。
酷狗百度一番,找到了两个参考:
《基于二叉树的多层的液晶菜单界面设计》
《--基于节点编号的通用树状菜单设计方法与实现.pdf》
按照他们的设计方法,鼓捣了一个版本,能用,挺好,但是也纠结。
因为他们用了这种数据结构。对于程序运行来说,非常好。
但是对于我来说,菜单代码是一次性的,但是菜单内容,却是会经常改的。
让我用人脑去维护一个几十个上百个菜单的树,不容易。

想来想去,这些菜单到底有什么不好?对于我来说,为什么不好用?
得出下面结论:
1 管得太宽
菜单,你就管菜单切换就行了,到了最低一层,也就是实际的测试功能了,就不要管了。
菜单切换时类似的,实际测试都是不同的。比如在菜单中,1,是进入第一个菜单。但是在测试中,按键1,功能都不一样。
如果菜单连这个也要管,太累。
2 出发点不一样
上面说到的菜单,出发点都是如何设计一个好的菜单数据结构,让程序快速,高效运行。
我想要的却是一个容易维护的菜单结构,至于菜单的代码有多乱多纠结,没关系,
而且,几百上千个菜单,就算用轮询的方法,也不过几百us吧,没关系。

根据需求,设计了一个菜单结构体
  1. /**
  2. * @brief  菜单对象
  3. */
  4. typedef struct _strMenu
  5. {
  6.     MenuLel l;     ///<菜单等级
  7.     char cha[MENU_LANG_BUF_SIZE];   ///中文
  8.     char eng[MENU_LANG_BUF_SIZE];   ///英文
  9.     MenuType type;  ///菜单类型
  10.     s32 (*fun)(void);  ///测试函数

  11. } MENU;
复制代码

是的,就这么简单,每一个菜单都是这个结构体
用这个结构体填充一个列表,就是我们的菜单了

  1. const MENU EMenuListTest[]=
  2. {
  3.         MENU_L_0,//菜单等级
  4.         "测试程序",//中文
  5.         "test",        //英文
  6.         MENU_TYPE_LIST,//菜单类型
  7.         NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行

  8.                 MENU_L_1,//菜单等级
  9.                 "LCD",//中文
  10.                 "LCD",        //英文
  11.                 MENU_TYPE_LIST,//菜单类型
  12.                 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行
  13.                         MENU_L_2,//菜单等级
  14.                         "VSPI OLED",//中文
  15.                         "VSPI OLED",        //英文
  16.                         MENU_TYPE_FUN,//菜单类型
  17.                         test_oled,//菜单函数,功能菜单才会执行,有子菜单的不会执行

  18.                         MENU_L_2,//菜单等级
  19.                         "I2C OLED",//中文
  20.                         "I2C OLED",        //英文
  21.                         MENU_TYPE_FUN,//菜单类型
  22.                         test_i2coled,//菜单函数,功能菜单才会执行,有子菜单的不会执行


  23.                 MENU_L_1,//菜单等级
  24.                 "声音",//中文
  25.                 "sound",        //英文
  26.                 MENU_TYPE_LIST,//菜单类型
  27.                 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行
  28.                         MENU_L_2,//菜单等级
  29.                         "蜂鸣器",//中文
  30.                         "buzzer",        //英文
  31.                         MENU_TYPE_FUN,//菜单类型
  32.                         test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行

  33.                         MENU_L_2,//菜单等级
  34.                         "DAC音乐",//中文
  35.                         "DAC music",        //英文
  36.                         MENU_TYPE_FUN,//菜单类型
  37.                         test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行

  38.                         MENU_L_2,//菜单等级
  39.                         "收音",//中文
  40.                         "FM",        //英文
  41.                         MENU_TYPE_FUN,//菜单类型
  42.                         test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行


  43.                 MENU_L_1,//菜单等级
  44.                 "触摸屏",//中文
  45.                 "tp",        //英文
  46.                 MENU_TYPE_LIST,//菜单类型
  47.                 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行
  48.                        
  49.                         MENU_L_2,//菜单等级
  50.                         "校准",//中文
  51.                         "calibrate",        //英文
  52.                         MENU_TYPE_FUN,//菜单类型
  53.                         test_cal,//菜单函数,功能菜单才会执行,有子菜单的不会执行

  54.                         MENU_L_2,//菜单等级
  55.                         "测试",//中文
  56.                         "test",        //英文
  57.                         MENU_TYPE_FUN,//菜单类型
  58.                         test_tp,//菜单函数,功能菜单才会执行,有子菜单的不会执行
  59.                        
  60.                 MENU_L_1,//菜单等级
  61.                 "按键",//中文
  62.                 "KEY",        //英文
  63.                 MENU_TYPE_FUN,//菜单类型
  64.                 test_key,//菜单函数,功能菜单才会执行,有子菜单的不会执行

  65.         /*最后的菜单是结束菜单,无意义*/                       
  66.         MENU_L_0,//菜单等级
  67.         "END",//中文
  68.         "END",        //英文
  69.         MENU_TYPE_NULL,//菜单类型
  70.         NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行
  71. };
复制代码
这个菜单列表有什么特点和要求呢?
1 需要一个根节点和结束节点
2 子节点必须跟父节点,类似下面结构
-----------------------------------------------
根节点
        第1个1级菜单
                       第1个子菜单
                       第2个子菜单
                       第3个子菜单
        第2个1级菜单
                       第1个子菜单
                                     第1个孙菜单
                                     第2个孙菜单
                       第2个子菜单
                       第3个子菜单
        第3个1级菜单
        第4个1级菜单
        第5个1级菜单
结束节点
------------------------------------------------
第2个1级菜单有3个子菜单,子菜单是2级菜单,其中第1个子菜单下面又有2个孙菜单(3级菜单)。

维护菜单,就是维护这个列表,添加删除修改,非常容易。
那菜单程序怎么样呢?管他呢。
定义好菜单后,通过下面函数运行菜单,
  1. emenu_run(WJQTestLcd, (MENU *)&WJQTestList[0], sizeof(WJQTestList)/sizeof(MENU), FONT_SONGTI_1616, 2);       
复制代码
-第1个参数是在哪个LCD上显示菜单,
-第2个是菜单列表,
-第3个是菜单长度,
-第4个四字体,
-第5则是行间距


注意:
运行这个菜单需要有rtos,因为菜单代码是while(1)的,陷进去就不出来了。
需要有其他线程(TASK)维护系统,例如按键扫描。

代码托管在github:http://github.com/wujique/stm32f407/tree/sw_arch
相关文件:emenu.c/emenu.h/emenu_test.c

当前代码:
1实现了双列菜单,用数字键选择进入下一层。每页最多显示8个菜单(4*4键盘用1-8键)
2 实现了单列菜单,通过上下翻查看菜单,确认键进入菜单。
3 天顶菜单未实现,谁有兴趣可以加上。
3 基于LCD驱动架构,这个简易菜单自适应于多种LCD。

效果如下,有需要的尽管拿去,不用谢。

OLED效果
3.jpg

4.jpg

1.44 128*128 tftlcd 效果
1.jpg

2.jpg

2.8 320*240 tftlcd 效果

5.jpg

6.jpg

路过点个赞呗!


评分

参与人数 3 ST金币 +15 收起 理由
五哥1 + 5 对于常用嵌套编程的人来说这个有新的思路.
toofree + 5 很给力!
子曰好人 + 5 很给力!

查看全部评分

收藏 3 评论19 发布时间:2018-6-24 11:52

举报

19个回答
huangxuejia-292 回答时间:2018-6-25 09:14:02
都在玩GUI,这么简陋的东西,不知道还有没有人用。。。。。
子曰好人 回答时间:2018-6-25 09:38:40
虽然我目前用不上GUI,但是楼主给的思路有一定的启发作用,感谢分享
strang 回答时间:2018-6-25 10:01:06
我们产品上就有菜单,和楼主思路类似
huangxuejia-292 回答时间:2018-6-25 10:03:32
strang 发表于 2018-6-25 10:01
我们产品上就有菜单,和楼主思路类似

有什么好设计提醒提醒我,我优化优化
strang 回答时间:2018-6-25 10:07:15
用函数指针做界面,每个函数里都有while(1)
wolfgang2015 回答时间:2018-6-25 11:00:47
麻烦的东东,继续优化;
潜在问题:返回上级菜单
程序员 回答时间:2018-6-25 11:26:30
很赞!
huangxuejia-292 回答时间:2018-6-25 13:22:55
wolfgang2015 发表于 2018-6-25 11:00
麻烦的东东,继续优化;
潜在问题:返回上级菜单

版主,你是说返回上级菜单有问题吗?
与龙共舞 回答时间:2018-6-25 16:09:28
双向链表 基本都是菜单的路子
12下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版