分享一个简单的基于C语言嵌入式GUI界面切换代码

目录

前言

一、数据类型

二、页面调度

三、页面显示

四、视频展示


前言

        最近在用LVGL写一个简单的UI界面,需要进行几个页面的切换,所以就自己写了一个简单页面切换代码,方便进行页面切换,同时使UI代码结构更加清晰。这个结构主要用于嵌入式MCU上使用,所以结构比较简单。

一、数据类型

typedef struct ui_show_t
{
    struct ui_show_t *last;
    uint32_t  *ui;
}ui_show_t;

这个页面切换代码会用到一个类似链表的结构,每个界面都会定义一个这样的数据数据结构,用来保存上一个页面的指针。如下图所示:

这样每切换到下一页面的时候都可以根据需要来切换到上一页面。

同时我定义了页面的函数类型:

typedef struct ui_show_t * (*ui_show_fun)(ui_show_t* ui_show,ui_opera_t ui_opera)

除了上面提到ui_show_t类型,还有一个ui_opera_t,这个类型定义了页面的操作设备,例如触摸屏、实体按键、旋转按钮等等,我的设备是旋转按钮,所以就定义了如下的类型:

typedef struct 
{
    int8_t      dir_cnt;    //旋转方向计数
    btn_sta_t   btn_sta;    //按键状态
}ui_opera_t;

这样就可以操作我的屏幕进行页面切换了。


二、页面调度

        对于页面的调用是单独创建了一个任务,在这个任务的循环里面获取旋转按钮的状态以及进行页面的显示。可以看到最终显示的是 my_show_ui->ui  这个页面,这个页面在初始化的时候被赋值了ln_lvgl_mainwindow这个函数指针,这个函数就是用来显示主页面的函数。

#include "ln_lvgl_ui.h"
lv_ui guider_ui;

static ui_show_t my_start_ui;
static ui_show_t *my_show_ui = NULL;
ui_opera_t my_ui_opera;

static OS_Thread_t g_lvgl_ui_thread;
#define LVGL_UI_TASK_STACK_SIZE   4*40*256 //Byte

void ui_show_scheduler(void *params);
ui_show_t* ln_lvgl_mainwindow(ui_show_t* ui_show,ui_opera_t ui_opera);
ui_show_t* ln_lvgl_lightwindow(ui_show_t* ui_show,ui_opera_t ui_opera);

int ln_lvgl_ui_init()
{
    ln_drv_rotate_btn_init();    //旋转按钮初始化
    lv_init();                   //LVGL初始化
    lv_port_disp_init();         //显示设备初始化
    setup_ui(&guider_ui);        //第一个页面初始化
    //创建页面显示调度任务
    if(OS_OK != OS_ThreadCreate(&g_lvgl_ui_thread, "LVGL Task", ui_show_scheduler, NULL, OS_PRIORITY_BELOW_NORMAL, LVGL_UI_TASK_STACK_SIZE)) {
        return HAL_ERROR;
    }
    return HAL_OK;
}

void ui_show_scheduler(void *params)
{
    //对第一个页面的链表进行数据初始化
    my_start_ui.last = NULL;
    my_start_ui.ui = (uint32_t*)ln_lvgl_mainwindow;
    my_show_ui = &my_start_ui;
    while(1)
    {
        //获取旋转按钮的旋转方向计数以及按键状态
        my_ui_opera.dir_cnt = ln_drv_rotate_btn_get_dir();
        my_ui_opera.btn_sta = (btn_sta_t)ln_drv_rotate_btn_get_press();
        if(my_ui_opera.dir_cnt != 0){
            LOG(LOG_LVL_ERROR, "cnt :%d \r\n", my_ui_opera.dir_cnt);
        }

        //显示对应UI
        my_show_ui = (ui_show_t*)(*((ui_show_fun)(my_show_ui->ui)))((ui_show_t*)my_show_ui,my_ui_opera);

        //LVGL函数
        lv_timer_handler();
        
        //延时1ms
        OS_MsDelay(1);
    }
}

三、页面显示

#include "ln_lvgl_mainwindow.h"

