LVGL | LVGL移植之中文文档

LVGL是一个强大的图形库,用于在嵌入式设备上创建用户界面。本文档详细介绍了如何配置LVGL、设置项目、获取库、配置文件、初始化、显示界面、显示缓冲区、显示驱动程序、回转、应用程序接口、输入设备接口、时钟接口、任务处理程序、睡眠管理和操作系统中断。通过这些步骤,你可以有效地在你的嵌入式系统上构建和管理LVGL图形用户界面。

目录

系统总览

设置项目

获取图书馆

配置文件

初始化

显示界面

显示缓冲区

显示驱动程序

回转

应用程序接口

输入设备接口

输入设备的类型

触摸板、鼠标或任何指针

键盘或键盘

编码器

按钮

其他特性

应用程序接口

时钟接口

应用程序接口

任务处理程序

睡眠管理

操作系统和中断

中断

日志记录

日志级别

使用 printf 记录

自定义日志功能

添加日志

任务和线程


LVGL文档中文网站

系统总览

 

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

LVGL 图形库本身。您的应用程序可以与库通信以创建 GUI。它包含一个 HAL(硬件抽象层)接口来注册您的显示和输入设备驱动程序。

驱动程序 除了您的特定驱动程序之外,它还包含驱动您的显示器的功能,可选择驱动到 GPU 并读取触摸板或按钮。


