一个单片机产品菜单设计框架

发布时间:2024-11-11 15:31:46  
本文所说的菜单是用在128*64这种小屏幕的菜单,例如下面这种,不是彩屏上的GUI。 嵌入式资料包"> 【付费】STM32嵌入式资料包
图片
作为一个底层驱动工程师,驱动写完了,是要写硬件测试程序的。这个测试程序,一般给测试部/硬件工程师用来测试硬件, 也会给工厂产线测试准成品。
开始的人偷懒,不假思索直接上,所有菜单都这样做,一层套一层:

图片

    当菜单越来越多,就开始纠结了,这样写维护不便,看起来也不美,还浪费程序空间。
作为一个天天看《编程之美》的码农,决定改变现状。
酷狗百度一番,找到了两个参考: 《基于二叉树的多层的液晶菜单界面设计》 《基于节点编号的通用树状菜单设计方法与实现.pdf》 按照他们的设计方法,鼓捣了一个版本,能用,挺好,但是也纠结。 因为他们用了树这种数据结构。
对于程序运行来说,非常好,效率高。但是对于我来说,菜单代码是一次性的,但是菜单内容,却是会经常改的。让我用人脑去维护一个包含几十个上百个菜单的树,不容易。
想来想去,这些菜单到底有什么不好?对于我来说,为什么不好用?
得出下面结论:
  • 管得太宽 菜单,你就管菜单切换就行了,到了最低一层,也就是实际的测试功能,就不要管了。菜单切换是类似的,实际测试都是不同的。比如在菜单中,按键1,是进入第一个菜单。但是在测试中,按键1,功能都不一样。如果菜单连这个也要管,相同动作功能太多,无法进行统一抽象,就很难模块化。

  • 出发点不一样 上面说到的菜单,出发点都是如何设计一个好的菜单数据结构,让程序快速,高效运行。我想要的却是一个容易维护的菜单结构,至于菜单的代码有多乱多纠结,没关系, 而且,几百上千个菜单,就算用轮询的方法,也不过几百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 子节点必须跟父节点,类似下面结构。
-----------------------------------------------根节点        第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级菜单)。
维护菜单,就是维护这个列表,添加删除修改,非常容易。那菜单程序怎么样呢?管他呢。定义好菜单后,通过下面函数运行菜单:
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
当前代码:
  • 实现了双列菜单,用数字键选择进入下一层。每页最多显示8个菜单(4*4键盘用1-8键)

  • 实现了单列菜单,通过上下翻查看菜单,确认键进入菜单。3 天顶菜单未实现,谁有兴趣可以加上。

  • 基于LCD驱动架构,这个简易菜单自适应于多种LCD。




显示效果如下。

128*64 OLED

图片
图片

128*128 tft lcd

图片
图片

320*240 tft lcd

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

文章来源于:单片机与嵌入式    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    ,//菜单函数,功能菜单才会执行,有子菜单的不会执行 MENU_L_1,//菜单等级 "LCD",//中文......
    个文件中添加变量。请参见附件。 步骤10:从Uvision Keil的项目菜单转到子菜单应用程序/用户。 从uvision Keil的“项目”菜单中转到“应用程序/用户”子菜单。附加......
    核中配置UDA1341 设备驱动 在内核源代码目录输入:make menuconfig 开始配置内核,依次选择如下子菜单,找到音频驱动配置菜单: Device Drivers --->      <......
    核中配置UDA1341 设备驱动 在内核源代码目录输入:make menuconfig 开始配置内核,依次选择如下子菜单,找到音频驱动配置菜单: Device Drivers --->      <......
    )、选择Debug crosstool-NG,会多出一个子菜单,选中Save intermediate steps,此选项提供一个从上一步错误的地方继续编译,而不是从新编译,这样节约大量的时间。选择(3......
    ,依次选择如下子菜单项: Device Drivers --->      [*] HID Devices ---> 按空格键选中“USB Human Interface Device......
    这一部分只是进行配置就可以使用。因为配置的东西较多,没有给出详细的截图,看手册上介绍的就很明白。需要手册的请留下邮箱索取。 1 配置和测试USB 键盘、扫描器和鼠标 在内核源代码目录的终端输入:make menuconfig,依次选择如下子菜单......
    menuconfig,移动上下按键找到File Systems,按回车进入该子菜单再找到“Miscellaneous filesystems”菜单项,按回车进入该子菜单,找到“YAFFS2 file......
    调整模式的方法是:在按下电源启动按钮启动示波器的同时,用工具按住示波器后面板上的校准孔按钮,直到示波器启动,然后松开后面板上的校准按钮。此时可以通过效用菜单下的CAL子菜单进入调节模式。 泰克......
    的 ABC, BCD,EFG分别是一个菜单列表的菜单 菜单的结构框图为 对于单个菜单的结构为 对于每个菜单,分别有指向它上面的菜单,下面的菜单,它的子菜单,它的父菜单,它的菜单列表,和这个菜单......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>