芯课堂 | LVG免费开源GUI图形库

图片

概述

本文介绍目前LVGL的应用小知识,希望对采用MCU设计UI界面的用户有所启发,开发出界面更友好的消费品或者工业产品,造福大众。

01.LVGL系统架构

LVGL系统框架

应用程序创建GUI并处理特定任务的应用程序。

LVGL本身是一个图形库。我们的应用程序通过调用LVGL库来创建GUI。它包含一个HAL(硬件抽象层)接口,用于注册显示和输入设备驱动程序。

驱动程序除特定的驱动程序外,它还有其他的功能,可驱动显示器到GPU (可选)、读取触摸板或按钮的输入。

根据MCU,有两种典型的硬件设置。一个带有内置LCD/TFT驱动器的外围设备,而另一种是没有内置LCD/TFT驱动器的外围设备。在这两种情况下,都需要一个帧缓冲区来存储屏幕的当前图像。

1.集成了TFT/LCD驱动器的MCU如果MCU集成了TFT/LCD驱动器外围设备,则可以直接通过RGB接口连接显示器。在这种情况下,帧缓冲区可以位于内部RAM(如果MCU有足够的RAM)中,也可以位于外部RAM(如果MCU具有存储器接口)中。

2.如果MCU没有集成TFT/LCD驱动程序接口,则必须使用外部显示控制器(例如SSD1963、SSD1306、ILI9341 )。在这种情况下,MCU可以通过并行端口,SPI或通过I2C与显示控制器进行通信。帧缓冲区通常位于显示控制器中,从而为MCU节省了大量RAM。

02.建立一个LVGL项目

要在我们的项目中使用 lvgl ,我们起码需要获取到官方的这两个库:

lvgl(lvgl)核心图形库的官方 GitHub 仓库地址:https://github.com/lvgl/lvgl。

lvgl(lv_drivers)输入输出设备驱动官方 GitHub 仓库地址:https://github.com/lvgl/lv_drivers

我们可以克隆或下载这两个库的最新版本,将它们复制到我们的项目中,然后进行适配。

目录 lvgl 就是 lvgl 的官方图形库

目录 lv_drivers 是 lvgl 输入输出设备驱动官方示例配置

目录 lv_examples 是 lvgl 的官方demo(可选,但不要直接使用到实际项目中)

图片

配置文件

上面的三个库中有一个类似名为 lv_conf_template.h 的配置头文件(template就是模板的意思)。通过它可以设置库的基本行为,裁剪不需要模块和功能,在编译时调整内存缓冲区的大小等等。

  1. 将 lvgl/lv_conf_template.h 复制到 lvgl 同级目录下,并将其重命名为 lv_drv_conf.h 。打开文件并将开头的 #if 0 更改为 #if 1 以使能其内容。

  2. 将 lv_drivers/lv_drv_conf_template.h 复制到 lv_drivers 同级目录下,并将其重命名为 lv_conf.h 。打开文件并将开头的 #if 0 更改为 #if 1 以使能其内容。

  3. (可选)将 lv_examples/lv_ex_conf_template.h 复制到 lv_examples 同级目录下,并将其重命名为 lv_ex_conf.h 。打开文件并将开头的 #if 0 更改为 #if 1 以使能其内容。

图片

准备lvgl配置文件

图片

使能配置文件

lv_conf.h 也可以复制到其他位置,但是应该在编译器选项中添加 ``LV_CONF_INCLUDE_SIMPLE``定义(例如,对于gcc编译器为``-DLV_CONF_INCLUDE_SIMPLE`` ) 并手动设置包含路径。

在配置文件中,注释说明了各个选项的含义。我们在移植时至少要检查以下三个配置选项,其他配置根据具体的需要进行修改:

  • LV_HOR_RES_MAX 显示器的水平分辨率。

  • LV_VER_RES_MAX 显示器的垂直分辨率。

  • LV_COLOR_DEPTH 颜色深度,其可以是:

8 - RG332

16 - RGB565

32 - (RGB888和ARGB8888)

初始化LVGL

准备好这三个库:lvgl、lv_drivers、lv_examples 后,我们就要开始使用lvgl带给我们的功能了。使用 lvgl 图形库之前,我们还必须初始化 lvlg 以及相关其他组件。初始化的顺序为:

  1. 调用 lv_init() 初始化 lvgl 库;

  2. 初始化驱动程序;

  3. 在 LVGL 中注册显示和输入设备驱动程序;

  4. 在中断中每隔 x毫秒 调用 lv_tick_inc(x) 用以告知 lvgl 经过的时间;

  5. 每隔 x毫秒 定期调用 lv_task_handler() 用以处理与 LVGL相关的任务。