//在这里定义了一个这个页面的链表方便存储上一个页面的指针
static ui_show_t my_mainwindow_ui;

ui_show_t* ln_lvgl_mainwindow(ui_show_t* ui_show,ui_opera_t ui_opera)
{
    static uint8_t show_flag    = 0;
    static int8_t cur_show_item = 0;
    static int8_t last_show_item = -1;
    if(show_flag == 0){
        //显示页面,只需要显示一次就可以
        show_flag = 1;
    }
    
    //根据旋转编码器不同的值,来执行不同的操作
    cur_show_item += 0 - ui_opera.dir_cnt;
    if(cur_show_item != last_show_item){
        switch(cur_show_item){
            case 0:{
                break;
            }
            case 1:{
                break;
            }
        }
    }
    last_show_item = cur_show_item;

    //按键长按和短按也都可以执行不同的操作,例如长按返回上一个页面,短按进入下一页面
    if(ui_opera.btn_sta == SHORT_PRESS){
        //短按进入下一个页面,下一个页面自行定义,直接赋值就好
        switch(cur_show_item){
            case 0:{
                    my_mainwindow_ui.last = ui_show;
                    my_mainwindow_ui.ui = (uint32_t*)ln_lvgl_lightwindow;//例如此处显示灯光页面
                    ui_show = &my_mainwindow_ui;
                    show_flag = 0;
                    break;
                }
             case 3:{
                    my_mainwindow_ui.last = ui_show;
                    my_mainwindow_ui.ui = (uint32_t*)ln_lvgl_timewindow;//例如此处显示时间页面
                    ui_show = &my_mainwindow_ui;
                    show_flag = 0;
                    break;
                }
        }
    }
    if(ui_opera.btn_sta == LONG_PRESS){
        //长按进入上一个页面(如果有的话)
        if(ui_show->last != NULL){
            //直接赋值
            ui_show = ui_show->last;
        }
    }
    //返回赋值后的指针地址
    return ui_show;
}

四、视频展示

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用注解实现接口的幂等性校验

如何使用注解实现接口的幂等性校验 背景什么是幂等性为什么要实现幂等性校验如何实现接口的幂等性校验1. 数据库唯一主键2. 数据库乐观锁3. 防重 Token 令牌4. redis 如何将这几种方式都组装到一起结语 背景 最近在小组同学卷的受不了的情况下,我决定换一个方向卷去…

人工智能轨道交通行业周刊-第67期(2023.11.27-12.3)

本期关键词:列车巡检机器人、城轨智慧管控、制动梁、断路器、AICC大会、Qwen-72B 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro…

使用Prometheus监控Padavan路由器

Prometheus监控Padavan路由器 1、背景 近期在Synology(群辉)中安装一套Prometheus监控程序,目前已经监控Synology,然后家中有有路由器(Padavan)型号,也准备使用PrometheusGrafan进行监控。 ‍…

Java基本数据类型详解

✨个人主页:全栈程序猿的CSDN博客 💨系列专栏:Java从入门到精通 ✌座右铭:编码如诗,Bug似流星,持续追求优雅的代码,解决问题如同星辰般自如 Java是一种强类型语言,数据类型在程序中起…

如何成为一名高效的前端开发者(10X开发者)

如今,每个人都想成为我们所说的“10倍开发者”。然而,这个术语经常被误解和高估。 本质上,一个高效或者10倍开发者,在我看来,是指那些能够充分利用所有可用工具的人,通过让这些工具处理冗余和重复的任务&am…

Java线程池的使用和最佳实践

第1章:引言 处理并发问题时,如果每次都新建线程,那系统的压力得有多大?这时候,线程池就像一个英雄一样出现了,它帮我们有效地管理线程,提高资源利用率,降低开销。那么,为…

iOS 自动签名打包,并用脚本上传appstore

背景: 1)测试环境给测试,产品,或者其他业务人员打测试包时,经常存在需要添加设备,不得不重新生成描述文件,手动去更新打包机描述文件配置 2)证书,描述文件过期造成打包失…

Lag-Llama:基于 LlaMa 的单变量时序预测基础模型

