1. LVGL初探:从认识到了解,再到跑起第一个程序
各位同学好,我是老周。做嵌入式GUI开发有些年头了,从最早的裸机画点、画线,到后来用各种商业GUI库,踩过的坑真不少。今天咱们开始聊LVGL——这个近几年在嵌入式圈子里特别火的开源图形库。
说实话,我第一次接触LVGL是在一个智能家居项目里。当时客户要求界面要“像手机一样流畅”,老板又不想花钱买商业授权。我翻遍了GitHub,最后锁定了LVGL。嗯,这一用就是好几年。
1.1 什么是LVGL?
LVGL的全称是 Light and Versatile Graphics Library,轻量级且多功能的图形库。它专门为嵌入式系统设计,目标是让资源受限的MCU也能跑出漂亮的图形界面。
你想想看,一个只有几百KB Flash、几十KB RAM的单片机,要显示按钮、滑块、图表、动画……听起来是不是有点扯?但LVGL做到了。
核心定位:LVGL不是操作系统,也不是硬件驱动。它是一层图形中间件,跑在RTOS或裸机上,帮你管理屏幕上的所有视觉元素。
我习惯把LVGL比作“嵌入式界的Qt”。它提供了丰富的控件库,你只需要调用API,就能快速搭建出专业级的用户界面。而且它是开源的,MIT许可证,商用也没问题。
1.2 LVGL的发展史
LVGL的故事要从2016年说起。匈牙利开发者Gábor Kiss-Vámosi(网名kisvegabor)在GitHub上发布了第一版,当时还叫LittlevGL。最初只是个小众项目,连文档都不全。
我记得2018年那会儿,我在一个论坛上看到有人讨论LittlevGL,说“这玩意儿能在STM32上跑出60帧”。我当时半信半疑,下载源码试了试……结果真香。
项目的发展有几个关键节点:
| 时间 | 版本 | 重要变化 |
|---|---|---|
| 2016年 | v1.0 | 初始发布,基本控件和绘图功能 |
| 2018年 | v5.0 | 引入样式系统,控件数量大幅增加 |
| 2019年 | v6.0 | 改名为LVGL,重构API,支持更复杂的动画 |
| 2021年 | v8.0 | 重大架构升级,引入lvgl.h统一头文件,性能优化 |
| 2023年 | v9.0 | 支持多显示器、GPU加速、更完善的输入设备管理 |
从v6到v8,API变化很大。我当年从v6迁移到v8,改代码改到怀疑人生。但v8的架构确实更清晰,性能也更好。现在新项目我建议直接上v9,除非你有特殊兼容需求。
1.3 LVGL的应用场景与优势
LVGL能做什么?说白了,只要你的设备需要屏幕交互,它基本都能上。
- 智能家居面板:温控器、灯光控制、门禁对讲
- 工业HMI:PLC人机界面、数据采集终端
- 消费电子:智能手表、健身设备、小家电屏幕
- 车载仪表:电动车仪表盘、后视镜显示
- 医疗设备:监护仪、手持诊断工具
它的优势,我总结了几点:
| 优势 | 说明 |
|---|---|
| 资源占用低 | 最小配置只需16KB Flash + 8KB RAM |
| 控件丰富 | 内置30+控件,按钮、滑块、图表、键盘等 |
| 样式灵活 | 支持CSS-like样式,可自定义主题 |
| 动画引擎 | 内置补间动画,无需额外算法 |
| 输入设备 | 支持触摸、按键、编码器、鼠标等 |
| 跨平台 | 可在Windows/Linux/Mac模拟器上调试 |
| 开源免费 | MIT许可证,商用无限制 |
我的经验:如果你用的是Cortex-M4以上内核、Flash大于256KB、RAM大于64KB,跑LVGL基本没压力。资源更紧张的话,可以裁剪不需要的控件和功能。
1.4 LVGL的架构概览
在动手之前,咱们先看看LVGL的整体架构。理解了这张图,后面学起来会顺很多。
从上往下看:你的应用程序调用LVGL的API,LVGL核心库负责所有控件的渲染和交互逻辑,硬件抽象层把绘图指令翻译成具体的LCD驱动命令,最后在屏幕上显示出来。
为什么要分层?我在项目中遇到过这种情况:换了一块屏幕,驱动芯片变了。如果代码里到处是直接操作寄存器的语句,那改起来真要命。但LVGL的HAL层把显示和输入设备抽象出来了,换屏只需要改底层驱动,上层代码完全不用动。
1.5 在模拟器上跑第一个LVGL程序
好了,理论说完了,咱们动手。我建议初学者先在PC模拟器上跑LVGL,原因很简单:调试方便,不用反复烧录固件,还能用IDE的断点调试功能。
下面我以Windows + VS Code + SDL2为例,带你走一遍流程。
1.5.1 准备环境
你需要装这几样东西:
- VS Code:代码编辑器,装好C/C++扩展
- CMake:构建工具,版本3.10以上
- MinGW或MSVC:C编译器,我习惯用MinGW
- SDL2:模拟器依赖的图形后端
注意:SDL2的安装路径不要带中文和空格。我曾经因为路径里有空格,折腾了半小时找不到库文件。
1.5.2 下载源码
从GitHub上克隆LVGL仓库和模拟器项目:
git clone https://github.com/lvgl/lvgl.git
git clone https://github.com/lvgl/lv_port_pc_eclipse.git
或者你直接下载ZIP包也行。我习惯用git,方便后面切换版本。
1.5.3 配置项目
进入 lv_port_pc_eclipse 目录,打开CMakeLists.txt。找到这几行:
# 设置LVGL源码路径
set(LVGL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../lvgl CACHE PATH "Path to lvgl repository")
确保路径指向你刚才下载的lvgl目录。如果目录结构不一样,手动改一下。
1.5.4 编译运行
在终端里执行:
mkdir build
cd build
cmake ..
make
编译成功后,运行生成的可执行文件。你会看到一个窗口,里面显示LVGL的默认demo界面——一个带按钮和标签的示例。
小技巧:如果窗口显示不出来,检查SDL2的dll是否在可执行文件同目录下。我一般直接把SDL2.dll复制到build目录里。
1.5.5 写一个最简单的程序
咱们不跑demo了,自己写一个。新建 main.c,输入以下代码:
#include "lvgl.h"
#include "lv_drivers/display/monitor.h"
#include "lv_drivers/indev/mouse.h"
int main(void)
{
/* 初始化LVGL */
lv_init();
/* 初始化显示器驱动 */
monitor_init();
/* 初始化鼠标驱动 */
mouse_init();
/* 设置默认显示设备 */
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = monitor_flush;
lv_disp_drv_register(&disp_drv);
/* 设置默认输入设备 */
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = mouse_read;
lv_indev_drv_register(&indev_drv);
/* 创建一个按钮 */
lv_obj_t *btn = lv_btn_create(lv_scr_act());
lv_obj_set_pos(btn, 100, 100);
lv_obj_set_size(btn, 120, 50);
/* 在按钮上添加标签 */
lv_obj_t *label = lv_label_create(btn);
lv_label_set_text(label, "Hello LVGL!");
lv_obj_center(label);
/* 主循环 */
while(1)
{
lv_task_handler();
SDL_Delay(5);
}
return 0;
}
这段代码做了几件事:初始化LVGL、设置显示和输入设备、在屏幕上创建一个按钮、按钮上显示文字。最后进入主循环,不断处理LVGL的任务。
编译运行,你会看到一个窗口,中间有个按钮,上面写着“Hello LVGL!”。点击按钮虽然还没反应,但你已经成功跑起了第一个LVGL程序。
恭喜你!从这一刻起,你已经迈入了嵌入式GUI开发的大门。后面我们会逐步深入,让这个按钮动起来、变漂亮、响应点击事件。
1.6 本章小结
这一章我们聊了LVGL是什么、怎么来的、能干什么、以及怎么在模拟器上跑起来。说白了,LVGL就是一个让单片机也能拥有漂亮界面的开源库。它的架构清晰,资源占用低,社区活跃,是目前嵌入式GUI领域最值得投入时间学习的选择之一。