当前位置:首页 > 公众号精选 > 嵌入式云IOT技术圈
[导读]声明:本处所说的菜单是用在128*64这种小屏幕的菜单,例如下面这种,不是彩屏上的GUI。

声明:本处所说的菜单是用在128*64这种小屏幕的菜单,例如下面这种,不是彩屏上的GUI。

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

开始的人偷懒,不想一秒就直接上,所有菜单都这样做,一层套一层

void test_main(void) { while(1)
        {
                get_key(&key); switch(key)
                { case 1:
                                test_key(); break; case 2:
                                test_lcd(); break;
                        ....
                }
        }
}

当菜单越来越多,就开始纠结了,这样写维护不便,看起来也不美,还浪费程序空间。

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

想来想去,这些菜单到底有什么不好?对于我来说,为什么不好用? 得出下面结论:

  1. 管得太宽 菜单,你就管菜单切换就行了,到了最低一层,也就是实际的测试功能,就不要管了。 菜单切换是类似的,实际测试都是不同的。比如在菜单中,按键1,是进入第一个菜单。但是在测试中,按键1,功能都不一样。 如果菜单连这个也要管,相同动作功能太多,无法进行统一抽象,就很难模块化。
  2. 出发点不一样 上面说到的菜单,出发点都是如何设计一个好的菜单数据结构,让程序快速,高效运行。 我想要的却是一个容易维护的菜单结构,至于菜单的代码有多乱多纠结,没关系, 而且,几百上千个菜单,就算用轮询的方法,也不过几百us吧,没关系。

根据需求,我重新设计了一个菜单结构体

