2、LVGL源码结构解析:lvgl文件夹下的核心组件
拿到LVGL源码包,解压后第一件事是什么?我个人的习惯是——先别急着编译,把文件夹结构看明白。你想想看,一个几千文件的工程,如果连目录都搞不清,后面出问题你都不知道去哪找原因。
LVGL的源码结构其实很清晰。核心就三个目录加一个配置文件。咱们一个一个说。
2.1 src目录——真正的核心代码
src 是LVGL的心脏。所有绘图、事件、控件、布局的逻辑都在这里。我刚开始移植的时候,总想着把整个 src 都加进工程,结果编译报错一大堆。后来才明白——这里面的文件是按模块组织的,你只需要选你需要的。
src 下面又分了几个子目录:
| 子目录 | 作用 | 我的建议 |
|---|---|---|
core |
对象系统、显示驱动、输入设备等核心机制 | 必须全部加入工程 |
draw |
底层绘图引擎,包括软件渲染和硬件加速接口 | 必须加入,但可以裁剪渲染后端 |
hal |
硬件抽象层,定义了你需要实现的接口 | 必须加入,这是移植的关键 |
widgets |
所有标准控件,比如按钮、标签、滑块 | 按需加入,用不到的可以去掉 |
layouts |
Flex和Grid布局引擎 | 推荐加入,布局会方便很多 |
misc |
工具函数、数学运算、内存管理 | 必须加入,很多模块依赖它 |
others |
文件系统、监控、快照等扩展功能 | 按需加入 |
widgets 目录下所有 .c 文件一股脑全加进去了。结果编译出来的固件大了 200KB,而我的 Flash 只剩 150KB。后来只保留了按钮和标签,瞬间就塞进去了。所以——不要贪多,用多少加多少。
2.2 examples目录——最好的学习资料
examples 目录里放的是官方示例代码。每个控件、每个功能都有对应的 demo。我个人觉得,这是学习LVGL最快的方式。
举个例子,你想知道按钮怎么用?直接打开 examples/widgets/btn 目录,里面就有完整的代码。复制粘贴,改改参数,跑起来看看效果。比看文档快多了。
但要注意一点:examples 里的代码是为 PC 模拟器写的。它默认用 SDL 模拟显示和输入。你移植到嵌入式平台时,不能直接拿过来用。需要把显示和输入的部分换成你自己的驱动。
2.3 demos目录——开箱即用的演示
demos 目录里是几个完整的演示应用。比如 widgets 演示了所有控件的效果,music 是一个音乐播放器界面,benchmark 用来测试性能。
这些 demo 的好处是——你移植完成后,可以直接跑一个 demo 来验证整个系统是否正常工作。如果 demo 能跑起来,说明你的移植基本没问题了。
但说实话,demos 目录在正式产品里基本用不上。它主要是用来做验证和展示的。我一般只在移植初期跑一下 benchmark,看看帧率是否达标。
2.4 lv_conf.h——整个LVGL的开关
这个文件太重要了。我甚至觉得,移植LVGL的 80% 工作都是在配置这个文件。
lv_conf.h 是LVGL的全局配置文件。它控制着:
- 最大显示分辨率
- 颜色深度(16位还是32位)
- 内存池大小
- 开启哪些控件和功能
- 日志等级
- 等等等等
这个文件默认是 lv_conf_template.h,你需要把它复制一份,重命名为 lv_conf.h,然后放到你的工程里。
打开文件,你会看到一堆 #if 0 和 #if 1 的宏开关。说白了,就是把你要用的功能打开,不需要的关掉。
/* 颜色深度设置 */
#define LV_COLOR_DEPTH 16
/* 内存池大小,单位是字节 */
#define LV_MEM_SIZE (32 * 1024)
/* 开启日志 */
#define LV_USE_LOG 1
#define LV_LOG_LEVEL LV_LOG_LEVEL_INFO
/* 开启按钮控件 */
#define LV_USE_BTN 1
/* 关闭不需要的控件,节省内存 */
#define LV_USE_CHART 0
#define LV_USE_CALENDAR 0
lv_conf.h 必须在所有 LVGL 源文件之前被包含。我见过有人把它放在某个 .c 文件里,结果编译报错说找不到定义。正确的做法是:在编译器的全局包含路径里加上这个文件,或者直接在工程设置里把它设为强制包含头文件。
嗯,这里要注意一个细节:LV_MEM_SIZE 的设置。这个值决定了LVGL内部动态分配内存的上限。设太小了,界面复杂时会分配失败;设太大了,MCU的内存又不够。我一般先设 32KB,跑起来看看,如果报内存不足就往上加。
2.5 整体结构图
说了这么多,咱们用一张图把关系理清楚:
2.6 移植时的文件取舍策略
说白了,你不需要把整个 lvgl 目录都塞进工程。我一般按这个策略来:
- src 目录: core、draw、hal、misc 这四个子目录全部加入。widgets 只加你用到的控件。layouts 建议加入,但如果你只用绝对定位,可以不加。others 看需求。
- examples 目录: 不加入嵌入式工程。只在 PC 模拟器上参考。
- demos 目录: 移植初期加入 benchmark 用于验证。正式产品中全部移除。
- lv_conf.h: 必须加入,且放在编译器全局包含路径中。
lvgl_port 文件夹,里面放 lv_conf.h 和我的显示/输入驱动文件。这样 LVGL 官方源码和我的移植代码分得清清楚楚,升级 LVGL 版本时直接替换 lvgl 目录就行,不会覆盖我的配置。
好了,源码结构就说到这。记住一句话:src 是引擎,examples 是说明书,demos 是试车跑道,lv_conf.h 是方向盘。搞清楚了这些,后面移植的时候你就知道该动哪里了。