0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于二叉树的多层的液晶菜单界面设计

GReq_mcu168 来源:屋脊雀工作室 作者:屋脊雀工作室 2022-07-08 14:27 次阅读

以前用单片机做用户交互的菜单的时候,都比较痛苦,如何写一个复用性高,方便维护,可扩展性高的GUI框架呢?当然可以自己动手写一个,这个过程充满了艰辛和挑战,现在我推荐一个很棒的框架,直接拿来用就行,也可以借鉴和学习其中的思路,一定会收获颇丰。

知道有多少人折腾过液晶显示的菜单,我觉得很多人都应该搞过,我还记得以前大学参加电子设计竞赛获奖的作品,我就用到了一个12864,里面有菜单功能。

以前可能觉得菜单高大上,其实并不是想象中的复杂,本文为大家分享一个用单色屏做的菜单框架。

代码托管在github:

https://github.com/wujique/stm32f407/tree/sw_arch

公众号回复"菜单"也可获得源码.

1、概述

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

6aebecd6-fe85-11ec-ba43-dac502259ad0.png   2、菜单框架设计

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

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


1voidtest_main(void) 2{ 3while(1) 4{ 5get_key(&key); 6switch(key) 7{ 8case1: 9test_key(); 10break; 11case2: 12test_lcd(); 13break; 14.... 15} 16} 17}

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

作为一个天天看《编程之美》的码农,决定改变现状。

索引擎找了很久,找到了两个参考:

基于二叉树的多层的液晶菜单界面设计

基于节点编号的通用树状菜单设计方法与实现.pdf

按照他们的设计方法,鼓捣了一个版本,能用,挺好,但是也纠结。因为他们用了树这种数据结构。对于程序运行来说,非常好,效率高。但是对于我来说,菜单代码是一次性的,但是菜单内容,却是会经常改的。让我用人脑去维护一个包含几十个上百个菜单的树,不容易。

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

管得太宽 菜单,你就管菜单切换就行了,到了最低一层,也就是实际的测试功能,就不要管了。菜单切换是类似的,实际测试都是不同的。比如在菜单中,按键1,是进入第一个菜单。但是在测试中,按键1,功能都不一样。如果菜单连这个也要管,相同动作功能太多,无法进行统一抽象,就很难模块化。

出发点不一样 上面说到的菜单,出发点都是如何设计一个好的菜单数据结构,让程序快速,高效运行。我想要的却是一个容易维护的菜单结构,至于菜单的代码有多乱多纠结,没关系, 而且,几百上千个菜单,就算用轮询的方法,也不过几百us吧,没关系。

3、改进菜单

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