03.显示接口

要设置显示,必须初始化 lv_disp_buf_t 和 lv_disp_drv_t 变量。

  • lv_disp_buf_t 保存显示缓冲区信息的结构体

  • lv_disp_drv_t HAL要注册的显示驱动程序、与显示交互并处理与图形相关的结构体、回调函数。

显示缓存区

关于缓冲区大小,有 3 种情况:

一个缓冲区 LVGL将屏幕的内保存到缓冲区中并将其发送到显示器。缓冲区可以小于屏幕。在这种情况下,较大的区域将被重画成多个部分。如果只有很小的区域发生变化(例如按下按钮),则只会刷新该部分的区域。

两个非屏幕大小的缓冲区 具有两个缓冲区的 LVGL 可以将其中一个作为显示缓冲区,而另一缓冲区的内容发送到后台显示。应该使用 DMA 或其他硬件将数据传输到显示器,以让CPU同时绘图。这样,渲染和刷新并行处理。与 一个缓冲区 的情况类似,如果缓冲区小于要刷新的区域,LVGL将按块绘制显示内容

两个屏幕大小的缓冲区 与两个非屏幕大小的缓冲区相反,LVGL将始终提供整个屏幕的内容,而不仅仅是块。这样,驱动程序可以简单地将帧缓冲区的地址更改为从 LVGL 接收的缓冲区。因此,当MCU具有 LCD/TFT 接口且帧缓冲区只是 RAM 中的一个位置时,这种方法的效果很好。

显示驱动器

一旦缓冲区初始化准备就绪,就需要初始化显示驱动程序。在最简单的情况下,仅需要设置 lv_disp_drv_t 的以下两个字段:

buffer 指向已初始化的 lv_disp_buf_t 变量的指针。

flush_cb 回调函数,用于将缓冲区的内容复制到显示的特定区域。刷新准备就绪后,需要调用lv_disp_flush_ready()。LVGL可能会以多个块呈现屏幕,因此多次调用flush_cb。使用 lv_disp_flush_is_last() 可以查看哪块是最后渲染的。

其中,有一些可选的数据字段:

hor_res 显示器的水平分辨率。(默认为 lv_conf.h 中的 LV_HOR_RES_MAX )

ver_res 显示器的垂直分辨率。(默认为 lv_conf.h 中的 LV_VER_RES_MAX )

color_chroma_key 在 chrome 键控图像上将被绘制为透明的颜色。(默认为 lv_conf.h 中的 LV_COLOR_TRANSP )

user_data 驱动程序的自定义用户数据。可以在 lv_conf.h 中修改其类型。

anti-aliasing 使用抗锯齿(anti-aliasing)(边缘平滑)。缺省情况下默认为 lv_conf.h 中的 LV_ANTIALIAS 。

rotated 如果 1 交换 hor_res 和 ver_res 。两种情况下 LVGL 的绘制方向相同(从上到下的线条),因此还需要重新配置驱动程序以更改显示器的填充方向。

screen_transp 如果为 1 ,则屏幕可以具有透明或不透明的样式。需要在      lv_conf.h 中启用 LV_COLOR_SCREEN_TRANSP 。

要使用GPU,可以使用以下回调:

gpu_fill_cb 用颜色填充内存中的区域。

gpu_blend_cb 使用不透明度混合两个内存缓冲区。

gpu_wait_cb 如果在 GPU 仍在运行 LVGL 的情况下返回了任何 GPU 函数,则在需要确保GPU渲染就绪时将使用此函数。

注意,这些功能需要绘制到内存(RAM)中,而不是直接显示在屏幕上。

其他一些可选的回调,使单色、灰度或其他非标准RGB显示一起使用时更轻松、优化:

rounder_cb 四舍五入要重绘的区域的坐标。例如。2x2像素可以转换为2x8。如果显示控制器只能刷新特定高度或宽度的区域(对于单色显示器,通常为8 px高),则可以使用它。

set_px_cb 编写显示缓冲区的自定义函数。如果显示器具有特殊的颜色格式,则可用于更紧凑地存储像素。(例如1位单色,2位灰度等)。这样,lv_disp_buf_t中使用的缓冲区可以较小,以仅保留给定区域大小所需的位数。set_px_cb不能与两个屏幕大小的缓冲区一起显示缓冲区配置。

monitor_cb 回调函数告诉在多少时间内刷新了多少像素。

clean_dcache_cb 清除与显示相关的所有缓存的回调

