2、开发环境搭建:硬件平台选择、软件工具链安装、源码获取与工程结构解析
好,咱们正式开始动手了。这一章我带你搞定开发环境。说白了,就是把你电脑变成一台能编译、能烧录、能调试 LVGL 的工作站。我这些年移植 LVGL 踩过的坑,有一半都出在环境没搭好上。所以这一章,咱们稳扎稳打。
2.1 硬件平台怎么选?STM32 还是 ESP32?
很多新手一上来就问:「老师,我用哪个板子好?」我的回答是:看你手头有什么,就用什么。但如果你让我推荐,我会说——
| 对比项 | STM32(以F4/H7为例) | ESP32(以S3为例) |
|---|---|---|
| 主频 | 168~480 MHz | 240 MHz |
| RAM | 192KB~1MB(片内) | 512KB(片内)+ 外挂PSRAM |
| Flash | 1~2MB(片内) | 16MB(外挂) |
| 显示接口 | LTDC/FMC(需外挂SDRAM) | SPI/QSPI + PSRAM |
| 开发难度 | 中等(寄存器/HAL库) | 较低(Arduino/ESP-IDF) |
| 成本 | 板子约80~200元 | 板子约30~60元 |
我个人习惯:做产品原型用 STM32,因为它的显示控制器 LTDC 是硬核,刷屏不占 CPU。做快速验证或小项目,我直接上 ESP32,便宜、WiFi 蓝牙都有,社区资源也丰富。
2.2 软件工具链安装
工具链这东西,装一次管三年。但装错了,能折腾你三天。我分三个平台来讲。
2.2.1 IDE 选择
- STM32 用户:我推荐 STM32CubeIDE。免费、自带 CubeMX 配置、GCC 编译器、OpenOCD 调试器,一套搞定。你不需要再装别的。
- ESP32 用户:用 VS Code + ESP-IDF 插件。或者直接用 Arduino IDE(适合纯新手)。我个人更倾向 ESP-IDF,因为 LVGL 的官方例程就是基于它写的。
2.2.2 编译器与调试器
嗯,这里要注意:STM32CubeIDE 自带的 ARM GCC 版本可能比较老。我遇到过编译 LVGL 的某些新特性时报错,比如 _Generic 关键字不支持。解决办法是手动更新编译器。
手动更新 GCC 步骤(STM32 用户):
- 下载最新版 ARM GCC:
arm-gnu-toolchain(去 ARM 官网) - 解压到
C:\ARM_GCC\或/opt/arm-gcc/ - 在 CubeIDE 中:Window → Preferences → C/C++ → Build → Global Tools Paths,把编译器路径指过去
调试器方面,ST-Link 是标配。ESP32 用板载的 USB 转串口(CH340/CP2102)就能烧录和看日志。如果你想单步调试 ESP32,需要买一个 JTAG 调试器,比如 FT2232H。说实话,我很少用 JTAG 调 ESP32,printf 大法它不香吗?
2.2.3 源码获取
LVGL 的源码托管在 GitHub 上。我建议你直接 clone 官方仓库,而不是下载 zip。为什么?因为后续你想切分支、看历史提交、或者拉取子模块,git 操作方便得多。
# 克隆 LVGL 主仓库
git clone https://github.com/lvgl/lvgl.git
# 进入目录
cd lvgl
# 查看所有版本标签
git tag -l
# 切换到稳定版本(比如 v8.3.11)
git checkout v8.3.11
lvgl/examples 和 lvgl/demos 文件夹。原来这些是子模块,zip 下载不会自动拉取。所以一定要用 git clone --recursive 或者手动 git submodule update --init。
2.3 工程结构解析
源码拿到了,咱们看看里面都有啥。我带你走一遍核心目录。
lvgl/
├── lvgl/ # 核心源码
│ ├── src/ # 所有源文件
│ │ ├── core/ # 核心对象、事件、刷新机制
│ │ ├── draw/ # 绘图引擎(软件渲染、GPU加速)
│ │ ├── font/ # 字体引擎
│ │ ├── hal/ # 硬件抽象层(显示、触摸、文件系统)
│ │ ├── misc/ # 工具函数、内存管理、日志
│ │ ├── layouts/ # 布局引擎(Flex、Grid)
│ │ ├── libs/ # 第三方库(PNG、GIF、Freetype等)
│ │ ├── others/ # 其他功能(文件浏览器、日历等)
│ │ └── widgets/ # 所有控件(按钮、标签、滑块等)
│ ├── examples/ # 示例代码
│ ├── demos/ # 演示应用(音乐播放器、手表等)
│ ├── docs/ # 文档(HTML、PDF)
│ └── lv_conf_template.h # 配置文件模板
└── lv_porting/ # 移植模板(显示、触摸、文件系统)
你想想看,这个结构其实很清晰。核心在 src/ 里,你基本不用动。你需要改的是 lv_conf.h(从模板复制过来)和 lv_porting/ 里的文件。
lv_conf_template.h 复制到项目根目录,重命名为 lv_conf.h。然后在 lv_porting 里,我只保留 lv_port_disp.c 和 lv_port_indev.c,其他删掉。这样工程清爽,不会引入无关代码。
2.3.1 配置文件 lv_conf.h 的关键宏
这个文件是 LVGL 的「总开关」。我挑几个你一定会碰到的:
| 宏定义 | 作用 | 我的建议值 |
|---|---|---|
LV_COLOR_DEPTH |
颜色深度:16 或 32 | 16(节省一半显存) |
LV_MEM_SIZE |
LVGL 内部堆大小 | 32KB(简单UI)~ 128KB(复杂UI) |
LV_HOR_RES_MAX |
屏幕水平分辨率 | 你的屏幕宽度 |
LV_VER_RES_MAX |
屏幕垂直分辨率 | 你的屏幕高度 |
LV_USE_DEMO_WIDGETS |
启用控件演示 | 1(调试阶段打开) |
LV_MEM_SIZE 设成了 8KB,结果创建几个按钮就崩了。后来查文档才发现,LVGL 默认的控件对象每个就要占用几十到几百字节。所以,起步至少 32KB,别省这点内存。
2.3.2 移植模板 lv_porting 怎么用?
打开 lv_porting 文件夹,你会看到三个核心文件:
lv_port_disp.c/.h—— 显示驱动接口lv_port_indev.c/.h—— 输入设备接口(触摸、按键、编码器)lv_port_fs.c/.h—— 文件系统接口(如果你需要读取 SD 卡图片)
每个文件里都有 /* TODO */ 注释,告诉你哪里需要填代码。说白了,你只需要实现三个函数:
disp_flush()—— 把显存里的像素数据刷到屏幕touchpad_read()—— 读取触摸坐标encoder_read()—— 读取编码器状态(如果有)
剩下的初始化、缓冲区管理,模板里都写好了框架。你照着填空就行。
小技巧:在 disp_flush() 函数里,记得在刷完一帧后调用 lv_disp_flush_ready()。我见过有人忘了这步,结果屏幕一直黑着。LVGL 会等这个回调通知,才继续下一帧的绘制。
2.4 验证环境是否搭好
工具链装完、源码拉下来、工程结构看懂了。怎么知道环境没问题?我的做法是:先编译一个空工程,只包含 LVGL 核心库,不跑任何 UI。编译通过,说明工具链和源码路径没问题。
# 在项目目录下执行(以 GCC 为例)
make clean
make -j4
# 如果看到类似输出,说明编译成功
# arm-none-eabi-size build/lvgl_demo.elf
# text data bss dec hex
# 123456 1234 5678 130368 1fd40
然后,我会烧录一个最简单的 demo:只显示一个标签 "Hello LVGL"。如果屏幕亮了,字出来了,恭喜你,环境搭建完成!