1/** 2*@brief菜单对象 3*/ 4typedefstruct_strMenu 5{ 6MenuLell;///<菜单等级 7    char cha[MENU_LANG_BUF_SIZE];   ///中文 8    char eng[MENU_LANG_BUF_SIZE];   ///英文 9    MenuType type;  ///菜单类型 10    s32 (*fun)(void);  ///测试函数 11 12} MENU;

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


1constMENUEMenuListTest[]= 2{ 3MENU_L_0,//菜单等级 4"测试程序",//中文 5"test",//英文 6MENU_TYPE_LIST,//菜单类型 7NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 8 9MENU_L_1,//菜单等级 10"LCD",//中文 11"LCD",//英文 12MENU_TYPE_LIST,//菜单类型 13NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 14MENU_L_2,//菜单等级 15"VSPIOLED",//中文 16"VSPIOLED",//英文 17MENU_TYPE_FUN,//菜单类型 18test_oled,//菜单函数,功能菜单才会执行,有子菜单的不会执行 19 20MENU_L_2,//菜单等级 21"I2COLED",//中文 22"I2COLED",//英文 23MENU_TYPE_FUN,//菜单类型 24test_i2coled,//菜单函数,功能菜单才会执行,有子菜单的不会执行 25 26 27MENU_L_1,//菜单等级 28"声音",//中文 29"sound",//英文 30MENU_TYPE_LIST,//菜单类型 31NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 32MENU_L_2,//菜单等级 33"蜂鸣器",//中文 34"buzzer",//英文 35MENU_TYPE_FUN,//菜单类型 36test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行 37 38MENU_L_2,//菜单等级 39"DAC音乐",//中文 40"DACmusic",//英文 41MENU_TYPE_FUN,//菜单类型 42test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行 43 44MENU_L_2,//菜单等级 45"收音",//中文 46"FM",//英文 47MENU_TYPE_FUN,//菜单类型 48test_test,//菜单函数,功能菜单才会执行,有子菜单的不会执行 49 50 51MENU_L_1,//菜单等级 52"触摸屏",//中文 53"tp",//英文 54MENU_TYPE_LIST,//菜单类型 55NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 56 57MENU_L_2,//菜单等级 58"校准",//中文 59"calibrate",//英文 60MENU_TYPE_FUN,//菜单类型 61test_cal,//菜单函数,功能菜单才会执行,有子菜单的不会执行 62 63MENU_L_2,//菜单等级 64"测试",//中文 65"test",//英文 66MENU_TYPE_FUN,//菜单类型 67test_tp,//菜单函数,功能菜单才会执行,有子菜单的不会执行 68 69MENU_L_1,//菜单等级 70"按键",//中文 71"KEY",//英文 72MENU_TYPE_FUN,//菜单类型 73test_key,//菜单函数,功能菜单才会执行,有子菜单的不会执行 74 75/*最后的菜单是结束菜单,无意义*/ 76MENU_L_0,//菜单等级 77"END",//中文 78"END",//英文 79MENU_TYPE_NULL,//菜单类型 80NULL,//菜单函数,功能菜单才会执行,有子菜单的不会执行 81};

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


1----------------------------------------------- 2根节点 3第1个1级菜单 4第1个子菜单 5第2个子菜单 6第3个子菜单 7第2个1级菜单 8第1个子菜单 9第1个孙菜单 10第2个孙菜单 11第2个子菜单 12第3个子菜单 13第3个1级菜单 14第4个1级菜单 15第5个1级菜单 16结束节点 17------------------------------------------------

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

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

1emenu_run(WJQTestLcd,(MENU*)&WJQTestList[0],sizeof(WJQTestList)/sizeof(MENU),FONT_SONGTI_1616,2);

-第1个参数是在哪个LCD上显示菜单, -第2个是菜单列表, -第3个是菜单长度, -第4个四字体, -第5则是行间距

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

4、菜单实现效果

相关文件:emenu.c、emenu.h、emenu_test.c

当前代码:

1实现了双列菜单,用数字键选择进入下一层。每页最多显示8个菜单(4*4键盘用1-8键)

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

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

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

显示效果

128*64 OLED

6afa7d32-fe85-11ec-ba43-dac502259ad0.png

6b03b4b0-fe85-11ec-ba43-dac502259ad0.png

128*128 tft lcd

6b193ec0-fe85-11ec-ba43-dac502259ad0.png

6b2c43ee-fe85-11ec-ba43-dac502259ad0.png

320*240 tft lcd

6b473c1c-fe85-11ec-ba43-dac502259ad0.png

6b5e6f40-fe85-11ec-ba43-dac502259ad0.png

5、最后说明

以上菜单框架来源屋脊雀工作室,适合初学者练习。我看下这个菜单框架,其实还有很多改进地方。

我当初大学电子设计竞赛用到类似结构体方式,但我那菜单框架用到了二级指针,可以做到无限极扩展,而且可以指向(跳转)任意菜单,方便按键进入、返回等操作。

本文就分享到这里,感兴趣的读者可以自己写一个菜单框架。

原文标题:值得学习的单片机菜单框架(附源码)

文章出处:【微信公众号:硬件攻城狮】欢迎添加关注!文章转载请注明出处。

审核编辑:彭静

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6035

    文章

    44554

    浏览量

    634640
  • 硬件
    +关注

    关注

    11

    文章

    3312

    浏览量

    66200
  • 二叉树
    +关注

    关注

    0

    文章

    74

    浏览量

    12324
  • 菜单界面
    +关注

    关注

    0

    文章

    4

    浏览量

    8796
收藏 人收藏

    评论

    相关推荐

    计算机二叉树的问题

    各位大神,本人马上要考计算机级了,那个二叉树老是弄不明白,比如一个题目,一棵二叉树共有25个节点,其中五个叶子节点,则度为1的节点数为?
    发表于 09-04 09:45

    基于二叉树的时序电路测试序列设计

    为了实现时序电路状态验证和故障检测,需要事先设计一个输入测试序列。基于二叉树节点和树枝的特性,建立时序电路状态二叉树,按照电路二叉树节点(状态)与树枝(输入)的层次逻辑
    发表于 07-12 13:57 0次下载
    基于<b class='flag-5'>二叉树</b>的时序电路测试序列设计

    二叉树层次遍历算法的验证

    实现二叉树的层次遍历算法,并对用”A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建的二叉树进行测试。
    发表于 11-28 01:05 2096次阅读
    <b class='flag-5'>二叉树</b>层次遍历算法的验证

    二叉树,一种基础的数据结构类型

    然后我们再定义一棵深度也为 3 的二叉树,该二叉树的 n 个结点(n≤7),当从 1 到 n 的每个结点都与上图中的编号结点一一对应时,这二叉树就称为完全二叉树
    的头像 发表于 04-13 10:48 4347次阅读
    <b class='flag-5'>二叉树</b>,一种基础的数据结构类型

    详解电源二叉树到底是什么

    作为数据结构的基础,分很多种,像 AVL 、红黑二叉搜索....今天我想分享的是关于二叉树
    的头像 发表于 06-06 15:05 1w次阅读
    详解电源<b class='flag-5'>二叉树</b>到底是什么

    C语言二叉树代码免费下载

    本文档的主要内容详细介绍的是C语言二叉树代码免费下载。
    发表于 08-27 08:00 1次下载

    红黑(Red Black Tree)是一种自平衡的二叉搜索

    平衡(Balance):就是当结点数量固定时,左右子树的高度越接近,这棵二叉树越平衡(高度越低)。而最理想的平衡就是完全二叉树/满二叉树,高度最小的二叉树
    的头像 发表于 07-01 15:05 5700次阅读
    红黑<b class='flag-5'>树</b>(Red Black Tree)是一种自平衡的<b class='flag-5'>二叉</b>搜索<b class='flag-5'>树</b>

    二叉树操作的相关知识和代码详解

    是数据结构中的重中之重,尤其以各类二叉树为学习的难点。在面试环节中,二叉树也是必考的模块。本文主要讲二叉树操作的相关知识,梳理面试常考的内容。请大家跟随小编一起来复习吧。 本篇针对面
    的头像 发表于 12-12 11:04 2038次阅读
    <b class='flag-5'>二叉树</b>操作的相关知识和代码详解

    二叉树的前序遍历非递归实现

    我们之前说了二叉树基础及二叉的几种遍历方式及练习题,今天我们来看一下二叉树的前序遍历非递归实现。 前序遍历的顺序是, 对于中的某节点,先遍历该节点,然后再遍历其左子树,最后遍历其右子
    的头像 发表于 05-28 13:59 1952次阅读

    C语言数据结构:什么是二叉树

    完全二叉树:完全二叉树是效率很高的数据结构。对于深度为K,有n个节点的二叉树,当且仅当每一个节点都与深度为K的满二叉树中编号从1至n的节点一一对应时,称为完全
    的头像 发表于 04-21 16:20 2507次阅读

    怎么就能构造成二叉树呢?

    一直跟着公众号学算法的录友 应该知道,我在二叉树:构造二叉树登场!,已经讲过,只有 中序与后序 和 中序和前序 可以确定一颗唯一的二叉树。前序和后序是不能确定唯一的二叉树的。
    的头像 发表于 07-14 11:20 1578次阅读

    使用C语言代码实现平衡二叉树

    这篇博客主要总结平衡二叉树,所以,二叉排序树知识不会提及,但是会用到。
    的头像 发表于 09-21 11:00 1093次阅读

    二叉树的代码实现

    二叉树的主要操作有遍历,例如有先序遍历、中序遍历、后序遍历。在遍历之前,就是创建一棵二叉树,当然,还需要有删除二叉树的算法。
    的头像 发表于 01-18 10:41 1227次阅读
    <b class='flag-5'>二叉树</b>的代码实现

    C++构建并复制二叉树

    使用C++构建一个二叉树并复制、输出。
    的头像 发表于 01-10 15:17 1014次阅读
    C++构建并复制<b class='flag-5'>二叉树</b>

    C++自定义二叉树并输出二叉树图形

    使用C++构建一个二叉树并输出。
    的头像 发表于 01-10 16:29 1741次阅读
    C++自定义<b class='flag-5'>二叉树</b>并输出<b class='flag-5'>二叉树</b>图形