要设置 lv_disp_drv_t 变量的字段,需要使用 lv_disp_drv_init(&disp_drv) 进行初始化。最后,要为 LVGL 注册显示设备,需要调用lv_disp_drv_register(&disp_drv)。

04.输入设备接口

(一)、输入设备的类型

要设置输入设备,必须初始化 lv_indev_drv_t 变量:

图片

类型 (indev_drv.type)可以是:

  1. LV_INDEV_TYPE_POINTER 触摸板或鼠标

  2. LV_INDEV_TYPE_KEYPAD 键盘或小键盘

  3. LV_INDEV_TYPE_ENCODER 带有左,右,推动选项的编码器

  4. LV_INDEV_TYPE_BUTTON 外部按钮按下屏幕

read_cb (indev_drv.read_cb)是一个函数指针,将定期调用该函数指针以报告输入设备的当前状态。它还可以缓冲数据并在没有更多数据要读取时返回 false ,或者在缓冲区不为空时返回 true 。

进一步了解有关 输入设备 的更多信息。

(二)、触摸板,鼠标或任何指针

可以单击屏幕点的输入设备属于此类别。

即使状态为 LV_INDEV_STATE_REL ,触摸板驱动程序也必须返回最后的 X/Y 坐标。

要设置鼠标光标,请使用 lv_indev_set_cursor(my_indev,&img_cursor) 。( my_indev 是 lv_indev_drv_register 的返回值)键盘或键盘

(三)、触摸板或键盘

带有所有字母的完整键盘或带有一些导航按钮的简单键盘均属于此处。

要使用键盘/触摸板:

  • 注册具有 LV_INDEV_TYPE_KEYPAD 类型的 read_cb 函数。

  • 在 lv_conf.h 中启用 LV_USE_GROUP

  • 必须创建一个对象组:lv_group_t * g = lv_group_create(),并且必须使用 lv_group_add_obj(g,obj) 向其中添加对象

  • 必须将创建的组分配给输入设备:lv_indev_set_group(my_indev,g)(      my_indev 是 lv_indev_drv_register 的返回值)

  • 使用 LV_KEY _… 在组中的对象之间导航。有关可用的密钥,请参见      lv_core/lv_group.h。

(四)、编码器

可以通过下面四种方式使用编码器:

  1. 按下按钮

  2. 长按其按钮

  3. 转左

  4. 右转

简而言之,编码器输入设备的工作方式如下:

  • 通过旋转编码器,可以专注于下一个/上一个对象。

  • 在简单对象(如按钮)上按下编码器时,将单击它。

  • 如果将编码器按在复杂的对象(如列表,消息框等)上,则该对象将进入编辑模式,从而转动编码器即可在对象内部导航。

  • 长按按钮,退出编辑模式。

要使用编码器(类似于键盘),应将对象添加到组中。

(五)、使用带有编码器逻辑的按钮

除了标准的编码器行为外,您还可以利用其逻辑来使用按钮导航(聚焦)和编辑小部件。如果只有几个按钮可用,或者除编码器滚轮外还想使用其他按钮,这将特别方便。

需要有3个可用的按钮:

LV_KEY_ENTER 将模拟按下或推动编码器按钮

LV_KEY_LEFT 将向左模拟转向编码器

LV_KEY_RIGHT 将正确模拟转向编码器

其他键将传递给焦点小部件

如果按住这些键,它将模拟indev_drv.long_press_rep_time中指定的时间段内的编码器单击。

(六)、按键

按钮是指屏幕旁边的外部“硬件”按钮,它们被分配给屏幕的特定坐标。如果按下按钮,它将模拟在指定坐标上的按下。(类似于触摸板)

使用 lv_indev_set_button_points(my_indev, points_array) 将按钮分配给坐标。points_array应该看起来像const lv_point_t points_array [] = {{12,30},{60,90},…}

points_array不能超出范围。将其声明为全局变量或函数内部的静态变量。

(七)、其它功能

除了 read_cb 之外,还可以在 lv_indev_drv_t 中指定 feedback_cb 回调。输入设备发送任何类型的事件时,都会调用feedback_cb。(独立于其类型)。它允许为用户提供反馈,例如在LV_EVENT_CLICK上播放声音。

可以在lv_conf.h中设置以下参数的默认值,但可以在lv_indev_drv_t中覆盖默认值:

  • 拖拽限制(drag_limit) 实际拖动对象之前要滑动的像素数 drag_throw 拖曳速度降低[%]。更高的价值意味着更快的减速

  • (drag_throw) 拖曳速度降低[%]。更高的价值意味着更快的减速

  • (long_press_time) 按下时间发送 LV_EVENT_LONG_PRESSED (以毫秒为单位)

  • (long_press_rep_time) 发送 LV_EVENT_LONG_PRESSED_REPEAT 的时间间隔(以毫秒为单位)

  • (read_task) 指向读取输入设备的lv_task的指针。可以通过 lv_task_...() 函数更改其参数