/**
 * @brief  菜单对象
*/ typedef struct _strMenu { MenuLel l; ///<菜单等级 char cha[MENU_LANG_BUF_SIZE]; ///中文 char eng[MENU_LANG_BUF_SIZE]; ///英文 MenuType type; ///菜单类型 s32 (*fun)(void); ///测试函数 } MENU;

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

const MENU EMenuListTest[]=
{
        MENU_L_0,//菜单等级 "测试程序",//中文 "test", //英文 MENU_TYPE_LIST,//菜单类型 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_1,//菜单等级 "LCD",//中文 "LCD", //英文 MENU_TYPE_LIST,//菜单类型 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "VSPI OLED",//中文 "VSPI OLED", //英文 MENU_TYPE_FUN,//菜单类型 test_oled,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "I2C OLED",//中文 "I2C OLED", //英文 MENU_TYPE_FUN,//菜单类型 test_i2coled,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_1,//菜单等级 "声音",//中文 "sound", //英文 MENU_TYPE_LIST,//菜单类型 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "蜂鸣器",//中文 "buzzer", //英文 MENU_TYPE_FUN,//菜单类型 test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "DAC音乐",//中文 "DAC music", //英文 MENU_TYPE_FUN,//菜单类型 test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "收音",//中文 "FM", //英文 MENU_TYPE_FUN,//菜单类型 test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_1,//菜单等级 "触摸屏",//中文 "tp", //英文 MENU_TYPE_LIST,//菜单类型 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "校准",//中文 "calibrate", //英文 MENU_TYPE_FUN,//菜单类型 test_cal,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_2,//菜单等级 "测试",//中文 "test", //英文 MENU_TYPE_FUN,//菜单类型 test_tp,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_1,//菜单等级 "按键",//中文 "KEY", //英文 MENU_TYPE_FUN,//菜单类型 test_key,//菜单函数,功能菜单才会执行,有子菜单的不会执行 /*最后的菜单是结束菜单,无意义*/ MENU_L_0,//菜单等级 "END",//中文 "END", //英文 MENU_TYPE_NULL,//菜单类型 NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 };

这个菜单列表有什么特点和要求呢? 1 需要一个根节点和结束节点 2 子节点必须跟父节点,类似下面结构

-----------------------------------------------
根节点
        第11级菜单
                       第1个子菜单
                       第2个子菜单
                       第3个子菜单
        第21级菜单
                       第1个子菜单
                                     第1个孙菜单
                                     第2个孙菜单
                       第2个子菜单
                       第3个子菜单
        第31级菜单
        第41级菜单
        第51级菜单
结束节点
------------------------------------------------

第2个1级菜单有3个子菜单,子菜单是2级菜单,其中第1个子菜单下面又有2个孙菜单(3级菜单)。

维护菜单,就是维护这个列表,添加删除修改,非常容易。 那菜单程序怎么样呢?管他呢。 定义好菜单后,通过下面函数运行菜单,

 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:https://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。

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

显示效果

128*64 OLED

128*128 tft lcd

320*240 tft lcd

总结

类似菜单在我开发的产品上已经推广使用。 经测试,可以明显减少测试程序代码量,节省程序空间。 并且易于修改和维护。

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

以前微处理器(MPU)与微控制器(MCU)是截然不同的两种设备,MPU支持丰富的软件系统,如Linux和相关的软件堆栈,而MCU通常将专注于裸机和RTOS。近年来,随着MCU的性能越来越高,MCU和MPU之间的区别变得越...

关键字: MCU MPU 开发板

该产品线提供了并行SRAM的低成本替代方案,容量高达 4 Mb,具有143 MHz SPI/SQI™通信功能

关键字: SRAM 存储器 MCU

瑞典乌普萨拉,2024年3月27日 – 全球领先的嵌入式系统开发软件解决方案供应商IAR自豪地宣布:公司备受全球数百万开发者青睐的开发环境再次升级,已率先支持瑞萨首款通用32位RISC-V MCU,该 MCU 搭载了瑞萨...

关键字: MCU RISC-V CPU

3月26日,四维图新旗下杰发科技与国际第三方独立检测、检验和认证机构德国莱茵TÜV集团(以下简称TÜV莱茵)在上海举办颁证仪式,杰发科技宣布AC7840x系列车规级MCU芯片已成功通过ISO 26262 ASIL B功能...

关键字: 芯片 MCU 智能座舱

吹风机是居家生活必备物品,然而传统型吹风机所带来的体验并不佳,高频使用的女性群体对此更是深有感触。究其原因主要有:转速低,通常在每分钟2万转左右,导致干发速度慢;高温干发,容易损伤头发;噪声大且体积笨重等等。因此,能改善...

关键字: 吹风机 MCU 电源

Holtek新推出Sub-1GHz RF OOK/FSK Transmitter OTP MCU BC68R2123,扩大Holtek Sub-1GHz Tx系列产品涵盖面,并提供客户无线控制产品优势竞争力,适合各类无线...

关键字: RF发射器 MCU 无线控制

Holtek隆重推出全新一代32-bit Arm® Cortex®-M0+ 5V CAN MCU - HT32F53231/HT32F53241/HT32F53242/HT32F53252。这一系列单片机带有来自Bosc...

关键字: MCU 工业自动化 单片机

Holtek新推出BS67F2432具备触控按键、高精准度HIRC与LCD驱动器Flash MCU。主要特色为内建高精准度4MHz HIRC振荡电路、8路触控按键及最大支持4COM×15SEG LCD驱动器。适用于触控接...

关键字: MCU LCD驱动器 定时器

Holtek 新推出 BS45F2345 Touch A/D Flash MCU,特点内建高精准度振荡器、精准的 ADC 参考电压、8 路触控按键及支持SLCD 功能。其中触控可通过 CS (Conductive Sus...

关键字: MCU 电磁炉 振荡器

Holtek针对电池充电器应用领域,推出HT45F5QC-5/HT45F5QC-6专用 MCU,内建CAN Bus控制器,符合ISO11898-1:2003规范的CAN 2.0A/B协议,应用于二轮/三轮电动车、电动辅助...

关键字: 充电器 MCU
关闭
关闭