[ LVGL ] 入门
一、简介定位
LVGL(Light and Versatile Graphics Library,轻量多功能图形库) 是一个专为资源受限的嵌入式设备打造的开源 GUI 框架,像 STM32、RTOS、裸机系统都能用。它能帮你 快速搭建像手机 App 那样的漂亮界面,但内存占用却非常小,适合用在小 MCU 上。按钮、滑块、动画、触摸响应这些功能,LVGL 都已经帮你封装好了 —— 就像你在做一个嵌入式 App,而不是一块板子上的界面。
二、运转机制
(一)引擎架构
要让 LVGL 跑起来,本质上只靠三样东西:输入、输出、时间。你把这三样供上,剩下的事它全包 —— 包括界面构建、事件响应、动画刷新,全流程自动完成。
具体来看,这三样分别对应:
-
输入接口(Input): 接收用户操作(触摸、按键),就像用户在说话,LVGL 靠它来听懂。
-
显示驱动(Display): 把界面内容画到实际的 LCD 上,LVGL 像设计师出图纸,驱动像粉刷匠照图刷墙,而你(开发者)是施工队长,负责搭接口、发指令,让图纸变成现实。
-
时间驱动(Tick): 通过定时调用 lv_timer_handler() 提供时钟节拍,相当于给系统上发条,不上发条,动画和事件就不会动。
此外还有两个内部模块也很关键:
-
控件树(Widget Tree): 界面控件按父子结构组织,像套娃一样层层嵌套,逻辑清晰,便于管理。
-
事件与动画系统: 操作触发事件、控件响应动作,动画播放平滑流畅,交互体验全由 LVGL 接手处理。
你喂它输入、输出、时间,它就能全自动完成响应用户 → 更新控件 → 显示界面这一整套链路。简单来说:输入进来 → LVGL 处理 → 显示出来,以下是该流程的示意图:
那么问题来了 —— 你喂给 LVGL 的时间到底是干什么用的?其实,每次界面要动起来、动画要刷新、控件要响应事件,背后都是靠你定时调用的那个函数:lv_timer_handler()
。它就像 LVGL 的主心跳,每调一次,系统就动一下,把界面该处理的事都安排一遍。
(二)循环剖析
在 LVGL 里,有一个核心函数叫 lv_timer_handler()
,你需要定时调用它,比如每 5 毫秒跑一次。可以把它看作是 LVGL 的心跳或 大脑主循环,每调用一次,LVGL 就完成一轮处理流程。
那么这一轮都干了什么?大致包括这些:
- 读取输入设备: 看看用户有没有点触摸屏、按了按键;
- 刷新显示内容: 如果有控件变了,或者该重画了,它就会触发重绘;
- 处理动画效果: 比如按钮弹一下、滑块滑动等;
- 触发事件回调: 如果某个控件注册了点击之类的事件,就会在这里被触发;
- 执行用户定时器: 你自己加的
lv_timer_t
类型的定时器,也会在这一步统一调度。
lv_timer_handler()
是 LVGL 运转的中枢,你 定时调它,LVGL 就能自动响应输入、刷新控件、播放动画、执行定时任务。你只要提供输入、输出、时间,设计好界面,剩下的活它全能安排。
通俗点说,你一喊开始下一轮,LVGL 就立刻检查一下有没有人敲门(输入)、该不该刷墙(显示)、是不是有人预约了任务(定时器),然后自己把事情干完。
(三)开发范式
开发者如何真正让 LVGL 跑起来?其实流程非常清晰,只需掌握三个核心步骤:
- 初始化: 先初始化 LVGL 本身,并接好输入设备、显示驱动、定时器等接口;
- 构建界面: 使用 LVGL 提供的控件系统搭建 UI 界面,比如按钮、标签、图标等;
- 注册事件回调: 为控件绑定事件回调,例如按钮点击后要执行什么功能;
其余流程(包括界面重绘、动画播放、事件分发、控件管理等)都由 LVGL 内部自动完成。你只需专注于控件的创建与逻辑设计,事件调度、绘制更新、动画执行等细节将由 LVGL 自动管理。但请注意,控件对象的销毁仍需开发者显式处理,除非使用自动屏幕切换机制。
总之,你搭好舞台,演员安排好,灯光和时间也交代清楚,然后就让 LVGL 自己演出就行了。
三、关键概念
(一)显示设备和显示对象
你看到的显示设备与你操作的显示对象
概念 | 解释 |
---|---|
显示器(Display Panel) | 这是实际的屏幕硬件,也就是你用来“看”界面的那个物理设备,比如 LCD、OLED 屏。 |
显示对象(lv_display_t ) | 这是 LVGL 内部在内存中创建的一个结构体对象,用来管理和控制显示器,比如负责把图像“画”到屏幕上。 |
屏幕(Screen) | 是一个没有父级的根 Widget,代表一整套用户界面。它附加在某个显示对象上,用于展示你设计的各种控件。 |
🔎 提示: 当你第一次创建一个 lv_display
显示对象时,它会自动成为默认显示。之后很多 LVGL 的函数(比如设置哪个屏幕当前显示)会自动使用这个默认显示对象,不需要你手动指定。这让开发流程更简洁,尤其是大多数项目只用一个屏幕时。
(二)控件(Widget)
Widget 是 LVGL 中的核心概念,它们是构建 UI 的基本单元,也是用户可以交互的图形控件。例如按钮、标签、滑块、图表等,都是用 lv_obj_t*
表示。
示例:创建滑块控件示例
lv_obj_t * slider1 = lv_slider_create(lv_screen_active());
// 设置滑块控件属性:
lv_obj_set_x(slider1, 30);
lv_obj_set_size(slider1, 200, 50);
lv_slider_set_value(slider1, 70, LV_ANIM_ON);
示例:删除滑块
lv_obj_delete(slider1);
(三)控件组织结构
Widget 可以相互嵌套使用。
每个 Widget 都有一个父对象。
父子 Widget 之间具有关联关系:
-
子控件位置相对于父控件;
-
删除父控件将级联销毁其所有子控件;
-
超出父控件区域的内容将被裁剪隐藏。
示例:创建标签控件并加载为屏幕
// 创建一个屏幕对象
lv_obj_t * screen = lv_obj_create(NULL);
// 在屏幕上创建标签
lv_obj_t * label = lv_label_create(screen);
lv_label_set_text(label, "Hello, LVGL!");
// 将该屏幕设为当前活动屏幕
lv_screen_load(screen);
(四)屏幕切换与管理
使用以下函数可切换当前显示的活动屏幕:
lv_screen_load(new_screen);
如果你希望在切换屏幕时自动删除旧的屏幕和其子控件,可使用带动画的方式并设置自动删除参数:
// 自动删除旧屏幕
lv_screen_load_anim(new_screen, ..., true);
支持多个屏幕缓存在内存中,便于快速切换或缓存复杂界面,提升性能。
四、事件系统
LVGL 支持将事件回调函数绑定到控件上,响应用户交互:
void my_btn_event_cb(lv_event_t * e)
{
printf("Button clicked\n");
}
lv_obj_add_event_cb(btn, my_btn_event_cb, LV_EVENT_CLICKED, NULL);
常见事件类型包括:
-
LV_EVENT_PRESSED
-
LV_EVENT_RELEASED
-
LV_EVENT_CLICKED
-
LV_EVENT_ALL
(监听全部事件,便于调试)
五、部件与状态
(一)部件(Part)
控件通常是由多个部件组成的,例如滑块控件包含:
- 主体:
LV_PART_MAIN
- 指示条:
LV_PART_INDICATOR
- 按钮:
LV_PART_KNOB
你可为每个部件设置独立样式,实现细粒度美化。
(二)状态(State)
控件可处于一种或多种状态的组合中,常见状态如下:
状态宏 | 描述 |
---|---|
LV_STATE_DEFAULT | 默认状态 |
LV_STATE_CHECKED | 被选中 |
LV_STATE_FOCUSED | 获取焦点 |
LV_STATE_PRESSED | 正在按压 |
LV_STATE_DISABLED | 已被禁用 |
示例:检查与设置状态
// 检查是否处于某状态
bool is_focused = lv_obj_has_state(widget, LV_STATE_FOCUSED);
// 添加状态
lv_obj_add_state(widget, LV_STATE_CHECKED);
// 移除状态
lv_obj_remove_state(widget, LV_STATE_PRESSED);
六、样式
LVGL 样式(lv_style_t
)定义控件视觉外观:背景色、边框、字体、透明度等。
完整设置流程
// 声明一个静态的样式对象style,用于配置UI组件的主体样式
static lv_style_t style;
// 初始化样式对象style,确保样式结构体处于可用状态
lv_style_init(&style);
// 设置style的背景颜色为十六进制值0x2080bb所代表的蓝色
lv_style_set_bg_color(&style, lv_color_hex(0x2080bb));
// 将配置好的style样式应用到指定的widget组件的主体部分(LV_PART_MAIN)
lv_obj_add_style(widget, &style, LV_PART_MAIN);
快捷设置单一属性
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff0000), LV_PART_INDICATOR);
样式继承机制: 属性缺省时,控件会向父控件查找继承。
七、主题
LVGL 支持主题机制:为所有控件预设统一样式。
主题配置通过 lv_conf.h
编译配置文件控制,便于整体风格统一与自定义美化。
八、MicroPython 支持
LVGL 提供完整的 MicroPython 绑定,适用于快速原型设计和高效迭代开发。
示例:创建按钮和标签
import display_driver
import lvgl as lv
scr = lv.obj()
btn = lv.button(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Hello World!")
lv.screen_load(scr)
九、总结
LVGL 是一个功能强大、设计精巧、资源友好的嵌入式图形界面解决方案,无论是小型 MCU(如 STM32),还是 Linux 平台下的 SoC 系统,均可适配使用。通过其高效架构和丰富控件体系,开发者可高效构建现代化的嵌入式 GUI 应用。
如需进一步学习与实践,推荐参考以下资料:
愿你用得顺手,做出惊艳界面!