news 2026/10/29 3:47:44

LVGL V1.3 移植实战:STM32 从白屏到点亮第一屏

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LVGL V1.3 移植实战:STM32 从白屏到点亮第一屏

简介:这份《LVGL开发指南》中文V1.3版面向嵌入式开发者与STM32学习者,聚焦在资源有限的微控制器上构建图形用户界面这一核心问题。内容以正点原子STM32开发板为实践平台,从初识LVGL、移植要求与源码获取讲起,依次覆盖无操作系统移植、带FreeRTOS等操作系统移植、PC模拟器使用及移植相关知识,并延伸到UI元素创建、动画交互与性能优化等应用开发环节,适合具备一定单片机基础、希望系统掌握LVGL的中级读者按章节循序渐进学习。资源包共1个PDF文件,大小约9.54MB,单文件即完整承载教程正文与例程说明,便于离线阅读和随查随用。目前已有764人学习下载,可作为嵌入式GUI入门与移植实践的参考手册。

1. 从一块白屏说起:LVGL V1.3 移植到底卡在哪

上周帮一个做工业面板的朋友看板子,STM32F407 加 3.5 寸屏,代码烧进去屏幕全白,串口一行日志都没有。他以为屏坏了,换了三块屏还是白。最后发现是lv_conf.h里颜色深度填了 32,而他的屏驱动按 RGB565 走,LVGL 画出来的缓冲区格式和 DMA 送出去的数据对不上,画面自然是一片白。这种坑在嵌入式 GUI 移植里太常见了,LVGL 本身不难,难的是版本、配置、驱动接口这三样东西必须严丝合缝地对上。

这份《LVGL 开发指南》中文 V1.3 是围绕 STM32 开发板写的移植教程,2023 年 1 月更新过例程功能,内容从无操作系统移植、FreeRTOS 移植一直讲到 PC 模拟器和部件实验。适合手里有 STM32 板子、想把 LVGL 跑起来做界面的开发者,也适合先在 PC 模拟器上把界面逻辑调通再往板子上搬的人。下面按我实际装环境的顺序,把版本选择、工程搭建、配置修改、验证排错一层层拆开。

2. 装前把环境列清:LVGL V1.3 的版本与工程底座

2.1 先定 LVGL 版本,别拿最新版套旧教程

这份指南的例程是按 LVGL 8.x 的 API 写的,V1.3 修订时间在 2023 年初,那时候 8.x 还是主流。如果你直接从仓库拉最新代码,很可能碰到lv_disp_drv_register参数变化、lv_img_dsc_t结构体字段调整这类问题,教程里的代码贴进去编译不过。我的做法是先把版本锁死,再动工程。

常见做法是从 LVGL 的 release 页面找 8.3.x 的稳定包,解压后只取lvgl根目录、lvgl/src、lvgl/examples这几块。不要整个仓库拖进 Keil 工程,里面有一堆 CI 脚本和文档,编译时会拖慢索引。目录结构建议这样放:

Project/ ├── Core/ ├── Drivers/ ├── LVGL/ │ ├── lvgl/ # 库源码,含 src、examples │ ├── lv_conf.h # 从 lv_conf_template.h 复制改名 │ └── lvgl_port/ # 自己写的显示和输入驱动 └── MDK-ARM/

lv_conf.h不要放在lvgl目录里面,放在外面一层,这样升级库版本时配置文件不会被覆盖。这一点教程里提过,但很多人图省事直接改模板文件,后面换版本就哭了。

2.2 硬件与工具链的最低要求

指南面向的是 STM32 全系开发板,但实际能不能跑起来,看三个硬指标:Flash 至少 128KB、RAM 至少 64KB、屏幕有可用的刷屏接口(FSMC、SPI 或并口都行)。LVGL 8.x 开基础部件加默认字体,代码体积大概 60 到 100KB,帧缓冲区按 1/10 屏幕大小算,320×240 的屏用 RGB565 需要 320×24×2 约 15KB,双缓冲翻倍。RAM 低于 64KB 的型号建议先砍部件、关动画。