根据 MCU 的不同,有两种典型的硬件设置。一个带有内置 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。

    设置项目

    获取图书馆

    LVGL 图形库可在 GitHub 上获得:https : //github.com/lvgl/lvgl

    您可以克隆它或从 GitHub 下载最新版本的库。

    图形库是lvgl目录,应复制到您的项目中。

    配置文件

    有一个名为lv_conf.h 的 LVGL配置头文件。它设置库的基本行为,禁用未使用的模块和功能,在编译时调整内存缓冲区的大小等。

    lvgl/lv_conf_template.h复制到lvgl目录旁边,并将其重命名为lv_conf.h。打开文件并将开头更改为以启用其内容。#if 0#if 1

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

    在配置文件的注释中解释了选项的含义。至少检查这三个配置选项并根据您的硬件进行修改:

    1. LV_HOR_RES_MAX显示器的水平分辨率。

    2. LV_VER_RES_MAX显示器的垂直分辨率。

    3. LV_COLOR_DEPTH 8 表示(RG332),16 表示(RGB565)或 32 表示(RGB888 和 ARGB8888)。

    初始化

    要使用图形库,您必须初始化它和其他组件。初始化的顺序是:

    1. 调用lv_init()

    2. 初始化您的驱动程序。

    3. 在 LVGL 中注册显示和输入设备驱动程序。有关显示输入设备注册的更多信息。

    4. lv_tick_inc(x)x中断中每毫秒调用一次以告诉经过的时间。了解更多

    5. lv_task_handler()每隔几毫秒定期调用以处理 LVGL 相关任务。了解更多

      显示界面

      要设置显示的lv_disp_buf_tlv_disp_drv_t变量的初始化。

      • lv_disp_buf_t包含内部图形缓冲区。

      • lv_disp_drv_t包含回调函数来与显示交互和操作绘图相关的东西。

      显示缓冲区

      lv_disp_buf_t 可以这样初始化:

          /*A static or global variable to store the buffers*/
          static lv_disp_buf_t disp_buf;
      
          /*Static or global buffer(s). The second buffer is optional*/
          static lv_color_t buf_1[MY_DISP_HOR_RES * 10];
          static lv_color_t buf_2[MY_DISP_HOR_RES * 10];
      
          /*Initialize `disp_buf` with the buffer(s) */
          lv_disp_buf_init(&disp_buf, buf_1, buf_2, MY_DISP_HOR_RES*10);
      

      关于缓冲区大小,有 3 种可能的配置:

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

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

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

      您可以使用基准示例来衡量显示配置的性能。

      显示驱动程序

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

      • 指向初始化lv_disp_buf_t变量的缓冲区指针。

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

      有一些可选的数据字段:

      • hor_res 显示器的水平分辨率。(LV_HOR_RES_MAX默认来自lv_conf.h)。

      • ver_res 显示器的垂直分辨率。(LV_VER_RES_MAX默认来自lv_conf.h)。

      • color_chroma_key将在镀铬键控图像上绘制为透明的颜色。LV_COLOR_TRANSP默认情况下来自lv_conf.h)。

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

      • 抗锯齿使用抗锯齿(边缘平滑)。LV_ANTIALIAS默认来自lv_conf.h

      • 旋转sw_rotate请参阅下面的旋转部分。

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

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

      • gpu_fill_cb用颜色填充内存区域。

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

      • gpu_wait_cb如果有任何 GPU 函数返回,当 GPU 仍在 LVGL 工作时,将在需要时使用此函数,确保 GPU 渲染已准备就绪。

      请注意,这些函数需要直接绘制到内存 (RAM) 而不是您的显示器。

      一些其他可选的回调,使处理单色、灰度或其他非标准 RGB 显示器更容易、更优化:

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

      • set_px_cb一个自定义函数来写入显示缓冲区。如果显示器具有特殊的颜色格式,它可用于更紧凑地存储像素。(例如 1 位单色、2 位灰度等)这样使用的缓冲区lv_disp_buf_t可以更小,以仅容纳给定区域大小所需的位数。set_px_cb不适用于显示缓冲区配置。Two screen-sized buffers

      • monitor_cb一个回调函数告诉多少像素在多少时间内被刷新。

      • clean_dcache_cb用于清除与显示相关的任何缓存的回调

      要设置lv_disp_drv_t变量的字段,它需要用lv_disp_drv_init(&disp_drv). 最后lv_disp_drv_register(&disp_drv)需要调用为 LVGL 注册一个显示。

      放在一起看起来像这样:

          lv_disp_drv_t disp_drv;                 /*A variable to hold the drivers. Can be local variable*/
          lv_disp_drv_init(&disp_drv);            /*Basic initialization*/
          disp_drv.buffer = &disp_buf;            /*Set an initialized buffer*/
          disp_drv.flush_cb = my_flush_cb;        /*Set a flush callback to draw to the display*/
          lv_disp_t * disp;
          disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created display objects*/
      

      这里有一些简单的回调示例:

      void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
      {
          /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
          int32_t x, y;
          for(y = area->y1; y <= area->y2; y++) {
              for(x = area->x1; x <= area->x2; x++) {
                  put_px(x, y, *color_p)
                  color_p++;
              }
          }
      
          /* IMPORTANT!!!
           * Inform the graphics library that you are ready with the flushing*/
          lv_disp_flush_ready(disp_drv);
      }
      
      void my_gpu_fill_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, const lv_area_t * dest_area, const lv_area_t * fill_area, lv_color_t color);
      {
          /*It's an example code which should be done by your GPU*/
          uint32_t x, y;
          dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
      
          for(y = fill_area->y1; y < fill_area->y2; y++) {
              for(x = fill_area->x1; x < fill_area->x2; x++) {
                  dest_buf[x] = color;
              }
              dest_buf+=dest_width;    /*Go to the next line*/
          }
      }
      
      void my_gpu_blend_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
      {
          /*It's an example code which should be done by your GPU*/
          uint32_t i;
          for(i = 0; i < length; i++) {
              dest[i] = lv_color_mix(dest[i], src[i], opa);
          }
      }
      
      void my_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area)
      {
        /* Update the areas as needed. Can be only larger.
         * For example to always have lines 8 px height:*/
         area->y1 = area->y1 & 0x07;
         area->y2 = (area->y2 & 0x07) + 8;
      }
      
      void my_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
      {
          /* Write to the buffer as required for the display.
           * Write only 1-bit for monochrome displays mapped vertically:*/
       buf += buf_w * (y >> 3) + x;
       if(lv_color_brightness(color) > 128) (*buf) |= (1 << (y % 8));
       else (*buf) &= ~(1 << (y % 8));
      }
      
      void my_monitor_cb(lv_disp_drv_t * disp_drv, uint32_t time, uint32_t px)
      {
        printf("%d px refreshed in %d ms\n", time, ms);
      }
      
      void my_clean_dcache_cb(lv_disp_drv_t * disp_drv, uint32)
      {
        /* Example for Cortex-M (CMSIS) */
        SCB_CleanInvalidateDCache();
      }
      

      回转

      LVGL 支持以 90 度为增量旋转显示器。您可以选择是要软件轮换还是硬件轮换。

      如果您选择软件旋转(sw_rotate标志设置为 1),LVGL 将为您执行旋转。您的驱动程序可以并且应该假设屏幕宽度和高度没有改变。只需像往常一样将像素刷新到显示器即可。软件轮换在您的flush_cb回调中不需要额外的逻辑。

      在软件中执行轮换需要大量的开销,这就是硬件轮换也可用的原因。在这种模式下,LVGL 将绘制到缓冲区中,就好像您的屏幕现在具有反转的宽度和高度一样。您有责任自己旋转提供的像素。

      初始化时显示的默认旋转可以使用rotated标志设置。可用选项为LV_DISP_ROT_NONELV_DISP_ROT_90LV_DISP_ROT_180,或LV_DISP_ROT_270。旋转值与顺时针方向旋转物理显示器的方式有关。因此,LV_DISP_ROT_90意味着您将硬件顺时针旋转 90 度,显示器逆时针旋转 90 度以进行补偿。

      (从 7.10.0 及更早版本升级的用户请注意:这些新的旋转枚举值与旧的 0/1 系统匹配,用于旋转 90 度,因此遗留代码应继续按预期工作。默认情况下,软件旋转也被禁用以实现兼容性.)

      也可以在运行时使用API更改显示旋转。lv_disp_set_rotation(disp, rot)

      支持软件轮换是一项新功能,因此根据您的配置可能存在一些故障/错误。如果您遇到问题,请在GitHub 上打开一个问题。

      应用程序接口

      显示驱动 HAL 接口头文件

      类型定义

      类型定义结构_disp_drv_tlv_disp_drv_t

      HAL 要注册的显示驱动程序结构

      类型定义结构_disp_tlv_disp_t

      显示结构。

      笔记

      lv_disp_drv_t 应该是结构的第一个成员。

      枚举

      枚举lv_disp_size_t

      价值观:

      枚举器LV_DISP_SIZE_SMALL

      枚举器LV_DISP_SIZE_MEDIUM

      枚举器LV_DISP_SIZE_LARGE

      枚举器LV_DISP_SIZE_EXTRA_LARGE

      职能

      无效lv_disp_drv_initlv_disp_drv_t *驱动程序

      使用默认值初始化显示驱动程序。它用于在字段中具有已知值而不是内存中的垃圾。之后,您可以安全地只设置您需要的字段。

      参数

      驱动程序——指向要初始化的驱动程序变量的指针

      void lv_disp_buf_initlv_disp_buf_t * disp_buf , void * buf1 , void * buf2 , uint32_t size_in_px_cnt )

      初始化显示缓冲区

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值