第一章 LVGL概述与环境搭建

1.1 LVGL是什么

LVGL,全称Light and Versatile Graphics Library,是一个开源的嵌入式图形库。说白了,它就是一套专门给资源受限的嵌入式设备用的UI框架。你想想看,一个只有几百KB内存的MCU,也能跑出流畅的动画和漂亮的界面,这就是LVGL的厉害之处。

我最早接触LVGL是在2019年,当时一个智能家居项目需要做触摸屏界面。传统的方案要么太臃肿,要么太简陋。LVGL正好卡在中间——功能丰富,但资源消耗又控制得很好。

LVGL的核心特性包括:

  • 轻量级:最低配置只需要16KB RAM和64KB Flash
  • 丰富的控件:按钮、滑块、图表、列表等30+内置控件
  • 硬件加速:支持帧缓冲和DMA2D加速
  • 多语言支持:UTF-8编码,轻松支持中文
  • 动画系统:内置缓动函数,动画流畅自然
  • 输入设备抽象:触摸、按键、编码器都能用

一句话总结:LVGL就是嵌入式界的Qt,但比Qt轻得多。

1.2 为什么选择LVGL

市面上嵌入式GUI方案不少,比如emWin、TouchGFX、LittlevGL(LVGL的前身)。为什么我推荐LVGL?

先看一个对比:

特性 LVGL emWin TouchGFX
开源免费 ✅ MIT协议 ❌ 商业授权 ❌ 商业授权
最低RAM需求 16KB 32KB 64KB
内置控件数 30+ 20+ 25+
社区活跃度 极高 低 中
学习曲线 平缓 中等 陡峭

我在项目中遇到过几次选型失误。有一次选了某商业GUI库,结果芯片涨价,项目预算被砍,授权费成了大问题。从那以后,我选方案第一原则就是——开源优先。LVGL的MIT协议意味着你可以随意商用,没有任何后顾之忧。

另外,LVGL的社区非常活跃。GitHub上3万+星标,遇到问题基本都能搜到答案。你想想看,一个闭源库出了问题,你只能等厂商回复;而LVGL的问题,可能当天就有人帮你解决了。

我的建议:如果你的项目需要快速迭代、成本敏感、团队规模不大,LVGL是首选。如果项目对实时性要求极高(比如汽车仪表盘),可以考虑TouchGFX,但代价是硬件成本更高。

1.3 LVGL源码获取

获取LVGL源码很简单,我一般用两种方式:

  1. GitHub直接下载:访问 https://github.com/lvgl/lvgl,选择Release版本下载
  2. Git克隆:git clone https://github.com/lvgl/lvgl.git

这里有个坑,我曾经踩过——不要直接拉master分支。master分支是开发版,可能有不稳定的API。我建议拉最新的稳定版tag,比如v8.3.x或v9.x。

LVGL的源码结构大致如下:

lvgl/
├── src/          # 核心源码
│   ├── core/     # 核心对象和事件
│   ├── draw/     # 绘制引擎
│   ├── font/     # 字体处理
│   ├── hal/      # 硬件抽象层
│   ├── misc/     # 工具函数
│   ├── widgets/  # 控件库
│   └── layouts/  # 布局管理
├── examples/     # 示例代码
├── docs/         # 文档
└── lv_conf_template.h  # 配置文件模板

注意:lv_conf.h是LVGL的配置文件,必须根据你的硬件资源裁剪。默认配置是为PC模拟器准备的,直接用在MCU上会爆内存。后面我会详细讲怎么配置。

1.4 开发环境搭建

搭建环境分两种情况:MCU和MPU。我分别说一下。

1.4.1 MCU环境搭建

MCU环境我一般用STM32CubeIDE或Keil。以STM32为例,步骤很简单:

  1. 用STM32CubeMX生成基础工程,配置好时钟和GPIO
  2. 把LVGL源码复制到工程目录
  3. 配置lv_conf.h,打开LV_USE_DEMO等宏
  4. 实现显示驱动和触摸驱动
  5. 在主循环中调用lv_timer_handler()

显示驱动的核心代码就这几行:

// 显示缓冲区
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];

// 初始化显示缓冲区
lv_disp_draw_buf_init(&draw_buf, buf, NULL, LV_HOR_RES_MAX * 10);

// 注册显示驱动
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = my_flush_callback;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);

嗯,这里要注意——flush_cb函数里一定要调用lv_disp_flush_ready(),否则画面会卡死。我刚开始做的时候忘了这步,折腾了一下午。

1.4.2 MPU环境搭建

MPU环境就简单多了。我一般用Linux + SDL模拟器,直接在PC上开发调试,最后再移植到目标板。

PC模拟器搭建步骤:

  1. 安装SDL2库:sudo apt install libsdl2-dev
  2. 下载LVGL的PC模拟器工程:git clone https://github.com/lvgl/lv_port_pc_eclipse.git
  3. 用CMake编译:mkdir build && cd build && cmake .. && make
  4. 运行:./demo

我个人习惯先在PC上把UI布局和交互逻辑调好,再移植到MCU。这样效率高很多,不用每次烧录看效果。

效率技巧:在PC模拟器上开发时,可以用lvgl的在线字体转换工具生成自定义字体,省去在MCU上调试字体的麻烦。

1.5 LVGL知识体系总览

为了让你对LVGL有个整体认识,我画了张图:

LVGL知识体系总览 应用层(UI界面) 控件层(Widgets + Layouts) 核心引擎(对象管理 + 事件 + 动画 + 绘制) 硬件抽象层(显示驱动 + 输入驱动 + 文件系统) 硬件层(MCU/MPU + 显示屏 + 触摸屏) 学习路径建议 从底层往上学 先理解HAL层

这张图展示了LVGL的层次结构。从下往上,每一层都依赖下一层。你想想看,如果硬件抽象层没写好,上面的控件再漂亮也显示不出来。所以我的建议是——先搞定显示驱动和触摸驱动,再谈UI设计。

1.6 本章小结

这一章我们聊了LVGL是什么、为什么选它、怎么获取源码、以及怎么搭建开发环境。说白了,LVGL就是嵌入式UI开发的一把利器,用好了能大幅提升开发效率。

我个人觉得,LVGL最大的优势不是技术本身,而是它的社区生态。你遇到的大部分问题,别人都遇到过。多逛逛GitHub Issues和论坛,能少走很多弯路。