一个产品级MCU菜单框架设计

news2025/1/10 20:57:08

分享一个用单色屏做的菜单框架。代码托管在github:

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

1、概述

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

图片

2、菜单框架设计

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

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

void test_main(void)
{
    while(1)
    {
        get_key(&key);

        switch(key)
        {
            case 1:
                test_key();
                break;

            case 2:
                test_lcd();
                break;
                ....
        }
    }
}

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

作为一个天天看《编程之美》的码农,决定改变现状。搜索引擎找了很久,找到了两个参考:《基于二叉树的多层的液晶菜单界面设计》 《基于节点编号的通用树状菜单设计方法与实现.pdf》 按照他们的设计方法,鼓捣了一个版本,能用,挺好,但是也纠结。

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

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

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

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

3、改进菜单

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

/**
  * @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)维护系统,例如按键扫描。

4、菜单实现效果

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

当前代码:

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

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

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

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

5、显示效果

图片

128*64 OLED

图片

128*64 OLED

图片

128*128 tft lcd

图片

128*128 tft lcd

图片

320*240 tft lcd

图片

320*240 tft lcd

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/979040.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hadoop的分布式文件存储系统HDFS组件的使用

Hadoop的第一个核心组件&#xff1a;HDFS&#xff08;分布式文件存储系统&#xff09; 一、HDFS的组成1、NameNode2、DataNode3、SecondaryNameNode4、客户端&#xff1a;命令行/Java API 二、HDFS的基本使用1、命令行操作2、Java API操作 三、HDFS的工作流程问题&#xff08;H…

递归算法学习——N皇后问题,单词搜索

目录 ​编辑 一&#xff0c;N皇后问题 1.题意 2.解释 3.题目接口 4.解题思路及代码 二&#xff0c;单词搜索 1.题意 2.解释 3.题目接口 4.思路及代码 一&#xff0c;N皇后问题 1.题意 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上…

阿里云服务器怎么退款?云服务器退款流程图

阿里云服务器如何退款&#xff1f;云服务器在哪申请退款&#xff1f;在用户中心订单管理中的退订管理中退款&#xff0c;阿里云百科分享阿里云服务器退款流程&#xff0c;包括申请退款入口、云服务器退款限制条件、退款多久到账等详细说明&#xff1a; 目录 阿里云服务器退款…

I/O系统:I/O设备,I/O接口,I/O端口的编址,I/O指令、通道指令,I/O控制方式 ,补充:中断

I/O&#xff1a;Input / Output&#xff0c;即输入/输出。 I/O系统一般由I/O硬件&#xff08;I/O设备&#xff0c;I/O接口&#xff0c;I/O总线等&#xff09;和I/O软件&#xff08;驱动程序&#xff0c;用户程序&#xff0c;管理程序&#xff0c;升级补丁等&#xff09;构成。…

基于sd的模特换装

这个领域的核心就是怎么把商品展示出来&#xff0c;商品本身不能发生变化&#xff0c;细节不能乱&#xff0c;模特换装或者虚拟换装&#xff0c;核心不在人&#xff0c;而在于商品&#xff0c;阿里塔玑这种核心在于怎么把平面的2D商品转成一个3D商品图&#xff0c;怎么让模特把…

蒙特卡洛方法使用原理解系-单位圆的面积计算

简介 蒙特卡洛也成为统计模拟方法&#xff0c;提出以概率统计理论为指导的一类非常重要的数值计算方法&#xff0c;是指使用随机数&#xff08;或者更常见的伪随机数&#xff09;来解决很多计算问题的方法。蒙特卡罗方法的名字来源于摩纳哥的一个城市蒙特卡罗&#xff0c;该城…

IIO驱动 Industrial I/O(正点原子笔记)

最近看见很多iio 驱动adc&#xff0c;赶紧找来学习一下。 传感器内部都会有ADC&#xff0c;传感器对外提供 IIC或者 SPI 接口&#xff0c;SOC 可以通过 IIC 或者 SPI 接口来获取到传感器内部的 ADC 数值&#xff0c;从而得到想要测量的结果。Linux 内核为了管理这些日益增多的…

恒运资本:港股内房股拉升 融创中国、中国恒大涨超30%

截至发稿&#xff0c;融创我国、我国恒大涨超30%&#xff0c;把戏年控股、天誉置业涨超20%。 9月6日&#xff0c;港股内地房地产板块拉升&#xff0c;截至发稿&#xff0c;融创我国、我国恒大涨超30%&#xff0c;把戏年控股、天誉置业涨超20%&#xff0c;佳兆业集团、富力地产…

springboot实战(六)之mybatis-plus代码自动生成器【重要】

目录 环境&#xff1a; 步骤&#xff1a; 1.添加依赖 2.配置代码 3.运行 测试 1.测试生成的service 1.1、service用法 2.分页查询 2.1、分页插件配置 2.2、测试 3.源码 环境&#xff1a; jdk:1.8 springboot版本&#xff1a;2.7.15 mybatis-plus版本&#xff1…

单片机-蜂鸣器

简介 蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电 蜂鸣器主要分为 压电式蜂鸣器 和 电磁式蜂鸣器 两 种类型。 压电式蜂鸣器 主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。多谐振荡器由晶体管或集成电路构成&#xff0c;当接通电源后&…

Object —— Guide Deform

使用动画skin驱动引导线&#xff1b;&#xff1b;内嵌Guid Deform节点&#xff1b;

Django创建应用、ORM的进阶使用及模型类数据库迁移

1 Django项目创建第一个应用 Django 项目就是基于 Django 框架开发的 Web 应用&#xff0c;它包含了一组配置和多个应用&#xff0c;我们把应用称之为 App&#xff0c;在前文中对它也做了相应的介绍&#xff0c;比如 auth、admin&#xff0c;它们都属于 APP。 一个 App 就是一…

2023高教社杯国赛ABCDE题免费思路预定(MathClub网站汇聚市面的所有资源,注册即送)

目录 引言A题&#xff1a;[题目名称]概述参考思路参考资源 B题&#xff1a;[题目名称]概述参考思路参考资源 结论 作者&#xff1a;MathClub 日期&#xff1a;2023年9月6日 引言 2023年全国大学生数学建模竞赛&#xff08;高教社杯&#xff09;即将来临&#xff0c;对于众多数…

ChatGPT:深度学习和机器学习的知识桥梁(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

nodejs+vue+elementui精品课程网站设计

前端技术&#xff1a;nodejsvueelementui基于nodejs语言、vue.js框架、B/S架构、Mysql数据库设计并实现了精品课程网站设计。系统主要包括首页、个人中心、用户管理、课程信息管理、课程分类管理、学习论坛、在线试题管理、试题管理、系统管理、考试管理等功能模块。 本文首先介…

tf和pytorch每轮epoch显示输出的auc是如何计算的

tf和pytorch每轮epoch显示输出的auc是如何计算的&#xff1f; tf的计算 近似 ROC 或 PR 曲线的 AUC&#xff08;曲线下面积&#xff09;。 tf1 通过计算真阳性&#xff0c;假阳性&#xff0c;假阴性&#xff0c;真阴性值的计算策略。 tensorflow AUC & streaming_auc_我…

浅谈Spring

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器&#xff08;框架&#xff09;。 一、什么是IOC&#xff1f; IoC Inversion of Control 翻译成中⽂是“控制反转”的意思&#xff0c;也就是说 Spring 是⼀个“控制反转”的容器。 1.1控制反转推导 这个控制反转怎…

PHP教学质量评估系统Dreamweaver开发mysql数据库web结构php编程计算机网页代码

一、源码特点 PHP教学质量评估系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 代码 https://download.csdn.net/download/qq_41221322/88301983 论文 https://down…

【简单几何】CF Edu11 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 和蓝桥杯国赛有道题类似&#xff0c;都是用中点来确定图形防止精度缺失 应该算是典 Code&#xff1a; #include <bits/stdc.h>using i64 long long;constexpr int N 2e3 10; constexpr int M 1e6 1…

stm32(GD32,apm32),开优化后需要特别注意的地方

提到优化就不得不提及 volatile 使用场景 1&#xff1a;中断服务程序中修改的供其它程序检测的变量&#xff0c;需要加volatile&#xff1b; : 2&#xff1a;多任务环境下各任务间共享的标志&#xff0c;应该加volatile&#xff1b; 3&#xff1a;并行设备的硬件寄存器&#x…