文章构建了一个通用单变量概率时间预测模型 Lag-Llama,在来自Monash Time Series库中的大量时序数据上进行了训练,并表现出良好的零样本预测能力。在介绍Lag-Llama之前,这里简单说明什么是概率时间预测模型。概率预测问题是指基于历史窗口内的…

目标检测算法改进系列之添加变核卷积AKConv模块

AKConv变核卷积 KConv的主要思想:AKConv(可变核卷积)主要提供一种灵活的卷积机制,允许卷积核具有任意数量的参数和采样形状。这种方法突破了传统卷积局限于固定局部窗口和固定采样形状的限制,从而使得卷积操作能够更加…

【栈和队列(2)】

文章目录 前言队列队列方法队列模拟实现循环队列练习1 队列实现栈 前言 队列和栈是相反的,栈是先进后出,队列是先进先出,相当于排队打饭,排第一的是最先打到饭出去的。 队列 队列:只允许在一端进行插入数据操作&…

Python练习题(二)

📑前言 本文主要是【Python】——Python练习题的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一句&am…

Pytest测试攻略:探寻pytest.main()隐藏的利器

更多资料获取 📚 个人网站:ipengtao.com 在Pytest测试框架中,pytest.main()是一个重要的功能,用于启动测试执行。它允许以不同方式运行测试,传递参数和配置选项。本文将深入探讨pytest.main()的核心功能,提…

栈和队列OJ题——15.循环队列

15.循环队列 622. 设计循环队列 - 力扣(LeetCode) * 解题思路: 通过一个定长数组实现循环队列 入队:首先要判断队列是否已满,再进行入队的操作,入队操作需要考虑索引循环的问题,当索引越界&…

Qt/QML编程学习之心得:如何添加资源文件到QML工程(十一)

Qt作为一种GUI界面编辑工具,在嵌入式编程中也大受欢迎,而进一步QML出现了,QML我理解也是一种资源文件,因为像其他资源文件一样添加进工程的。那么一个图片如何增加进资源文件呢?这个的确很基础,就是把资源文…

IdleStateHandler 心跳机制源码详解

优质博文:IT-BLOG-CN 一、心跳机制 Netty支持心跳机制,可以检测远程服务端是否存活或者活跃。心跳是在TCP长连接中,客户端和服务端定时向对方发送数据包通知对方自己还在线,保证连接的有效性的一种机制。在服务器和客户端之间一…

C++实现DFS、BFS、Kruskal算法和Prim算法、拓扑排序、Dijkstra算法

背景: 实现要求: 根据图的抽象数据类型的定义,请采用邻接矩阵来存储图1,采用邻接表来存储图2,并完成如下操作:对图1无向图进行深度优先遍历和广度优先遍历。对图1无向图采用Kruskal算法和Prim算法得出最小…

<蓝桥杯软件赛>零基础备赛20周--第8周第2讲--排序的应用

报名明年4月蓝桥杯软件赛的同学们,如果你是大一零基础,目前懵懂中,不知该怎么办,可以看看本博客系列:备赛20周合集 20周的完整安排请点击:20周计划 每周发1个博客,共20周(读者可以按…

c语言-归并排序

目录 1、归并排序基本思想 2、归并排序的实现(递归法) 2.1 代码实现递归法归并排序 3、归并排序的实现(非递归法) 3.1 修正边界问题 3.2 代码实现非递归法归并排序 结语: 前言: 归并排序是一种把数…

万界星空科技灯具行业MES介绍

中国是LED照明产品最大的生产制造国,如今,我国初步形成了包括LED外延片的生产、LED芯片的制备、LED芯片的封装以及LED产品应用在内的较为完超为产业链,随着LED照明市场渗诱率的快速警升,LED下游应用市场将会越来越广阔。这也将推动…

硬件基础:二极管

基本定义 二极管的内部其实就是一个PN结。 把PN结封装起来,两边加上两个电极,就组成了半导体二极管。简称二极管(Diode) 二极管和PN结一样,具有单向导通性: 外观和正负极 常见芯片封装如下: 一般…
最新文章