LVGL与MicroPython三个仓库辨析:从绑定到v9固件实战指南
2026/9/10 1:56:43 网站建设 项目流程

一打开 GitHub 搜 LVGL 和 MicroPython,你大概率会看到三个长相极其相似的仓库:lvgl-micropythonlv_micropythonlv_binding_micropython。名字都带 lv 和 micropython,乍看像三个不同项目,实际又好像都在做同一件事。我在群里见过不下十次有人问“这三个到底该 clone 哪个”“怎么有的教程用这个有的教程用那个”,每次解释都要从头讲一遍。这篇直接把这些仓库的来龙去脉、定位差异、选型建议和实操流程一次性说清楚。

先给结论:这三个不是三个并列的独立项目,而是 LVGL 官方在 MicroPython 绑定这条线上一路改版、改名、重构后的产物。lv_binding_micropython是最早的绑定层源码,lvgl-micropython是 v8 时代官方整合出来的全量固件仓库,lv_micropython则是 v9 时代的新主仓,也是现在唯一推荐使用的仓库。接下来逐个拆解。

1. 三个仓库的历史沿革与深层归属关系

1.1 lv_binding_micropython:最早的绑定层,也是所有故事的起点

LVGL 本身是一个纯 C 语言编写的图形库,跑在嵌入式设备上。MicroPython 是运行在微控制器上的 Python 精简解释器。要让 MicroPython 能调用 LVGL 的控件、样式、动画,就得在 Python 和 C 之间架一座桥,把 C 的 API 封装成 Python 可以 import 的模块。这座桥在编程领域一般叫 binding(绑定),lv_binding_micropython就是 LVGL 官方维护的这个桥的源码仓库。

这个仓库很早就存在了,名字里的lv_binding就是这个意思。它内部包含绑定生成器、封装层代码、以及一部分显示驱动的适配代码。在 LVGL v7、v8 早期,官方文档的推荐做法是:把lv_binding_micropython克隆下来,再配合 LVGL 主仓库一起编译。你可以把lv_binding_micropython理解为“半成品”——它给你绑定的骨架,但你要自己把 LVGL 源码、驱动、平台代码整合进自己的构建体系里。

但是这里有个很尴尬的问题:MicroPython 本身对每个开发板(ESP32、STM32、RP2040 等)都有独立的移植工程和构建脚本。你在lv_binding_micropython里做完绑定,还要想办法把它塞进对应板子的 MicroPython 源码树,手动改mpconfigport.hmicropython.mk、CMakeLists 之类的一大堆配置文件。对新手来说,这个过程等于“先学会造轮子,再学会装车”,门槛极高,很多人卡在这里就放弃了。

1.2 lvgl-micropython:v8 时代官方整合出的“一键固件仓库”

正因为lv_binding_micropython的整合成本太高,官方后来弄出了一个新仓库lvgl-micropython。这个仓库的做法很粗暴,也很有用:把 MicroPython 源码、LVGL 源码、绑定层、显示/输入驱动全部打成一个大仓库,你克隆下来之后,执行一条构建命令,就能生成可以直接烧录到开发板上的固件。简单说,lvgl-micropython是一个“全家桶式”的固件工程,而不是单纯的绑定层。

lvgl-micropython最活跃的时期是 LVGL v8 时代,也就是 2021 到 2023 年前后。那个时期网上大部分 ESP32 跑 LVGL 的教程、视频、CSDN 文章,用的都是这个仓库。仓库里带着 ESP32、STM32 等平台的移植文件,还配套了lv_drivers(当时官方独立的驱动库,主要支持几个主流屏幕控制器和触摸控制器)。使用体验确实比lv_binding_micropython好很多,至少不用自己拼拼图了。

但也因为什么都塞在一起,仓库体积膨胀得很厉害,MicroPython 上游版本升级时,这个仓库的同步总比官方慢半拍。而且lvgl-micropython对 LVGL 版本绑得很死,升级 LVGL 版本往往要动不少底层代码,维护成本越来越高。所以当 LVGL 进入 v9 之后,官方干脆对这个仓库做了“归档处理”(GitHub 上标注 Archived,只读不再维护)。如果你现在去搜lvgl-micropython,会发现仓库首页有条醒目的提示,让你迁移到新仓库lv_micropython

1.3 lv_micropython:v9 时代的新主仓,统一且长期维护

lv_micropython是 LVGL 官方从 2023 年开始强推的新仓库,也是现在一切 LVGL + MicroPython 开发的主入口。它本质上并非完全新建,而是把lvgl-micropythonlv_binding_micropython的能力合并、重构,然后以更清晰的工程结构重新发布。