每个输入设备都与一个显示器关联。默认情况下,新的输入设备将添加到最后创建的或显式选择的显示设备(使用lv_disp_set_default())。相关的显示已存储,并且可以在驱动程序的显示字段中更改。

(八)、心跳

LVGL 需要系统滴答声才能知道动画和其他任务的经过时间。

为此我们需要定期调用 lv_tick_inc(tick_period) 函数,并以毫秒为单位告知调用周期。例如, lv_tick_inc(1) 用于每毫秒调用一次。

为了精确地知道经过的毫秒数,lv_tick_inc 应该在比 lv_task_handler() 更高优先级的例程中被调用(例如在中断中),即使 lv_task_handler 的执行花费较长时间。

(九)、任务处理器(Task Handler)

要处理 LVGL 的任务,我们需要定期通过以下方式之一调用 lv_task_handler() :

  • mian 函数中设置 while(1) 调用

  • 定期定时中断(低优先级然后是 lv_tick_inc()) 中调用

  • 定期执行的 OS 任务中调用

计时并不严格,但应保持大约5毫秒以保持系统响应。

05.日志记录

LVGL 内置有日志模块,用于记录用户库中正在发生的事情。

(一)、日志级别

要启用日志记录,需要在 lv_conf.h 中将 LV_USE_LOG 设置为 1 ,并将 LV_LOG_LEVEL 设置为以下值之一:

  • LV_LOG_LEVEL_TRACE 记录所有信息

  • LV_LOG_LEVEL_INFO 记录重要事件

  • LV_LOG_LEVEL_WARN 记录是否发生了警告事件

  • LV_LOG_LEVEL_ERROR 记录错误信息,当系统可能发生故障时或致命错误

  • LV_LOG_LEVEL_NONE 不要记录任何东西

级别高于设置的日志级别的事件也将被记录。例如。如果使用 LV_LOG_LEVEL_WARN ,也会记录错误。

(二)、使用printf记录

如果您的系统支持printf,则只需在 lv_conf.h 中启用 **LV_LOG_PRINTF **即可发送带有 printf 的日志。

(三)、自定义日志功能

如果不能使用 printf 或想要使用自定义函数进行日志记录,可以使用 lv_log_register_print_cb() 注册 “logger” 回调。

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

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

相关文章

Python Selenium如何下载网页中的图片到本地?(Base64编码的图片下载)

前言: 在网页上,图片有时会以Base64编码的形式嵌入在HTML中,而不是作为单独的文件提供。这种方式的优点是可以减少HTTP请求的数量,因为图片数据直接包含在HTML中,不需要额外的请求来获取图片文件。这对于小图片…

【TC3xx芯片】TC3xx芯片的GTM模块详解

目录 前言 正文 1.GTM模块功能概述 1.1 GTM具体功能 1.2 GTM架构 2. GTM模块输入时钟 2.1.fGTM的值怎么计算 3. CMU 3.1 CMU功能 3.2 CMU时钟的计算 3..2.1 CLS0_CLK怎么计算 3.2.1 GTM Global Clock时钟计算 3.2.2 分频时钟的计算 4. CCM 4.1 CCM功能 4.2 CCM…

SpringMVC-视图

SpringMVC中的视图实现了View接口,作用是渲染数据,将Model中的数据展示给用户。render是渲染方法,可以看到渲染的视图是一个View类型的对象。 SpringMVC视图的种类有很多,默认有转发视图和重定向视图。 如果配置了Thymeleaf视图解…

使用Docker方式安装Artifactory

1、安装前环境准备 首先要关闭防火墙,关闭Selinux,准备好安装好的docker。以下安装版本:7.19.10 ##关闭防火墙,并设置开机自关闭 systemctl stop firewalld.service systemctl disable firewalld.service ##查看防火墙状态 sy…

SpringCloud Alibaba之Nacos配置中心配置详解

目录 Nacos配置中心数据模型Nacos配置文件加载Nacos配置 Nacos配置中心数据模型 Nacos 数据模型 Key 由三元组唯一确定,三元组分别是Namespace、Group、DataId,Namespace默认是公共命名空间(public),分组默认是 DEFAUL…

『年度总结』逐梦编程之始:我的2023学习回顾与展望

