一、LVGL简介
1.1、什么是LVGL
LVGL(Light and Versatile Graphics Library)是一个免费的开源图形库,提供创建具有易于使用的图形元素、漂亮的视觉效果和低内存占用的嵌入式 GUI。接下来我们来看一下 LVGL图形用户库的主要特征有哪些:
- 强大的构建块:按钮、图表、列表、滑块、图像等部件。
- 具有高级图形属性:具有动画、抗锯齿、不透明度、平滑滚动的高级图形。
- 支持各种输入设备:如触摸、鼠标、键盘、编码器。
- 支持多语言:UTF-8 编码。
- 支持多显示器:它可以同时使用多个 TFT 或者单色显示器。
- 支持多种样式属性:它具有类 CSS 样式的完全可定制的图形元素。
- 独立于硬件之外:它与任何微控制器或显示器一起使用。
- 可扩展性:它能够以小内存运行(最低 64 kB 闪存,16 kB RAM 的 MCU)。
- 支持操作系统、外部存储器和 GPU(不是必需的)。
- 具有高级图形效果:可进行单帧缓冲区操作。
- 纯 C 编写: C语言编写以获得最大的兼容性。
从上述特征可知:LVGL 是一款具有丰富的部件,具备高级图形特性,支持多种输入设备,多国语言和独立于硬件之外等免费的开源图形库
官网地址:https://lvgl.io/
注:该网页主要包含用户文档、图片转换器和字体转换器
如下图所示,点击“GitHub”图标即可进入 LVGL 源码的 github 仓库,在该仓库中,可以下载 LVGL 相关的源码
如下图所示,点击“Docs”图标即可打开LVGL官方文档,该文档是纯英文编写的,主要讲解LVGL的基础知识、移植、部件使用、示例等等
1.2、LVGL移植要求
1.2.1、MCU要求
LVGL图形库移植对 MCU是有要求的,每一个能够驱动显示器的 MCU 是否能运行 LVGL图形库,取决于 MCU 是否具备 LVGL 的最低移植需求。该最低移植需求如下图所示:
从上图可知:微处理器至少是 16 位以上的,显然有些微处理器并不满足这个最低移植需求,接下来,我们以STM32F103ZET6开发板来对比是否满足 LVGL 最低移植需求。STM32开发板的主控 MCU 是 32 位微处理器单元,它的主频率为72MHz,内嵌 Flash 为512KB 以及内嵌 SRAM 为 64KB 等资源信息,这些资源信息比图中的LVGL 最低移植要求是远远大于的,所以是可移植 LVGL 图形库的
1.2.2、显示屏
- 具有 8/16 /24/ 32 位色深的显示屏。
- HDMI 端口的显示器
- 小型单色显示器。
- LED 矩阵。
- 其他可以控制像素颜色/状态的显示器。
例如正点原子的2.8/3.5/4.3/7/10.1寸TFTLCD模块及RGBLCD模块都是16位深的显示屏,这些显示屏皆可满足要求
1.3、LVGL源码获取
LVGL 相关的源码和工程都是存放在 GitHub 远程仓库中,该 GitHub 远程仓库地址为: GitHub - lvgl/lvgl: Embedded graphics library to create beautiful UIs for any MCU, MPU and display type. It's boosted by a professional yet affordable drag and drop UI editor, called SquareLine Studio.读者可以在浏览器打开并下载 LVGL 图形库最新版本源码。
下载完成解压之后,如下图所示
注:本文章中下载的源码版本为V8.2
由上图可知,LVGL源码的目录下有很多文件和文件夹,但我们并不需要完全去了解它们,我们只需要大概的知道文件夹的含义及移植需要的相关部分即可,各文件夹和文件的功能如下图所示:
由上表可知,与LVGL移植相关的文件有examples文件夹、src文件夹、lv_conf_template.h文件和lgvl.h文件,其他部分均与移植无关,我们可以选择忽略
1.3.1、examples文件夹
该文件夹主要包含 LVGL 部件实例、动画实例、其他第三方库实例以及输入设备和显示器驱动文件等内容
注:上表中,只有potring文件夹与移植相关,其他文件夹中存放的是各种实例,可选择忽略
1.3.2、src文件夹
该文件夹主要包含 LVGL 源文件(部件源码、多种解码库)
注:上表中的内容在移植中都是需要用到的,不可选择忽略
二、开始移植
通过上一章的简单介绍,我们对LVGL有了一个大概的认知,接下来我们就将开始进行移植的操作
2.1、准备工作
硬件:STM32F103ZET6开发板
屏幕:7寸LCD显示屏(800*480)
在移植LVGL之前,我们需要先准备一个基础工程,因为本章是无操作系统的移植,因此我们准备的基础工程也要是裸机的,这里我们采用正点原子的《实验27 触摸屏实验》,同时由于我们需要为LVGL提供时基,因此我们还需要准备正点原子的《实验8 定时器中断实验》,最后我们还要准备LVGL8.2版本的源码文件
2.1.1、裁剪LVGL工程源码
准备好上述文件之后,我们就开始对LVGL进行裁剪,我们打开源码文件,将除了examples文件夹、src文件夹、 lv_conf_template.h文件,lvgl.h文件之外的文件都删除掉,因为这些文件是与移植无关的(如果需要用到官方的测试demo,则可以保留demos文件夹,如果不需要将其一并删除即可,本次需要用到测试demo,因此保留了demos文件夹),裁剪完成之后如下图所示:
注:左边为未裁剪之前的源码,右边为裁剪之后的源码
接着打开examples文件夹,将除了porting之外的文件全部删除
注:左边为未删减之前的examples文件夹,右边为裁剪之后的examples文件夹
2.1.2、更改文件名
1.将 lv_conf_template.h 文件名修改成 lv_conf.h 文件名,修改之后如下图所示:
2.将porting文件夹里面的文件全部去除_template字样,修改后如下图所示:
例子:lv_port_disp_template.c 修改为 lv_port_disp.c
2.1.2、修改条件编译指令
1、通过记事本或vscode打开lv_conf.h文件,按要求进行修改,修改完成之后将其保存
修改前:
修改后:
2、打开porting文件夹,将里面的全部文件按要求进行修改
lv_port_disp.c文件
修改前:
修改后:
lv_port_fs.c文件
修改前:
修改后:
lv_port_indev.c文件
修改前:
修改后:
修改完C文件,接着修改H文件
lv_port_disp.h文件
修改前:
修改后:
lv_port_fs.h文件
修改前:
修改后:
lv_port_indev.h文件
修改前:
修改后:
2.2、添加工程文件
2.2.1、新建Middlewares文件夹
我们在前面准备的基础工程目录下,新建一个 Middlewares 文件夹,并在该文件夹下新建 LVGL 文件夹,其次在该文件夹下再新建 GUI 文件夹和 GUI_APP 文件夹,在这两个文件夹下也分别新建 lvgl文件夹,lvgl 文件夹保存前面所精简后的LVGL源码的文件和文件夹,而 GUI_APP 文件夹保存用户编写的文件
注:具体的文件结构图
为什么要使用这样的文件结构呢,因为 LVGL 的源文件内声明 lvgl.h 文件都是以“#include “…/…/lvgl.h””这样的形式声明的,显然这个文件的声明是放在第三层路径下,所以我们把 LVGL 源码放在上图中的 lvgl 文件夹下,这样就符合了 LVGL 声明路径的风格
2.2.2、复制LVGL源码到工程中
将裁剪过后的LVGL源码复制到Middlewaes/LVGL/GUI/lvgl 路径下,如下图所示:
注:demos文件夹先不用复制,后续再讲述复制到何处
2.2.3、添加工程分组
打开基础工程,添加如下工程分组
注:该工程分组是为了对应src文件夹中的内容
2.2.4、添加LVGL源文件
(1)Middlewares/lvgl/src/core 组添加 core 文件夹下的全部.c 文件,如下图所示:
(2)Middlewares/lvgl/src/draw 组添加 draw 文件夹下除 nxp_pxp、 nxp_vglite、sdl 和stm32_dma2d 文件夹之外的全部.c 文件,如下图所示:
(3)Middlewares/lvgl/src/extra 组添加 extra 文件夹下除libs文件夹外的全部.c 文件,如下图所示:
注:Middlewares/lvgl/src/lib文件夹下的文件没有添加到该分组,这些文件是第三方解码库相关的,后续使用到时在讲解如何添加和使用
(4) Middlewares/lvgl/src/font 组添加 font 文件夹下的全部.c 文件,如下图所示:
(5)Middlewares/lvgl/src/gpu 组添加 draw/stm32_dma2d 和 draw/sdl 文件夹下的全部.c 文件,如下图所示:
(6)Middlewares/lvgl/src/hal 组添加 hal 文件夹下的全部.c 文件,如下图所示:
(7)Middlewares/lvgl/src/misc 组添加 misc 文件夹下的全部.c 文件,如下图所示:
(8)Middlewares/lvgl/src/widgets 组添加 widgets 文件夹下的全部.c 文件,如下图所示:
(9)Middlewares/lvgl/examples/porting 组添加Middlewares/LVGL/GUI/lvgl/examples/porting目录下的 lv_port_disp.c 和 lv_port_indev.c 文件,如下图所示:
2.2.5、添加头文件路径
移植LVGL只需要添加关键的头文件路径即可,因为lvgl.h文件已经为我们省去很多包含头文件的操作,添加的头文件路径如下图所示:
2.2.6、添加定时器驱动
将《实验8 定时器中断实验》中的TIMER驱动文件,复制去基础工程的HARDWARE中
复制文件夹完成之后,打开工程,将TIMER添加进工程分组中
并添加timer的头文件路径
2.2.7、屏蔽MDK的警告
移植至此,如果我们此时编译代码,则会出现很多警告,这些警告多少LVGL源码带来的,如果想屏蔽掉这些警告,可以采用以下方法(非必须,慎用):点击魔法棒图标,选中C/C++选项卡,在 Misc Controls 中填入“–diag_suppress=68 --diag_suppress=111 --diag_suppress=188 --diag_suppress=223 --diag_suppress=546 --diag_suppress=1295”。
2.3、修改工程文件
2.3.1、为LVGL提供时基
打开timer.c文件,按要求进行以下修改:
(1)添加lvgl头文件
(2)修改定时器中断服务函数
注:上述源码中,定时器中断服务函数调用了 LVGL 的 lv_tick_inc 函数,该函数让 LVGL 内部一个时基参数加 1。
(3)timer函数初始化
在 main 函数中,对定时器进行初始化操作,对于STM32F103来说,调用定时器设置1ms函数调用如下:
注意:根据自己的 MCU 来开启定时器,定时器周期 1ms。
2.3.2、修改lv_port_disp.c文件
(1)添加LCD头文件及定义屏幕分辨率,如下图所示:
注:本章教程所配套的屏幕为800*480的
(2)在lv_port_disp_init函数中保留模式1,将模式2、3注释或者删除掉,如下图所示:
注:显示缓冲区初始化有三种方式,这里使用的是方式1,方式1消耗的硬件资源最小,但运行效果也是最差的
(3)设置显示设备分辨率修改为自身屏幕的
注:由于基础工程使用的是正点原子的工程,因此此处修改为lcddev.width和lcddev.height,正常我们可以将此处修改成第一点所定义的屏幕分辨率大小
(4)初始化LCD屏幕
(5)修改disp_flush函数
2.3.3、修改lv_port_indev.c文件
(1)添加touch.h头文件
(2)选择触摸输入外设,并将其余外设注释
(3)修改lv_port_indev_init()函数
将100行~172行代码注释或者删除掉
(4)初始化触摸函数
(5)修改touchpad_is_pressed()函数
(6)修改touchpad_get_xy()函数
(7)裁剪代码
将232行~412行代码注释或者删减掉
2.4、移植官方Demo
本次我们采用官方的keypad_encoder来进行demo移植演示
2.4.1、复制demos源码
将demos文件夹复制到Middlewares/LVGL/GUI_APP路径下
2.4.2、添加demos源文件
路径为:实验27 触摸屏实验\Middlewares\LVGL\GUI_APP\demos\keypad_encoder
2.4.3、添加头文件路径
2.4.4、修改lv_conf.h文件
(1)打开 lv_conf.h 文件,找到 LV_USE_DEMO_KEYPAD_AND_ENCODER宏定义并设置为 1,开启该实验
2.4.5、报错解决