工具链这边,Keil MDK 5 加 STM32CubeMX 生成底层初始化是最省事的组合。CubeMX 负责把 FSMC 或 SPI、DMA、时钟树配好,生成工程后再往里加 LVGL 源码。注意 CubeMX 生成的main.c里SystemClock_Config别被后续手改覆盖,我见过有人加 LVGL 时把时钟配置整段替换掉,结果屏刷得极慢,还以为是 LVGL 性能差。

项目建议值说明
LVGL 版本8.3.x与 V1.3 教程例程匹配
颜色深度16(RGB565)与多数屏驱动一致
帧缓冲屏幕的 1/10内存紧张时再降
编译器Keil MDK 5 / GCC教程以 Keil 为主
RTOSFreeRTOS 可选带系统移植章节单独讲

2.3 工程文件怎么加才不乱

把lvgl/src下所有.c文件加进工程时,Keil 的 Add Group 一个个点太慢。我一般按目录建 Group:lvgl/core、lvgl/draw、lvgl/font、lvgl/widgets,然后把对应目录的源文件批量加进去。lvgl/examples只在跑官方例程时加,正式项目里删掉,能省不少编译时间。

头文件路径要加三条:LVGL/lvgl、LVGL(为了找到lv_conf.h)、LVGL/lvgl/src。少加一条就是满屏的cannot open source input file "lv_conf.h"。加完之后先别急着编译,把lv_conf.h里LV_CONF_INCLUDE_SIMPLE这个宏打开,它让 LVGL 用简单路径找配置文件,省得在编译选项里绕。

3. 无操作系统移植:从加文件到点亮第一屏

3.1 lv_conf.h 里必须先改的五个参数

lv_conf.h是从lv_conf_template.h复制来的,开头有个#if 0要改成#if 1,否则整个文件不生效,这是第一个坑。改完之后重点看这几项:

#define LV_COLOR_DEPTH 16 // 与屏驱动位深一致,RGB565 填 16 #define LV_MEM_CUSTOM 0 // 用 LVGL 自带内存池 #define LV_MEM_SIZE (32U * 1024U) // 内存池大小,按 RAM 余量调 #define LV_DISP_DEF_REFR_PERIOD 30 // 刷新周期 ms #define LV_USE_LOG 1 // 调试期打开日志

LV_COLOR_DEPTH填错就是开头那个白屏案例,屏是 16 位就填 16,别看着电脑显示器 32 位就跟着填。LV_MEM_SIZE给 32KB 是保守值,界面部件多、图片多的时候要往上加,加完记得看链接后的 RAM 占用,别把栈挤爆。LV_USE_LOG打开后配合LV_LOG_LEVEL设成LV_LOG_LEVEL_WARN,移植阶段能看到初始化失败的提示,比盲猜强。

3.2 显示驱动:flush_cb 是整条链路的咽喉

LVGL 不直接操作屏幕,它把画好的缓冲区交给你写的flush_cb回调,由你把数据送到屏上。这个回调写不对,前面配置全白搭。典型实现是这样:

static void disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { uint32_t w = area->x2 - area->x1 + 1; uint32_t h = area->y2 - area->y1 + 1; /* 按屏的坐标窗口设置,再把 color_p 里的 w*h 个像素写进去 */ LCD_SetWindow(area->x1, area->y1, area->x2, area->y2); LCD_WriteData((uint16_t *)color_p, w * h); lv_disp_flush_ready(drv); // 必须调用,否则 LVGL 一直等 }

lv_disp_flush_ready这行是血泪经验,漏掉它界面只会刷第一帧然后卡死,因为 LVGL 以为上一次刷新还没完成。如果用的是 DMA 传输,要等 DMA 完成中断里再调这个函数,不能在启动 DMA 后立刻调,否则缓冲区被下一帧覆盖,画面会撕裂。注册驱动时把缓冲区地址、宽高、flush 回调填进lv_disp_drv_t,再lv_disp_drv_register。

3.3 时基和任务处理:两个函数决定界面活不活

LVGL 需要知道时间流逝,还要定期处理自己的任务。无操作系统时,这两件事放在SysTick中断和主循环里:

void SysTick_Handler(void) { HAL_IncTick(); lv_tick_inc(1); // 每 1ms 告诉 LVGL 过了一毫秒 } while (1) { lv_task_handler(); // 主循环里反复调用 HAL_Delay(5); }

lv_tick_inc的调用频率要和实际毫秒数对上,放错位置或者频率不对,动画会忽快忽慢,触摸响应也会飘。lv_task_handler的调用间隔决定界面刷新节奏,5ms 一次比较稳,太频繁浪费 CPU,太稀疏按钮按下去半天没反应。这两处是移植后界面“能动但不对劲”的高发区。

3.4 输入设备注册:触摸坐标对不上先查这里

触摸屏接进来后要注册输入设备,读点函数返回原始坐标,LVGL 再按显示分辨率映射。常见问题是点左边响应右边,多半是坐标没做方向转换或者 x/y 反了。读点回调里把原始值读出来,必要时交换或取反:

static void touch_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { uint16_t x, y; TP_Read(&x, &y); >void lvgl_task(void *pvParameters) { while (1) { lv_task_handler(); vTaskDelay(pdMS_TO_TICKS(5)); } } /* 创建时优先级低于通信任务,高于空闲任务 */ xTaskCreate(lvgl_task, "lvgl", 2048, NULL, 3, NULL);

vTaskDelay的 5ms 和裸机里的HAL_Delay(5)作用一样,但这里让出了 CPU,其他任务能跑。如果发现界面刷新时串口丢数据,说明 LVGL 任务占 CPU 时间太长,可以把刷新周期调大或者降低颜色深度减少绘制量。

4.2 时基改用系统 tick

带系统后lv_tick_inc不必再放 SysTick 中断里手动调,FreeRTOS 的 tick 本身就是毫秒级,可以在 LVGL 任务里按差值补,或者干脆用lv_tick_set_cb绑定一个返回xTaskGetTickCount的回调。后者更干净,省得两套时基打架。注意 FreeRTOS 的 tick 频率如果是 1000Hz 正好对应 1ms,如果是 100Hz 就要换算,否则动画速度差十倍。

4.3 内存分配交给系统还是 LVGL 自己管

LV_MEM_CUSTOM设 1 时 LVGL 用malloc/free,设 0 时用自带内存池。带 FreeRTOS 的项目里,如果系统堆够大,用自定义分配能和其他模块共享内存;但 FreeRTOS 的heap_4有碎片风险,界面反复创建删除对象时间长了可能分配失败。稳妥做法是保持LV_MEM_CUSTOM 0,给 LVGL 一块独立内存池,界面对象生命周期再乱也影响不到系统堆。这块内存从链接脚本里预留,别和任务栈抢。

5. 避坑排查:移植阶段最常见的五个翻车现场

5.1 编译报 lv_conf.h 找不到

现象是满屏cannot open source input file "lv_conf.h"。原因是头文件搜索路径没加LVGL这一层,或者LV_CONF_INCLUDE_SIMPLE没开。解决是把LVGL目录加进 Include Paths,并在lv_conf.h里确认#if 1已生效。改完 Clean 再全编译,Keil 有时缓存旧路径。

5.2 屏幕白屏或花屏

现象是烧录后全白、全黑或者彩色噪点。原因按概率排:颜色深度和屏驱动不一致、flush 回调没调lv_disp_flush_ready、缓冲区大小算错越界。解决是先确认LV_COLOR_DEPTH与屏的像素格式一致,再在 flush 回调末尾补上 ready 调用,最后检查缓冲区数组长度是否等于宽×高×每像素字节数。

5.3 界面能显示但触摸没反应

现象是画面正常,点按无响应。原因是输入设备没注册、读点回调没返回按下状态、坐标超出分辨率。解决是确认lv_indev_drv_register被调用,在回调里打印原始坐标看范围,方向不对就交换 x/y 或做镜像。

5.4 动画卡顿、刷新慢

现象是按钮切换有拖影,动画一顿一顿。原因是帧缓冲太小、刷新周期太长、或者用了单缓冲还在等 DMA。解决是把缓冲提到屏幕 1/10 以上,LV_DISP_DEF_REFR_PERIOD降到 20 到 30ms,双缓冲配合 DMA 完成中断。RAM 实在不够就减少同屏部件数量。

5.5 带系统后偶发死机

现象是跑一段时间后卡死或 HardFault。原因是 LVGL 内存池和任务栈重叠、或者在中断里调用了 LVGL 函数。解决是检查链接脚本里 LVGL 内存池地址段是否与栈区分离,并确保所有lv_*调用都在任务上下文,中断里只置标志位。

6. 装完怎么验证:从模拟器到板子的双端确认

移植完别急着写业务界面,先做两层验证。第一层在 PC 模拟器上跑,指南第四章专门讲模拟器工程,用 VS 或 CodeBlocks 把 LVGL 源码编成可执行程序,官方例程能正常显示、鼠标能点,说明库本身和配置没问题。这一步把硬件因素排除掉,后面板子上出问题就只查驱动。

第二层在板子上跑最小验证:一个标签加一个按钮,按钮按下改变标签文字。这个 demo 同时覆盖显示、输入、事件三条链路,比直接跑复杂例程更容易定位问题。验证时打开LV_USE_LOG,串口能看到初始化各阶段的日志,哪一步没打印出来就查哪一步。

验证项通过标准失败先查
模拟器例程窗口正常显示可交互lv_conf.h 与库版本
板子显示标签文字清晰无花屏颜色深度与 flush 回调
板子触摸按钮按下有响应输入设备注册与坐标
动画过渡平滑无明显拖影缓冲大小与刷新周期
长时间运行半小时不死机内存池与任务栈

我自己的习惯是每次换板子或者升级 LVGL 版本,都先把这套最小验证走一遍,通过了再往里堆部件。有次偷懒直接拿旧工程改,结果新屏的驱动时序不一样,调了两天才发现是最小验证没做。从那以后我每次移植都强制先跑模拟器再跑板子最小 demo,两步都过了才动业务代码。希望这套流程能帮你少走点弯路,指南 PDF 里的例程和配置说明对着看,装环境这一步基本就稳了。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 3:47:08

零基础Python爬虫入门:从HTTP请求到数据存储的完整指南

简介:这份文档面向具备一定编程基础、希望系统掌握网络数据采集的学习者与开发者,围绕Python爬虫从概念到落地的完整链路展开,帮助读者理解自动化抓取工具的运行逻辑并规避常见误区。内容覆盖发送请求、解析网页、数据存储三大核心环节&#…

作者头像 李华
网站建设 2026/10/29 3:46:59

2025视觉设计趋势背后的技术驱动力与工程落地实践

1. 视觉设计趋势背后的技术驱动力拆解1.1 为什么2025年的设计趋势不再是“审美问题”这两年跟不少前端开发者和UI设计师聊天,大家有个共同的感受:以前聊设计趋势,聊的是配色、圆角、阴影、字体搭配,本质上是审美层面的迭代。但从2…

作者头像 李华
网站建设 2026/10/29 3:46:43

序列推荐系统核心技术解析:从DIN到Transformer

1. 序列推荐系统概述在推荐系统领域,序列推荐(Sequential Recommendation)已经成为近年来最受关注的研究方向之一。与传统的协同过滤方法不同,序列推荐系统会考虑用户行为的时间顺序,通过建模用户的历史交互序列来预测…

作者头像 李华
网站建设 2026/10/29 3:46:43

计算卡 vs 游戏卡:AI运算选型指南与避坑实践

计算卡和游戏卡在AI运算上的差别,这个话题在圈子里被反复咀嚼了无数遍,但每次聊起来还是有人踩坑。我见过太多人拿着刚入手的游戏卡兴冲冲跑训练脚本,结果显存爆了、多卡通信卡成幻灯片、驱动版本对不上折腾一整晚;也见过有人咬牙…

作者头像 李华
网站建设 2026/10/29 3:46:07

Google Agent Platform中skills的设计原理与工程实践

1. 项目概述:从“skills”这个词开始,我们到底在谈什么?“skills”这个词最近在技术圈里反复刷屏,但它绝不是字面意义上那个泛泛而谈的“技能”概念。如果你最近在Google Cloud控制台、GKE集群配置页、或者Gemini开发者文档里频繁…

作者头像 李华