新仓库有这几个明显变化:

第一,LVGL 源码不再直接拷贝进仓库,而是用git submodule的方式引用。构建时自动拉取指定版本的 LVGL,仓库体积小得多,版本切换也更干净。你在仓库目录下会看到一个lib/lvgl子目录,它其实是指向lvgl/lvgl仓库的链接。

第二,驱动层大换血。放弃了老的lv_drivers,改用 LVGL 官方新的驱动接口,各种显示器、触摸芯片通过lv_conf.py(注意后缀是.py)统一配置。这个 python 配置脚本会在构建时生成对应的头文件,灵活性比之前强很多。

第三,构建系统化。lv_micropython提供一个make.py脚本,支持多种目标平台,常见的是esp32stm32raspberrypiwindowslinux等。你执行一条命令就能从源码构建固件,体验上接近常规的嵌入式 SDK。

第四,分支策略明确。master分支对应 LVGL v9(现在新功能都往上推),另有release/v8之类分支维护老版本。如果你在网上找到的教程是基于 v8 的,也能在新仓库里找到对应分支继续用,不会一下被抛弃。

一句话总结:想了解历史、看老代码,去lv_binding_micropythonlvgl-micropython;想正常做项目,直接用lv_micropython

2. 三个仓库的定位差异与选型建议

2.1 仓库定位对照表

为了方便大家快速判断,我把三个仓库的核心差异整理成了一张表:

仓库名当前状态核心定位适合使用的时机LVGL 版本
lv_binding_micropython维护中,但偏底层绑定层源码,不直接提供完整固件想研究绑定原理、二次开发绑定层的人基本跟随主线
lvgl-micropython已归档(Archived)v8 时代全家桶固件工程只能跑老教程、老项目,不推荐新开固定 v8.x
lv_micropython活跃维护中官方主推的固件工程所有新项目、v9 开发、跨平台模拟v9 / v8 分支

这里有个容易踩的坑:很多人看到lv_binding_micropython名字里带“binding”,以为它就是“官方绑定库本体”。严格说它确实是本体,但在 v9 时代,lv_micropython已经把绑定层整合进工程里了。你再去单独 clonelv_binding_micropython反而不好用,因为它的构建说明、依赖关系都还停留在老一套逻辑上,直接套用会踩不少坑。

2.2 新手选型:无脑选 lv_micropython

我给不同人群的选型建议是:

  • 如果你完全没接触过 LVGL 和 MicroPython,想快速在 ESP32 上点个灯、显示个 UI,直接看lv_micropython的 README,照着编译烧录,不要碰另外两个仓库。你不需要理解绑定层到底怎么工作的,把它当成一个“带图形库的 MicroPython 固件”来用就行。
  • 如果你是做产品原型、毕业设计、个人项目,同样用lv_micropython,但建议先看一眼lv_micropython/lib/lvgl指向的 LVGL 版本,然后以该版本的官方文档为准学习 API。
  • 如果你确实对“Python 怎么调用 C 库”这件事感兴趣,或者想往 MicroPython 里加别的 C 库,可以拿lv_binding_micropython当参考案例,看它怎么注册模块、封装函数、转换类型。但这个仓库代码结构比较复杂,不建议入门阶段死磕。
  • 如果你拿到一块老的开发板,网上只有基于 v8 的使用例程,可以翻lv_micropythonrelease/v8分支。这个分支的存在,比老仓库lvgl-micropython更值得用,因为至少还有人在维护。

2.3 为什么官方要反复改名:从“零散组件”到“一体化方案”

很多人不理解,为什么不能干脆只保留一个仓库,非要弄出三四个名字,导致搜索和沟通成本极高。实际上,这是开源项目演进过程中的常见现象,尤其在图形库这种依赖链条比较长的项目里。

lv_binding_micropython的角色是“可复用组件”,服务对象是各个平台移植工程、以及想自定义绑定的人。lvgl-micropython的角色是“集成示例”,它证明了“MicroPython + LVGL + 驱动”这条路能走通,但因为是早期整合,代码质量和可维护性赶不上正规产品。lv_micropython的角色则是“官方正式产品”,代表官方希望用户直接使用的一体化方案。

名字相似确实容易混淆,但理解了它们的定位,就不会再被绕晕。我自己的习惯是:谈论绑定原理时叫lv_binding_micropython,谈论构建固件时叫lv_micropython,绝不把lvgl-micropython推荐给新项目。

3. 实操:在 ESP32 上从零构建 LVGL + MicroPython 固件

3.1 以 lv_micropython 为例,准备好构建环境