2.5、下载验证
我们按照上述步骤完成相关的移植操作之后,接下来我们就要进行代码下载
2.5.1、更改编译模式
将编译模式更改为C99模式,如果不更改的话会报很多错误
2.5.2、编写代码
如下图所示将测试代码添加进main中去,并删除掉其余无关代码
修改完成之后将代码下载进去即可看到运行效果:
2.6、备注
(1)开启内存使用显示以及帧率显示
打开lv_conf.h文件,找到LV_USE_PERF_MONITOR和LV_USE_MEM_MONITOR,并将其改为1即可
注:因为本次我们不需要用到内存使用显示以及帧率显示,因此并没有开启,大家可根据自己的需求来选择是否开启
(2)内存不足报错(Not enough information to list the image map.)
如果编译代码时系统报如上图所示错误,则打开LVGL的配置文件:lv_conf.h,从代码可以看到里面有一个定义内存空间大小为48KB,虽然STM32F103ZET6有64KB的内存,但程序自身要占用很多内存,所以不足以分配这么多给LVGL,因此减小这个内存,一般分配20KB即可。然后重新编译,可以看到编译是没有错误的(分配的内存根据自己的实际需求来选择)
(3)程序运行不了
如果将移植好的代码烧录进去发现无法正常运行的话,可以通过修改堆栈的大小来尝试解决
(4)教学视频:
1.1-初识LVGL--LVGL简介_哔哩哔哩_bilibili
第1讲 基础篇-LVGL入门(1)_哔哩哔哩_bilibili
(5)参考博客:
【LVGL应用开发--基于STM32】第2章 LVGL无操作系统移植_lvgl外部sram-CSDN博客
LVGL8 移植(STM32F1)_lvgl8 触摸移植-CSDN博客
STM32移植LittleVgl(LVGL)嵌入式开源图形库_stm32 tft图形库-CSDN博客
(6)完整代码、文档和工具下载地址: