LVGL工程初步移植
209.3.8 LVGL工程初步移植
/*
* 本节唯一直接修改的 LVGL 配置源码:
* 先把 lv_conf_template.h 重命名为 lv_conf.h,再启用模板中的配置正文。
* 视频只展示这一处配置开关;显示驱动、触摸驱动和 main() 调用均从后续课程开始。
*/
#if 1 /*Set it to "1" to enable content*/ /* 将原来的 #if 0 改成 #if 1,使下方配置参与编译。 */
一、LVGL
LVGL 是 Light and Versatile Graphics Library 的缩写,是面向嵌入式设备的免费开源图形库。它提供对象、控件、布局、样式、动画、输入设备和显示刷新等能力;开发者不必再用底层画点、画线函数手工拼出整个界面。
本节展示官方演示效果后,开始把 LVGL release/v8.3 源码加入已经能显示和触摸的 STM32F103 工程。本地课程包的 lv_conf.h 标明版本为 v8.3.11。课程中的语音转写大量把 “LVGL” 识别成 “IVGL”,精校后统一为正确名称 LVGL。
1.1 LVGL介绍
使用 LVGL 可以构建手表、温湿度仪表、按钮、滑块、滚轮、图表和动画等界面。触摸屏可作为输入设备,实现滑动、点击等交互,例如用滑块设置风扇速度。
需要区分三个层次:
LVGL:计算控件布局、绘制像素、处理事件
显示端口:把 LVGL 生成的像素送到 ST7796
输入端口:把 XPT2046 的触摸坐标和按下状态交给 LVGL
LVGL 本身不要求必须有触摸屏;没有触摸也可以只显示界面,或者接入按键、编码器等输入设备。本课程已有电阻触摸屏,所以后续会把它接成 LVGL 的 pointer 输入设备。
视频开头播放的是已经移植完成后的官方测试演示,用来预览最终目标,不代表本节新建的第 15 号工程此时已经能够运行演示。
1.2 任务及资源导图
本专题有两个学习目标:
- 利用 LVGL 创建比基础 LCD 画图函数更完整的图形界面;
- 通过裁剪、导入和适配开源库,理解第三方源码如何与 MCU 的显示、触摸和时间基准连接。
视频口述的资源门槛是“主频大于 16 MHz、Flash 大于 64 KB、RAM 大于 8 KB”。配套 LVGL v8.3.11 官方资料需要更精确地理解:
| 项目 | 配套 README.md 的最低值 | 推荐值 |
|---|---|---|
| 架构 | 16/32/64 位处理器 | 同左 |
| 主频 | > 16 MHz | > 48 MHz |
| Flash/ROM | > 64 kB | > 180 kB |
| Static RAM | > 16 kB | > 48 kB |
| 绘制缓冲 | 大于 1 行水平像素 | 大于约 1/10 屏幕像素 |
| 编译器 | C99 或更新标准 | C99 或更新标准 |
官方详细文档又把 RAM 拆分为约 2 kB 静态数据、> 2 kB 栈、> 4 kB 动态内存以及显示缓冲;其中 8 kB 是推荐栈大小,不是整个 LVGL 的统一最低 RAM。实际占用还会随控件、字体、颜色深度、编译器和配置项变化。
课程 MCU 是 STM32F103ZET6,工程配置为 512 kB Flash、64 kB SRAM,能够运行经过裁剪的界面,但资源并不宽裕。例如 320×480、RGB565 的完整帧缓冲需要:
[ 320\times480\times2=307200\text{ 字节} ]
这远大于 64 kB SRAM,所以后续必须使用局部绘制缓冲,而不能把整屏 RGB565 帧缓冲放进内部 SRAM。STM32F407、ESP32 或带更多内部/外部内存的芯片更适合复杂界面。
1.3 LVGL部分
本节的工作只到“把 LVGL 源文件正确放入工程并建立编译配置”。显示输出端口、触摸输入端口、LVGL tick、任务处理函数和演示调用均未实现。
1.3.1 LVGL的GitHub仓库
官方源码仓库是 github.com/lvgl/lvgl。视频在 GitHub 的分支/版本选择器中选择 release/v8.3,再执行 Code → Download ZIP。
课程资料已经在第 14 号目录 14LVGL8.3源代码 中提供:
剪裁前/
├─ lvgl-release-v8.3.zip
└─ lvgl-release-v8.3/
剪裁后/
└─ lvgl-release-v8.3/
因此本节无需联网下载。必须使用课程指定的 8.3 系列源码,不能直接拿当前主分支替换,因为不同大版本的配置项、端口模板和 API 可能不兼容。
1.3.2 移植过程
视频把初步移植分为三类工作:裁剪源码、复制到目标工程目录、修改 Keil 工程。文件夹在磁盘中的存在、文件是否被加入 Keil 分组、头文件路径是否可搜索是三件不同的事,缺少任何一项都可能导致编译失败。
1.3.2.1 剪裁
从完整 lvgl-release-v8.3 目录开始,课程执行四步:
- 删除与本课程构建无关的仓库文件,只保留
demos、examples、src三个目录,以及lvgl.h、lv_conf_template.h两个头文件; - 在
examples中只保留porting目录; - 把
lv_conf_template.h重命名为lv_conf.h; - 把
lv_conf.h开头的#if 0改为#if 1,启用配置正文。
剪裁后的准确顶层内容是:
lvgl-release-v8.3/
├─ demos/
├─ examples/
│ └─ porting/
├─ src/
├─ lv_conf.h
└─ lvgl.h
原笔记中的 demo、excel、config.temp.h 分别是识别错误,正确名称为 demos、examples、lv_conf_template.h。这里的“裁剪”主要是减少要搬入课程工程的仓库文件,并不等同于已经通过 lv_conf.h 关闭所有不需要的运行功能。
课程包同时保留剪裁前 ZIP、解压源码和剪裁后结果,既可自己练习,也可在误删或误移动文件后用已知正确的副本恢复。
1.3.2.2 将代码添加到工程文件夹
以第 13 号 13LCD_Display_Touch 工程为基础复制一份,命名为 15LCD_Display_Touch_Lvgl。第 14 号编号已经用于存放 LVGL 源码,所以目标工程从 13 跳到 15。
第 13 号工程已经验证 LCD 与触摸均可用,这是移植 GUI 库的必要基础。LVGL 只负责生成需要刷新的像素和处理界面事件,真正驱动 ST7796、读取 XPT2046 的仍是前面课程移植好的 BSP。
目标工程中实际创建的文件夹名是小写 midware,不是原笔记的 middle,也不是常见拼写 middleware。最终磁盘结构为:
15LCD_Display_Touch_Lvgl/
└─ midware/
├─ demos/
└─ lvgl/
├─ examples/
│ └─ porting/
├─ src/
├─ lv_conf.h
└─ lvgl.h
具体复制方式是:
- 把剪裁后除
demos外的四项——examples、src、lv_conf.h、lvgl.h——复制进midware/lvgl; - 把
demos单独复制到midware,使它与lvgl同级。
视频反复强调 lvgl 使用小写。Windows/Keil 文件系统通常不区分大小写,但源码布局和其他平台可能区分;严格采用库期望的名称可避免相对包含和跨平台问题。
复制完成后可在资源管理器地址栏输入 cmd,再执行:
tree
cd ..
tree 显示目录树,cd .. 返回上一级。原转写还把 ls、pwd 说成 Windows CMD 命令,这不准确:传统 cmd.exe 列目录应使用 dir,查看当前目录可直接使用 cd;ls 和 pwd 是 PowerShell 中可用的别名。
1.3.2.3 工程的修改
将文件复制到磁盘后,还要在 Keil 中完成四项工程配置:建立 9 个虚拟分组、把对应 .c 文件加入分组、添加 4 条头文件路径、开启 C99。第 15 号配套工程可作为最终清单进行核对。
- 1.3.2.3.1 添加代码分组
Keil 左侧的黄色 Group 是工程组织结构,不等同于磁盘文件夹。新建 Group 不会创建目录,也不会自动把目录里的源码纳入编译。
本节新建的 9 个分组为:
midware\lvgl\examples\porting
midware\lvgl\src\core
midware\lvgl\src\draw
midware\lvgl\src\gpu
midware\lvgl\src\extra
midware\lvgl\src\font
midware\lvgl\src\hal
midware\lvgl\src\misc
midware\lvgl\src\widgets
这些名称采用路径样式只是为了便于识别。例如 src\gpu 是虚拟分组名,实际加入的文件位于 src/draw/stm32_dma2d 和 src/draw/sdl;不能根据 Group 名反推出磁盘上必然存在同名文件夹。
- 1.3.2.3.2 添加c文件到分组里
配套第 15 号工程的准确文件清单如下:
| Keil 分组 | 添加规则 | 文件数 |
|---|---|---|
examples\porting | 只加 lv_port_disp_template.c、lv_port_indev_template.c,不加 lv_port_fs_template.c | 2 |
src\core | 加入该目录全部 .c | 15 |
src\draw | 加入 draw 根目录和 draw/sw 的全部 .c | 25 |
src\gpu | 加入 draw/stm32_dma2d 的 1 个 .c 和 draw/sdl 的全部 .c | 15 |
src\extra | 递归加入 extra 及其所有子目录的 .c | 51 |
src\font | 加入该目录全部 .c | 30 |
src\hal | 加入该目录全部 .c | 3 |
src\misc | 加入该目录全部 .c | 22 |
src\widgets | 加入该目录全部 .c | 16 |
| 合计 | 本节加入的 LVGL C 文件条目 | 179 |
porting 中的第三个模板是文件系统端口,本课程此时没有使用,所以不加入。demos 目录本节只复制到磁盘,没有建立 demo 分组,也没有把 demo .c 加入工程;官方演示的实际启用属于后续课程。
GPU、SDL、多媒体库和大量字体虽然被机械地加入工程,但当前 lv_conf.h 中 LV_USE_GPU_STM32_DMA2D、LV_USE_GPU_SDL、PNG、GIF、FreeType、FFmpeg 和各 demo 等开关均为 0。加入源文件不等于启用功能,真正参与编译的代码由预处理配置控制。STM32F103 本身也没有 STM32 DMA2D 外设。
- 1.3.2.3.3 处理问题
视频在 Keil 的添加文件窗口中误拖了文件,可能改变了 draw 目录的真实内容。处理方法是关闭/退出当前选择操作,删除已经被误改的 draw 副本,再从第 14 号“剪裁后”目录重新复制一份干净的 draw。
这个过程说明添加文件时应避免拖拽,尽量放大窗口、核对当前工程编号和路径,再用 Ctrl+A 选择文件并点击 Add。如果不能确定哪个文件被移动,仅靠继续添加无法保证源码完整;从未修改的课程副本恢复更可靠。
extra 的层级最深,课程逐个进入 layouts、libs、others、themes、widgets 等子目录,把其中 .c 加到同一个 src\extra 虚拟分组。字体、HAL 抽象层、misc 工具和基础 widgets 则可在各自目录中批量全选。
二、工程文件介绍
9 个分组的职责可简化理解为:
| 模块 | 主要职责 |
|---|---|
porting | MCU 显示和输入设备适配模板,本课程后续重点修改 |
core | 对象、事件、显示刷新、输入设备和主题核心 |
draw | 矩形、线、圆弧、图片、文字等软件绘制 |
gpu | 可选硬件/平台绘图后端;当前配置未启用 |
extra | 扩展布局、主题、第三方库和扩展控件 |
font | 字体引擎和内置字体数据 |
hal | LVGL 自身的 display、input、tick 抽象,不是 STM32 HAL |
misc | 内存、定时器、动画、颜色、链表、文本等通用工具 |
widgets | 按钮、标签、滑块、表格、文本框等基础控件 |
这里的 src/hal 是 LVGL Hardware Abstraction Layer,不要把它误认为 STM32Cube 的 STM32F1xx_HAL_Driver。前者定义 LVGL 如何看待显示、输入和 tick,后者是 ST 提供的 MCU 外设驱动库;后续端口代码负责连接两者。
把源文件加入 Group 后,Keil 才会为每个活动 .c 建立编译单元。仅把整个 midware 目录复制进工程文件夹,并不会自动编译其中源码。
三、工程修改
在 Options for Target → C/C++ → Include Paths 中新增四条路径:
..\midware
..\midware\lvgl
..\midware\lvgl\src
..\midware\lvgl\examples\porting
它们分别支持从不同位置包含 lvgl/lvgl.h、lvgl.h、lv_conf.h、内部头文件及两个端口模板头文件。必须选择第 15 号工程内的路径;若误指向第 14 号素材目录或第 13 号基础工程,修改与编译的就可能不是同一份源码。
头文件搜索路径和 .c 文件分组作用不同:
- Include Path 只告诉预处理器去哪里找
.h; - Group 中的
.c条目决定哪些实现文件进入编译; - 两者都正确,声明和实现才能最终链接起来。
视频在添加 LVGL 文件前曾点击过一次编译,但也明确说此时“编不编都一样”。本节结束后没有展示包含全部新源文件的最终构建结果,因此不能记录为“LVGL 已经编译通过”。第 15 号工程只是保存为后续继续移植的中间检查点。
四、开启C99模式
最后在 Options for Target → C/C++ 勾选 C99 Mode。第 15 号配套 .uvprojx 中对应值为 uC99 = 1。
LVGL v8.3.11 的官方要求是 C99 或更新标准。开启此选项会让 Keil/Arm Compiler 5 按 C99 规则解析源码,例如支持在代码块中间声明变量等语法;它不是性能优化开关,也不会自动完成 LVGL 的硬件适配。
本节结束状态应准确概括为:
源码已裁剪并复制
→ 179 个 LVGL C 文件已加入 9 个 Keil 分组
→ 4 条头文件路径已加入
→ C99 已开启
→ 尚未配置显示输出、触摸输入、tick 和任务处理
→ 尚未完成 LVGL 编译及上屏验证
保存第 15 号工程后结束本课。第 210 课会复制它作为第 16 号工程,继续开启并修改显示端口模板。