因为新项目都该用lv_micropython,下面所有操作都基于这个仓库。先说明,构建过程会涉及 ESP-IDF 和 MicroPython 的交叉编译工具链,第一次操作需要点耐心,但流程非常固定。

我实验过的推荐环境:

  • 操作系统:Ubuntu 22.04(或 WSL2 里的 Ubuntu),Windows 原生也能搞但坑多一些
  • Python:3.8 以上,需要pip可用
  • 构建/编译工具:gccmakecmakegit
  • ESP-IDF:lv_micropython构建 ESP32 固件时需要 ESP-IDF,版本要求以仓库 README 为准

有两点特别提醒:

第一,不要把lv_micropython直接放在桌面上构建,路径里不要有中文和空格,很多编译脚本对路径非常敏感。第二,ESP-IDF 的安装会下载大量工具链,网络不稳定时容易失败,建议先确认能稳定访问 GitHub 和乐鑫的下载服务器。

3.2 克隆仓库并初始化子模块

lv_micropython并不像普通仓库那样 clone 完就能编译,因为 LVGL 本体是用 submodule 引用的。正确的克隆方式:

git clone https://github.com/lvgl/lv_micropython.git cd lv_micropython git submodule update --init --recursive

如果你忘了执行git submodule update,后面构建时会出现找不到 LVGL 源码的报错,而且这种报错往往会指向lib/lvgl目录为空。我见过有人卡在这里很久,其实只要补上这一句就行。

如果想要 v8 分支而不是 v9,执行:

git checkout release/v8 git submodule update --init --recursive

官方主推master,除非你确有兼容需求,否则建议留在master

3.3 使用 make.py 构建 ESP32 固件

lv_micropython的构建入口是make.py。以 ESP32(经典版)为例:

python make.py build esp32

这个命令执行时,会先检查 ESP-IDF 环境。如果你还没设置 ESP-IDF 的导出脚本(通常要在终端 source 一下),这里就会报错。常见的是:

export IDF_PATH=~/esp/esp-idf source $IDF_PATH/export.sh python make.py build esp32

如果你用的是 ESP32-S3、ESP32-C3 这类芯片,命令稍有区别。例如:

python make.py build esp32 -m ESP32S3

不同版本仓库对参数的定义可能调整,最稳妥的办法是执行python make.py build --help看当前支持哪些平台和参数。

构建成功后,会在build/esp32目录下生成固件文件,通常是firmware.bin。整个过程如果网络好、环境干净,大约需要十几分钟到半小时。如果编译中途报错,九成是依赖没装全,对照官方 README 里的 prerequisites 一项项确认。

3.4 烧录固件到开发板

烧录 ESP32 固件有几种方式,个人推荐直接用 esptool:

python -m esptool --port /dev/ttyUSB0 write_flash 0x0 build/esp32/firmware.bin

注意,这里烧录地址用的是0x0,因为lv_micropython生成的firmware.bin是包含了整个 MicroPython 固件(包括 bootloader、分区表、应用)的合并镜像。如果你用 Micropython 官方固件,就要按官方文档用0x1000之类地址,但这里不用纠结,直接0x0整片写入即可。

烧录完成后,用任何串口工具(我用的是minicom或 VS Code 的 Serial Monitor)连接开发板,波特率 115200,应该能看到 MicroPython 的 Python REPL 提示符:

>>> import lvgl as lv

如果这一行不报错,说明 LVGL 已经成功内置进固件里了。接下来写任何 UI 代码都是 Python 层的活儿了。

3.5 快速体验:不买硬件也能跑 LVGL

很多想要快速验证自己 UI 思路的人,不一定手头有 ESP32 屏幕。lv_micropython官方其实支持模拟器构建,就是编译出一个可以在电脑上运行的 LVGL+Micropython 程序。这种方式对应很多人搜的“lvgl模拟器”或“vscode 模拟器”。

在 Linux 下构建:

python make.py build linux

在 Windows 下(需要 MSYS2 或 MinGW 环境)可以尝试windows平台:

python make.py build windows

构建成功后运行生成的可执行文件,会弹出一个窗口,里面就是 LVGL 的渲染界面。你甚至可以在里面跑 Python 脚本,实时看控件布局效果,比反复烧录 ESP32 快得多。

我个人的做法是:在模拟器里把页面布局、颜色、交互逻辑全部调好,再同步到开发板跑真实触摸校准。这样能把开发周期缩短一半以上,强烈推荐。只不过模拟器里没有真实触摸屏,手势和触摸坐标只能靠鼠标模拟,真机调试时还是少不了一轮适配。

4. 常见问题与排查技巧实录