目录 前言 我与Python 我与C语言 第一篇正式博客: 第二篇正式博客(扫雷): 指针学习笔记: C语言学习笔记: 我与数据结构: yuan 这篇博客,我将回顾2023年编程之旅的起点,同时展…

Flowable中6种部署方式

1. addClasspathResource src/main/resources/processes/LeaveProcess.bpmn20.xml Deployment deploy repositoryService.createDeployment().name("请假审批").addClasspathResource("processes/LeaveProcess.bpmn20.xml").deploy();2. addInputStream…

pandas.DataFrame() 数据自动写入Excel

DataFrame 表格数据格式 ; to_excel 写入Excel数据; read_excel 阅读 Excel数据函数 import pandas as pd#df2 pd.DataFrame({neme: [zhangsan, lisi, 3]}) df1 pd.DataFrame({One: [1, 2, 3],name: [zhangsan, lisi, 3]})#One是列明,123是…

分类预测 | Matlab实现RP-CNN-LSTM-Attention递归图优化卷积长短期记忆神经网络注意力机制的数据分类预测【24年新算法】

分类预测 | Matlab实现RP-CNN-LSTM-Attention递归图优化卷积长短期记忆神经网络注意力机制的数据分类预测【24年新算法】 目录 分类预测 | Matlab实现RP-CNN-LSTM-Attention递归图优化卷积长短期记忆神经网络注意力机制的数据分类预测【24年新算法】分类效果基本描述模型描述程…

计算机基础面试题 |09.精选计算机基础面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

面试算法89:房屋偷盗

题目 输入一个数组表示某条街道上的一排房屋内财产的数量。如果这条街道上相邻的两幢房屋被盗就会自动触发报警系统。请计算小偷在这条街道上最多能偷取到多少财产。例如,街道上5幢房屋内的财产用数组[2,3,4,5,3]表示…

http 503 错误

503错误是一种HTTP状态码,表示你请求的网站或服务暂时不可用,通常是因为服务器过载或维护,你可能会看到类似这样的提示:503 Service Unavailable、503 Service Temporarily Unavailable、HTTP Server Error 503、HTTP Error 503 I…

论文管理器

论文管理器 这个论文管理器仍然存在许多漏洞。目前,通过按照一些例行程序操作,它可以正常工作。我将在有时间的时候改进代码,提供详细说明,并添加新功能。当该管理器的代码进行优化后,我会上传到github上。 一个建立…

YACS(上海计算机学会竞赛平台)2023年12月月赛——移动复位

移动复位 内存限制: 256 Mb时间限制: 1000 ms 题目描述 二维平面上有一个点。该点最初所在的位置称之为起点。接下来,该点接受了一串命令,每个命令可以用一个大写字母表示: R 表示该点沿 X 轴坐标正方向移动了一个单位;L 表示…

Java商城 免 费 搭 建:鸿鹄云商实现多种商业模式,VR全景到SAAS,应有尽有

鸿鹄云商 b2b2c产品概述 【b2b2c平台】,以传统电商行业为基石,鸿鹄云商支持“商家入驻平台自营”多运营模式,积极打造“全新市场,全新 模式”企业级b2b2c电商平台,致力干助力各行/互联网创业腾飞并获取更多的收益。从消…

pod进阶:探针和容器钩子

探针* 容器钩子: poststart prestop pod的生命周期开始 Q:docker和k8s的重启策略对比 A: k8s的pod重启策略: Always:正常退出和非正常退出都重启(deployment的yaml文件只能是Always。pod的yaml文件三…

【模拟量采集1.2】电阻信号采集

【模拟量采集1.2】电阻信号采集 1 怎么测?2 测输入电阻电压即转为测模拟电压值,这里需要考虑选用怎样的辅助电阻?3 实际电路分析3.1 在不考虑 VCC-5V 电压的纹波等情况时(理想化此时输入的 VCC 就是稳定的 5V)3.2 若考…

HT81698 内置升压双声道 相互p2p兼容 HT81696

HT81698内置升压的立体声D类音频功率放大器,其支持单节锂电、双节锂电串联、5V、12V等多种输入,升压后的电压提供给功放供电,功放支持双通道立体声BTL输出以及并联PBTL单声道输出; HT81698内置的升压电路,可通过FB脚设置升压值&a…

已解决‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。”的问题

已解决‘ping‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。”的问题 文章目录 问题介绍 问题分析 解决思路 解决方法 检查并修复环境变量 进入c:\windows\system32再ping 使用系统工具修复系统文件 Q1 - 问题介绍 当您尝试在Windows命令提示符下…