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

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

3天内不再提示

全面解读目前LVGL的应用小知识

电子工程师 来源:华芯微特32位MCU 作者:华芯微特32位MCU 2021-06-04 12:01 次阅读

概述

本文介绍目前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就是模板的意思)。通过它可以设置库的基本行为,裁剪不需要模块和功能,在编译时调整内存缓冲区的大小等等。

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

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

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

准备lvgl配置文件

af7f2894-c4c6-11eb-9e57-12bb97331649.png

使能配置文件

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 以及相关其他组件。初始化的顺序为:

调用 lv_init() 初始化 lvgl 库;

初始化驱动程序;

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

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

每隔 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 变量:

afb16c3c-c4c6-11eb-9e57-12bb97331649.jpg

类型 (indev_drv.type)可以是:

LV_INDEV_TYPE_POINTER 触摸板或鼠标

LV_INDEV_TYPE_KEYPAD 键盘或小键盘

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

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。

(四)、编码器

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

按下按钮

长按其按钮

转左

右转

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

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

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

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

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

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

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

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

需要有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” 回调。

编辑:jq

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

    关注

    68

    文章

    19191

    浏览量

    229311
  • 编码器
    +关注

    关注

    45

    文章

    3604

    浏览量

    134257
  • gpu
    gpu
    +关注

    关注

    28

    文章

    4709

    浏览量

    128781
  • 函数
    +关注

    关注

    3

    文章

    4317

    浏览量

    62487
  • LVGL
    +关注

    关注

    1

    文章

    82

    浏览量

    2931

原文标题:华芯微特小课堂--LVG免费开源GUI图形库

文章出处:【微信号:gh_ed4f95bde4df,微信公众号:华芯微特32位MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    芯原股份与开源图形库LVGL达成战略合作

    芯原股份 (芯原,股票代码:688521.SH) 今日宣布与嵌入式系统领域领先的开源图形库LVGL达成战略合作,在LVGL库中支持芯原的低功耗3D和VGLite 2.5D GPU技术。此次合作旨在
    的头像 发表于 11-29 09:20 251次阅读

    如何在低成本ARM平台部署LVGL免费图形库,基于全志T113-i

    本帖最后由 Tronlong创龙科技 于 2024-10-29 10:39 编辑 LVGL简介 LVGL(Littlev Graphics Library)是一个开源的图形库,主要用于嵌入式
    发表于 10-29 09:55

    LVGL开发指南介绍

    电子发烧友网站提供《LVGL开发指南介绍.pdf》资料免费下载
    发表于 09-09 10:24 15次下载

    百问网全志T113-PRO LVGL环境配置

    运行LVGL示例 启动开发板 ​ 按要求接入电源或Type-c数据线,拨动拨码开关,将开发板上电 运行LVGL示例 ​ 打开串口终端软件,这里我使用MobaXterm软件演示,选择开发板的串口终端号
    发表于 08-01 10:11

    如何优雅的在OpenMV上使用LVGL

    LVGL适配到OpenMV工程menuconfig配置LVGL配置在SDK中的openmv工程的基础上进行修改,添加LVGLV8的packages包,使用scons
    的头像 发表于 07-31 08:36 1016次阅读
    如何优雅的在OpenMV上使用<b class='flag-5'>LVGL</b>

    rt-thread中的lvgl怎样才使用外部RAM?

    我想问一下rt-thread中的lvgl怎样才使用外部RAM,我想把lvgl的绘图缓冲区搬到外部RAM上,我是这么做的,直接在lv_port_disp.c中修改
    发表于 07-15 07:29

    求助,如何更新esp-iot-solution中lvgl库的版本?

    因为现在esp-iot-solution组件中自带的lvgl是7.5的,如果我想使用最新的lvgl版本,我怎么才能正确的更新它呢?
    发表于 06-28 06:56

    如何正确的将lv_port_esp32的LVGL部分合并到ESP_IDF中呢?

    我使用lv_port_esp32测试LVGL显示正常,但是在将其合并到我自己基于ESP_IDF(v4.2.1)工程中的时候遇见了问题。我将lv_examples、lvgl
    发表于 06-21 12:43

    请问esp32在使用lvgl的时候要怎么配置使用外部ROM?

    请问esp32 在使用lvgl的时候要怎么配置使用外部ROM?我现在用的是git上的的lv_port_esp32 https://github.com/lvgl/lvgl
    发表于 06-20 06:29

    esp32s2同时使用wifi和lvgl出错重启是什么原因?

    我尝试在用lvgl做一组wifi扫描连接界面,但加入wifi扫描后,esp32s2就不断重启,使用的版本是release4.4,vscode c开发。具体我也去查过,也有人遇到这个问题,他用
    发表于 06-17 06:16

    ESP32S3 + LVGL遇到LoadProhibited问题如何解决?

    was unhandled. dump PC指向.../components/lvgl/src/core/lv_disp.c:150 lv_demo_benchmark也遇到同样的问题,只是最后指向的位置
    发表于 06-06 07:30

    ESP32S3R8使用iot—button组件是否可以和lvgl搭配使用呢?

    IDF:ESP-IDFV5.1.1 芯片:ESP32S3R8 请问使用iot—button组件是否可以和lvgl搭配使用呢?目前想用GPIO按键去控制LVGL的UI界面按键控件,是否有例子去实现呢?
    发表于 06-05 08:13

    【Vision Board创客营连载体验】RA8D1-Vision Board 移植LVGL8.3驱动库和触摸屏驱动代码

    先说结论:移植LVGL的过程挺顺利的,触摸屏也能正常移植运行,但是目前无法通过触摸与LVGL界面联动,原因未知。 移植LVGL8.3.10图形库,包括源文件和头文件: 修改颜色位数
    发表于 05-13 19:53

    基于RA8D1的LVGL FSP配置以及使用介绍

    本文介绍由e2 studio自动生成的FSP LVGL pack的使用说明,Pack的生成方法可以参考前面的介绍文章。
    的头像 发表于 03-13 13:48 1822次阅读
    基于RA8D1的<b class='flag-5'>LVGL</b> FSP配置以及使用介绍

    详解全志R128GUI图形系统——LVGL

    和PDF 格式的文档和API 参考。 目前RTOS 中移植了LVGL 8.1.0 核心组件与Demo,下表列出LVGL 相关库说明: 包名 说明 lv_demos lvgl的官方dem
    发表于 12-07 15:43