4.1 编译报错找不到 lv_conf.h

lvgl-micropython(老仓库)时,经常遇到编译时提示找不到lv_conf.h。这是因为 LVGL 的配置文件需要用户自己提供,老仓库默认不携带。新仓库lv_micropython已经处理了这个问题,它用lv_conf.py在构建时自动生成配置项。

如果在新仓库里还是遇到配置相关问题,大概率是你改了lv_conf.py里某个宏的名字写错了。LVGL 的配置宏命名都非常规范,比如颜色深度是LV_COLOR_DEPTH、内存大小是LV_MEM_SIZE,但不排除版本迭代时会改名字。报错时不要只看 error 那一行,向上翻几行,往往有提醒“unknown config option”之类的信息。

提示:不要直接修改lib/lvgl/lv_conf_template.h,LVGL 升级时这个文件会被覆盖。所有自定义配置都写在lv_conf.py里,由构建脚本生成最终的头文件。

4.2 屏幕白屏或显示花屏

白屏基本能确定是背光、初始化或配置不匹配的问题。优先检查三处:

  • lv_conf.py里的LV_COLOR_DEPTH,如果你的屏幕是 RGB565,就设置成 16;如果是 RGB888,就设置成 24 或 32。设置不对,画面会偏色、花屏甚至不显示。
  • 屏幕的分辨率设置,一定要和面板真实分辨率一致。比如 SSD1306 的 OLED 是 128x64,你写成 128x32,显示区域就会被截断或者偏移。
  • 背光引脚和复位引脚的配置。很多屏幕模块的背光(BLK)和复位(RST)需要接到 ESP32 的 GPIO 上,并在驱动配置里指定。如果背光引脚没配置,屏幕会亮但什么都看不见,这时候测试一下背光脚电压就能排查出来。

4.3 触摸没反应或者坐标完全不对

屏幕能显示了,但触摸不对,这个在 LVGL + MicroPython 里非常常见。触摸问题分三类:

一类是驱动压根没加载。检查lv_conf.py里的输入设备驱动是否启用,是否选对了触摸芯片型号。我见过有人用的是 XPT2046 触摸屏,结果配置里写的是 FT6X36,那肯定读不到数据。

一类是 I2C 地址不对。很多触摸芯片有多个 I2C 地址,比如0x380x48等,取决于模块上地址电阻的接法。先用 I2C 扫描脚本确认设备地址,再填进配置,这是最稳妥的。

还有一类是坐标旋转和翻转问题。屏幕物理方向、显示方向、触摸坐标方向的对应关系很容易搞错。LVGL 里可以通过lv_display_set_rotation或单独配置触摸的swap_xymirror_xmirror_y来修正。调试时可以在屏幕上显示触摸点坐标,点几个角,看看坐标是否有规律地偏移,然后决定翻转哪一轴。

4.4 内存不足导致控件创建失败

跑 LVGL 的程序,动辄创建几十个控件,内存不足是常态。尤其在 ESP32-S3 这种 SRAM 不算大的芯片上,很容易出现lv_mem相关的报错。

解决思路有三个:

  • 增大lv_conf.py中的LV_MEM_SIZE,但要确保芯片剩余 RAM 够用。
  • 缩小显示缓冲区。LVGL 允许缓冲只占屏幕的一部分,比如 1/10 屏大小,虽然刷新率会略降,但能省大量内存。
  • 检查和释放不用的对象。LVGL 里lv_obj_delete是显式删除,Python 的垃圾回收不直接管 LVGL 对象,这个要注意。

实测中,一个带几个页面、几十个控件的界面,把LV_MEM_SIZE设在 64KB 左右,配合 40x40 的小缓冲,在 ESP32 经典款(320KB SRAM)上跑得很稳。

4.5 老教程迁移到 v9 的典型报错

很多网上的 v8 教程代码直接拿到 v9 会报AttributeError,比如lv.obj在 v9 中改成了lv.obj_create()lv.label改成了lv.label_create()。这个我一开始也不适应,习惯 v8 的简洁风格。v9 的更强调显式父对象和创建方法,整体上更接近 C API 的原始语义。

如果你手里有大量 v8 代码,先别急着全改,建议重新梳理一遍官方迁移指南(lv_migrating_to_v9.md)。许多 API 只是换了个名字,替换成本并不高。但也有少数行为差异,比如事件处理、样式回调、动画参数的默认值,这些改起来需要一点耐心。

5. 围绕 LVGL 高频热词的实际场景补充

5.1 “lvgl容器”到底指什么?

很多人搜“lvgl容器”,其实是想知道怎么把多个控件放进一个整体里统一管理位置、统一移动、统一滚动。这里说的容器,在 LVGL 里就是lv_obj,也就是“对象”。LVGL 里几乎所有控件都是lv_obj的子类,而一个lv_obj也可以作为父对象去容纳其他控件。

创建容器很简单:

import lvgl as lv cont = lv.obj(lv.scr_act()) # 在活动屏幕上创建容器 cont.set_size(200, 150) # 设置容器大小 cont.center() # 居中显示

容器最有用的地方是布局管理。LVGL 内置了 Flex 和 Grid 两种布局,可以让子控件自动排列,不用手动计算坐标。比如做横向排列的菜单:

cont.set_layout(lv.LAYOUT_FLEX.ROW)

子控件就会从左往右自动排开。容器还能开启滚动,子控件太多超出容器范围后,可以用手指或鼠标滚动浏览。整个界面设计如果从一开始就用容器分层,后期调整布局会省很多事。

5.2 “lvgl怎么启动”有没有标准流程?

新手第一次接触 LVGL + MicroPython 时,最迷茫的是“我写完了控件代码,怎么让画面开始渲染?”在老版本里,需要手动写一个循环调用lv.timer_handler()或者lv.task_handler(),间隔几毫秒刷一次。这个循环是 LVGL 的心跳,没有它,界面不会自动刷新。

在 v9 里情况变了。LVGL 内部集成了定时器调度,你只需要保证 MicroPython 的顶层不退出、同时让出执行权即可。官方推荐用lv_utils模块的loop管理:

import lvgl as lv from lv_utils import event_loop loop = event_loop() # 启动 v9 的事件循环

之后你创建控件、绑定事件,界面就会自动重绘。这种方式比手写 while 循环优雅得多,而且不会阻塞其他 MicroPython 任务。如果你用了uasyncio,也可以在异步任务里让 LVGL 的循环和你的业务协程共存。

5.3 “lvgl当前时间控件”怎么实现?

LVGL 没有内置一个叫“当前时间”的专用控件。它提供的lv_label(标签)组件就是最常用、最推荐用来显示时间的。实现思路是:创建一个标签,然后用lv_timer每秒更新一次文本。

import lvgl as lv time_label = lv.label(lv.scr_act()) time_label.set_text("00:00:00") time_label.center() def update_time(timer): import time t = time.localtime() txt = "{:02d}:{:02d}:{:02d}".format(t[3], t[4], t[5]) time_label.set_text(txt) timer = lv.timer_create(update_time, 1000, None)

每隔 1000 毫秒(1秒),回调函数刷新一次标签文本。如果要做日期、星期几,同样往字符串里拼就行。做数字时钟其实就这么点东西,不需要额外依赖任何库。

5.4 “esp32 s3 oled micropython”怎么连起来用

这一组热词其实对应的是很经典的开发组合:ESP32-S3 + 小尺寸 OLED(常见 SSD1306 或 SH1106)+ MicroPython。有了lv_micropython固件后,OLED 在 LVGL 里的接入也分两步。

第一步,在lv_conf.py里启用 SSD1306 驱动,配置 I2C 总线、地址、分辨率。比如:

SSD1306 = 1 SSD1306_I2C_ADDR = 0x3C

第二步,在 Python 代码里初始化显示驱动,然后交给 LVGL:

import lvgl as lv # 这里假设驱动初始化函数已经注册到 LVGL disp_buf = lv.disp_buf_create() lv.init()

有些固件默认集成了便捷的显示屏初始化函数,可以直接调用,具体看lv_conf.py里驱动配置的注释。OLED 因为分辨率低、接口速度有限,跑复杂动画会有性能瓶颈,但显示简单的仪表盘、时间、菜单完全足够。

写在最后的一些经验

我踩过最大的坑,就是一开始没搞清仓库关系,照着老教程用lvgl-micropython建了一个项目,结果 LVGL 版本是 v8,后来想跟着官方新文档学习 v9 的 API,代码对不上,全部重写。所以第一步选对仓库,比什么都重要。

另外想提醒的是,lv_micropython的构建流程虽然已经尽量自动化,但不同版本之间命令细节会变,网上的文章未必跟你 clone 到的仓库完全对应。遇到问题先看仓库里的 README 和make.py --help,再动手折腾,这是最靠谱的路径。

如果你只是想在桌面上验证 UI 想法,模拟器绝对是效率神器。我在 Linux 上跑linux平台的模拟器,配合 VS Code 写代码,几乎能在几个小时内完成一个页面的交互原型,然后才烧到 ESP32 上调真实时序。希望这篇能帮你少走几个月的弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询