新闻详情

新闻详情

首页 / 资讯中心 / 详情

LVGL+SquareLine Studio:嵌入式UI开发从入门到实战

发布时间:2026/9/28 1:08:54来源:尧图网络
LVGL+SquareLine Studio:嵌入式UI开发从入门到实战
有没有遇到过这种情况嵌入式产品功能都调通了结果显示端还是一块傻乎乎的LCD——白底黑字或者一堆死板的方块按钮。用户一看就觉得廉价老板一看就想改版实际体验和手机App差了十万八千里。要是项目再踩上触摸屏、多页面、动态刷新这些需求纯手写控件逻辑直接能把人写麻。这篇文章聊的就是怎么解决这个问题。我会围绕LVGL和SquareLine Studio这一对组合从零开始把嵌入式UI这件事拆开讲清楚LVGL是什么、为什么它能成为当前嵌入式UI领域的主流选择、如何在PC模拟器上快速上手、怎么移植到STM32这类MCU上跑起来以及如何用SquareLine Studio拖拽出满意的界面并集成到工程里最后再补上容器布局、Tab切换、按键输入、中文字体这些高频实战细节。无论你是刚接触嵌入式图形开发的应届生还是项目里被迫接过UI这块的驱动工程师这篇文章都适合你按图索骥地过一遍。先说结论嵌入式UI没有想象中那么难难的是没人把工具链、设计思路和踩坑点串起来讲。这篇文章的内容踩过的坑够多写出来的步骤基本可以直接抄作业。1. LVGL到底是什么为什么大家都选它1.1 从“显示”到“界面”的进化很多老项目的显示逻辑是这样的底层驱动把显存地址交给LCD应用层直接往这个地址里填像素需要显示文字时调用字库API需要用进度条时画一个矩形再填充颜色。这种做法的成本低但每个页面都要重复造轮子而且动效、触摸命中检测、控件焦点管理这些需求一旦复杂起来工程量就迅速膨胀。LVGLLight and Versatile Graphics Library就是来替代这种“手工绘图”模式的。它是一个用纯C写的开源嵌入式图形库核心设计目标是让资源受限的MCU也能运行接近现代UI体验的界面。它提供了按钮、滑块、开关、图表、列表、Tab等几十种现成控件自带样式系统、Flex/Grid布局引擎、动画框架、事件回调机制以及精简过的MVP架构思路在LVGL里体现为对象树和事件分发。也就是说你不需要自己维护每个控件该怎么绘制、怎么响应用户操作把控件“放”上去告诉LVGL长什么样、点了之后干什么剩下的交给库处理。类比一下LVGL对于嵌入式UI开发相当于建造一栋房子的框架和预制板材你只要负责户型图界面设计和装修风格样式配置而不用自己从烧砖开始。1.2 一条斜坡而不是一堵墙市面上同类方案不少比较常见的有TouchGFX、emWin、AWTK、Qt for MCU。选型时我最终把票投给LVGL主要是看中这几点开源且协议友好LVGL以MIT许可证发布商业项目可以闭源使用不必担心授权费或法律风险emWin等商业库按芯片或工程收费对小公司和个人项目不友好。资源占用曲线平缓LVGL的裁剪跨度很大。极简配置下RAM需求可以压到几KB到几十KBFlash占用约几十KB起步Flash和RAM充足的MCU可以开更多特效相比之下Qt for MCU的起步资源要求明显高一个数量级。如果你的项目是从STM32F103这类小芯片起步LVGL几乎是唯一能优雅跑起来的现代开源方案。硬件平台无关性强LVGL本身不依赖任何特定MCU和屏幕驱动只要底层提供“画一个像素/复制一块显存”的能力它就能跑。这也使得官方模拟器和各种开发板的移植包非常丰富。生态活跃配套工具成型这一点我要重点说。SquareLine Studio是LVGL官方团队推出的可视化UI设计器拖拽即可生成C代码再配合官方的手写移植文档和设备驱动库整个开发流程从设计到落地基本是贯通的。相比之下有些开源库虽然本身设计不错但缺少一个顺手的“所见即所得”编辑器界面开发效率确实低了一截。1.3 什么时候不要用LVGL当然得泼一点冷水。LVGL不是万能的。如果项目只是显示几个温度数字要求极低成本和极低功耗那用段码屏或者断码屏驱动芯片就够了没必要上LVGL。如果产品的UI复杂度已经接近手机App水准有复杂的网页嵌套、复杂的视频播放需求那LVGL也会捉襟见肘这时候需要考虑AOSP或嵌入式Linux。选型的关键是匹配需求复杂度而不是盲目追逐“别人都在用”。2. 环境准备先把模拟器跑起来2.1 为什么建议先搞PC模拟器很多人拿到LVGL的第一反应是把工程往STM32开发板里烧烧完发现白屏、花屏、触摸无反应然后又不知道是硬件问题还是软件问题调试效率极低。我的建议正好相反先在PC上通过模拟器把LVGL本身跑明白再考虑硬件移植。理由很简单PC模拟器屏蔽了底层驱动差异编译运行周期短还能直接在PC屏幕上看到效果方便调试界面布局和业务逻辑。等模拟器上的逻辑稳定了再往MCU上移这时候剩下的问题就只有底层驱动适配排查范围小得多。2.2 用CMake和SDL快速搭建模拟器LVGL官方仓库里有PC模拟器工程基于SDL库拉下来编译即可。这里我以LVGL 9.x版本为例步骤大致如下安装基础工具Windows下装Code::Blocks或Visual StudioLinux下确保有gcc、make、CMakeSDL库在Windows上建议直接下载预编译包。克隆LVGL仓库以及它的模拟器工程git clone --recurse-submodules https://github.com/lvgl/lv_port_pc_eclipse.git注意这里用的是官方PC模拟器仓库里面已经包含了LVGL子模块。如果网络访问GitHub困难可以手动下载LVGL源码包并解压到指定目录比如把lvgl文件夹放到lv_port_pc_eclipse子目录下。配置SDL库路径。在CMakeLists.txt里找到SDL相关设置填入你本机SDL2的安装路径如果使用Visual Studio也可以直接导入仓库里的Eclipse工程文件再配置包含目录和库目录。编译运行cd lv_port_pc_eclipse mkdir build cd build cmake .. make -j4 ./demo正常的话会弹出一个带示例界面的窗口里面有很多演示控件鼠标点击、拖动都能响应。2.3 模拟器调试的几个小技巧模拟器上有几个参数值得关注模拟器分辨率在lv_conf.h或lv_drv_conf.h里可以设置模拟窗口大小我一般会设成与目标屏幕同尺寸比如800x480或480x272这样界面布局的参考价值更高。帧率与日志输出模拟器默认就会输出LVGL内部日志比如内存分配失败、未处理事件等。调试时开着日志很多奇怪问题会直接暴露出来。修改代码后热重载PC模拟器不能直接热重载但编译只要几秒配合自动构建脚本效率也能接受如果你是VS用户每次修改后F5重新编译就行。建议在模拟器阶段把界面布局、样式、交互逻辑都调好再动硬件移植这样可以大幅减少后续烧板调试的次数。3. 移植到STM32从裸机到FreeRTOS3.1 移植前需要准备什么要把LVGL跑在STM32上需要具备以下前置条件一个能正常点亮屏的基础工程无论是HAL库还是标准外设库必须保证已有工程能把屏幕刷成纯色这一步排除了底层驱动的问题。屏幕驱动IC的手册或驱动代码常见的有ILI9341、ST7789、NT35510等确认像素格式、初始化序列、显存方式。LVGL源码包从GitHub Release或官方源码仓库获取建议选择固定的release tag比如v9.2.x。不要用master分支的最新提交因为API可能会变。3.2 配置lv_conf.hLVGL的配置文件是lv_conf.h通常放在项目的lvgl目录外或者在lv_conf.h顶部通过宏开关LV_CONF_INCLUDE_SIMPLE控制路径。重点配置这几项#define LV_COLOR_DEPTH 16 #define LV_MEM_SIZE (64U * 1024U) #define LV_DEF_REFR_PERIOD 33 #define LV_USE_OS 0 #define LV_FONT_MONTSERRAT_14 1色深必须和屏幕驱动IC的像素格式一致。RGB565就是16位ARGB8888就是32位。如果设置不一致颜色会偏差甚至花屏。内存池大小LVGL内部动态分配对象和缓冲内存池太小会导致控件无法创建。这个值需要根据UI复杂度来调整初学者可以先给64KB跑起来再观察内存占用越大MCU内存这个设置越宽松。刷新周期LV_DEF_REFR_PERIOD是LVGL刷新屏幕的最小间隔单位毫秒一般设33ms约30FPS视觉效果比较平衡。LV_USE_OS如果不用裸机轮询方式想移植到FreeRTOS里跑可以打开这个宏不过LVGL在FreeRTOS上更常见的做法是自己创建任务宏开关影响不大。3.3 对接显示驱动和输入设备LVGL跑起来后每过一个刷新周期就会调用用户注册的“刷屏函数”把内部缓冲区的数据推送到屏幕。这个函数在LVGL 9.x中通过lv_display_set_flush_cb()注册。裸机模式下常见的接口实现是这样void my_display_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) { uint32_t w lv_area_get_width(area); uint32_t h lv_area_get_height(area); LCD_SetWindow(area-x1, area-y1, area-x2, area-y2); // LCD的写数据接口把px_map里的像素按RGB565写入 LCD_WriteData((uint8_t *)px_map, w * h * 2); // 通知LVGL刷新完成必须调用否则画面会卡死 lv_display_flush_ready(disp); }如果屏幕读写速度较慢要用到DMA需要注意缓冲区的生命周期LVGL在flush回调执行完之前不会复用这块缓冲区所以只要你在回调里把数据全部送走再调用lv_display_flush_ready()逻辑就是安全的。触摸输入则注册lv_indev设备void my_touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) { static lv_coord_t last_x, last_y; if (touch_scan(last_x, last_y)) { >lv_indev_t *indev lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(indev, my_touchpad_read);3.4 在主循环里驱动LVGLLVGL不是自动跑的它每隔一段时间需要通过lv_timer_handler()来处理事件、更新动画并触发屏幕刷新。裸机模式下直接放在主循环while (1) { lv_timer_handler(); HAL_Delay(5); }注意lv_timer_handler()内部会调用刷新回调且必须周期性地执行。如果主循环里有耗时过长的任务比如Flash擦写、传感器等待画面就会掉帧甚至卡死。这也是为什么很多项目会把它放到FreeRTOS的一个单独任务里。3.5 在FreeRTOS中集成在FreeRTOS中LVGL推荐的做法是创建一个独立的低优先级任务来跑lv_timer_handler()void vLvglTask(void *argument) { lv_init(); my_lvgl_init(); // 初始化显示器、触摸等 for (;;) { lv_timer_handler(); vTaskDelay(pdMS_TO_TICKS(5)); } }在main()里创建任务时注意给这个任务分配足够大的栈空间建议至少1024字节实际需求取决于LVGL内部对象创建的深度如果任务栈不足会出现随机死机的现象。另外lv_timer_handler()只能在一个任务里调用不能在多个任务里重复调用否则会引发资源竞争和刷新混乱。提示在FreeRTOS中运行LVGL时默认的心跳时钟LV_DEF_REFR_PERIOD由lv_tick_inc()提供需要在某个定时器中断里周期性调用。如果使用STM32 HAL的HAL_GetTick()最简单的方式是在SysTick中断里调用lv_tick_inc(1)保持LVGL时间基准不中断。4. 用SquareLine Studio从拖拽到生成代码4.1 SquareLine Studio解决的是设计效率问题手写UI布局是件很消耗耐心的事情调间距、调对齐、调颜色每次微调都要重新编译烧录看效果半天下来可能就为了把一个按钮的圆角调好。SquareLine Studio把这一环从“写代码”变成了“画界面”。SquareLine Studio是LVGL官方团队开发的桌面端可视化设计工具你可以在画布上拖拽控件、配置样式、关联事件最终导出C代码。导出的代码结构清晰UI元素被组织成screens和objects初始化函数负责创建对象和绑定事件回调。最关键的是它生成的代码依赖的是LVGL公开API因此可以直接整合进任何LVGL工程不受特定IDE或平台限制。4.2 一个实际案例设计“首页设置页”我以一次实际项目中常见的小型控制面板为例演示SquareLine Studio的使用流程。这个面板的运行目标是一块480x272的RGB屏幕带电容触摸物理按键若干界面分首页、设置页两个页面。打开SquareLine Studio新建工程时设置显示分辨率设为480x272色彩深度选16位RGB565与MCU驱动一致目标版本选LVGL 9.x。在首页画布上从左侧控件面板拖入一个Label作为标题再拖一个Button作为“进入设置”按钮拖一个Arc或者Slider作为系统参数调节。右侧属性面板里可以调整背景色、圆角半径、字体大小。这些操作和Figma这类工具很类似有设计工具的同事上手也快。接下来新建一个Screen命名为ScreenSettings拖入几个开关控件Switch和仪表盘控件Line Meter或Scale做一个简单的参数开关列表。为本页按钮绑定事件选中首页的Button在右侧“Events”面板点击加号选择“Clicked”事件然后在代码框里写上void home_btn_clicked(lv_event_t *e) { lv_screen_load(ui_ScreenSettings); }这个操作的作用是给按钮创建点击回调在回调里调用lv_screen_load()切换到设置页。4.3 导出代码并集成到工程点击工具栏的Export选择“Create UI Project”生成一个ui文件夹里面包含ui.c、ui.h、ui_events.c等文件。把这些文件复制到工程里在初始化时调用ui_init();这个函数会创建所有控件、加载样式、注册事件回调整个界面就出现在屏幕上了。这时候你需要做的就是把ui_init()放在LVGL和底层驱动初始化完成之后、主循环开始之前。注意SquareLine Studio默认生成的代码会包含它自带的lvgl版本依赖检查。如果你的LVGL版本与项目对应关系不一致编译时大概率报找不到某些API。所以使用SquareLine Studio时最好选择与工具内置版本一致的LVGL源码或者在工程里直接以工具生成的源码为准。4.4 用SquareLine Studio做项目的一些心得SquareLine Studio解决了很多手工布局的痛点但它不是全自动的银弹。有几点经验写在下面分辨率必须提前定死SquareLine Studio的工程一般基于固定分辨率的画布。如果中途改分辨率需要重新检查所有布局约束。所以尽量在项目早期把屏幕型号和分辨率确定下来。中文显示需要自己准备字体SquareLine Studio自带的英文字体无法显示中文。需要在“Fonts”里手动导入中文字体文件TTF/OTF并选择所需字符集中文字体文件较大建议在LVGL里通过lv_font_conv工具生成子集字体只包含项目中用到的少数中文汉字可大幅减少Flash占用。别忘了事件回调里的上下文导出的事件回调会被调用于多个控件注意用lv_event_get_user_data()或静态变量区分控件实例不要指望回调里能推断出是哪个控件触发的。自动生成的代码不一定最优它的样式配置可能包含大量“重复设置”生产代码时若对Flash极度敏感可以关掉不必要的属性导出或者手动精简部分样式配置。5. 进阶实战容器、Tab控件、按键输入与中文字体5.1 用容器Container和Flex布局管理多控件没有容器的LVGL项目容易出现“控件满天飞坐标全靠手写”的局面。一旦采用不同分辨率的屏幕布局直接崩掉。容器lv_obj就是用来解决控件分类组织和自动布局的。在SquareLine Studio或代码里你可以创建一个容器设置为Flex布局lv_obj_t *cont lv_obj_create(parent); lv_obj_set_size(cont, 400, 200); lv_obj_set_layout(cont, LV_LAYOUT_FLEX); lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);这样之后添加进去的子控件会自动按行排列设置lv_obj_set_flex_align()还能控制排列方向和对齐方式。LVGL 9.x中还引入了Grid布局更接近现代CSS Grid的使用体验。掌握容器和布局界面的响应式能力会明显提升。5.2 Tab控件多个页面切换不再手动管理Tab控件在嵌入式面板中非常常用典型场景是“一屏多页”总览页、配置页、日志页通过标签栏切换。LVGL的Tab控件是lv_tabview_create()lv_obj_t *tabview lv_tabview_create(parent, LV_DIR_TOP, 40); lv_obj_t *tab1 lv_tabview_add_tab(tabview, Overview); lv_obj_t *tab2 lv_tabview_add_tab(tabview, Settings); lv_obj_t *tab3 lv_tabview_add_tab(tabview, Log); // 在tab1里放具体的控件 lv_obj_t *label lv_label_create(tab1); lv_label_set_text(label, This is overview page);Tab控件内部已经处理了页面切换、触摸滑动或点击标签切换等逻辑不需要自己写。使用Tab时需要留意每个Tab的内容高度不要超出显示区否则会被截断如果内容确实多可以在Tab内部再套容器并开启滚动。5.3 物理按键输入不依赖触摸也能操控界面很多工业设备没有触摸屏只有几个物理按键。LVGL把输入设备抽象成lv_indev物理按键可以模拟成LV_INDEV_TYPE_ENCODER或LV_INDEV_TYPE_BUTTON。按键方式常见两种做法编码器模式一个旋钮一个按键用旋钮选择控件焦点按键触发点击。适合旋钮式操作界面。Button模式给每个按键映射屏幕上的一个坐标按下按键相当于触摸点落到某个坐标适合“上、下、左、右、确定”这种标准五键导航。我实际用过的五键导航方案是把UP、DOWN、LEFT、RIGHT分别模拟成屏幕特定区域坐标确定键模拟一次PRESSEDRELEASED。这样LVGL对象树的导航规则依然生效按下方向键时焦点会在可聚焦控件之间移动确定键则会触发控件的点击事件。代码如下void key_read_cb(lv_indev_t *indev, lv_indev_data_t *data) { static lv_coord_t x 120, y 120; bool key_down false; if (key_up_pressed()) { y - 10; // 模拟焦点上移 key_down true; } else if (key_down_pressed()) { y 10; key_down true; } // 确定键 if (key_ok_pressed()) { >LV_FONT_DECLARE(my_font_16); lv_obj_set_style_text_font(label, my_font_16, 0);注意如果你在SquareLine Studio里导入了字体生成的项目里会自带字体文件的C数组直接包含即可不需要重复生成。如果字库文件太大检查是否只导出了需要的字符。6. 常见问题与排查技巧实录以下这些问题几乎每个做LVGL项目的团队都会遇到拿出来分享给各位参考6.1 白屏或者屏幕无输出排查路径先确认LVGL是否初始化成功以及lv_timer_handler()是否被周期调用再用最简单的代码在屏幕左上角画一个纯色矩形确认底层驱动的flush有没有生效。这三个层次逐层排查能迅速找到问题所在。常见原因屏幕驱动未正确设置窗口坐标flush回调未调用lv_display_flush_ready()导致LVGL一直等待缓冲区释放颜色格式与驱动不匹配绘制了但显示出来是花屏或全黑。6.2 编译错误找不到lvgl.h或版本不匹配LVGL的头文件路径是lvgl/lvgl.h。在Keil/MDK工程里需要把lvgl和lvgl/src目录加入Include Path。版本不匹配的问题也高发SquareLine Studio生成的代码声明了#if LVGL_VERSION_MAJOR ! 9这类检查如果LVGL版本低于9编译时会直接报错。遇到这种情况按提示调整LVGL版本即可。6.3 控件创建了但没有显示可能原因父对象不可见或未设置尺寸控件被其他对象遮挡颜色与背景色相同。LVGL里对象的size为0时不会显示所以如果父容器没有尺寸子控件即使设置了坐标也不会出现在屏幕上。检查父容器的size是否非零。6.4 内存不足导致花屏或随机崩溃LVGL在失败时的表现通常是“部分控件不显示”或“随机卡死”不会像PC上那样弹窗提示。解决方式是打开LVGL的日志系统LV_USE_LOG置1并正确实现串口输出。内存池大小LV_MEM_SIZE不足时日志中会有lv_mem相关报错。适当调大该值或者使用动态heap分配模式都可以缓解问题。6.5 触摸偏移或方向不正确触摸芯片读取到的坐标通常是原生的电阻式或电容式坐标不一定和屏幕的显示坐标对应。解决办法是在touchpad_read回调里做坐标变换例如data-point.x lv_scr_act()-get_width() - raw_x; // 水平镜像>
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

智能仓储项目技术专家如何避免背锅?从技术思维到项目防守 2026/9/28 6:39:23

智能仓储项目技术专家如何避免背锅?从技术思维到项目防守

1. 困局拆解:技术专家怎么就成了“背锅侠”先说说我自己的经历。干了八年智能仓储,从WMS(仓储管理系统)开发到自动化立体库集成,再到整个智能仓项目的现场交付负责人,我算是完整走过了“技术越干越深、锅也…

阅读更多 →
PostgreSQL删除表格全指南:从DROP TRUNCATE到误删恢复 2026/9/28 6:39:23

PostgreSQL删除表格全指南:从DROP TRUNCATE到误删恢复

说实话,做数据库的人每天打交道最多的操作,除了查询,就是删除。而“PostgreSQL 删除表格”这件事,看着简单,实际藏了不少坑。刚入门的同学可能觉得不就是一条DROP TABLE嘛,老手都知道,删除表格牵…

阅读更多 →
建设网站要买服务器?3个免费工具搞定选型与备案 2026/9/28 6:39:23

建设网站要买服务器?3个免费工具搞定选型与备案

建设网站要买服务器?3个免费工具搞定选型与备案 域名买好了,服务器到底该挑哪家?这是90%的建站新手最容易卡壳的地方。很多人对着阿里云、腾讯云的控制台发呆,配置看花了眼,价格算不明白,更担心买回来备案过不了、速度跟不上。…

阅读更多 →
编程语言类型系统扩展:编译期状态机约束与注解处理器实战 2026/9/28 6:39:22

编程语言类型系统扩展:编译期状态机约束与注解处理器实战

1. 类型系统扩展的整体设计思路类型系统这个东西,表面上看起来是编程语言里最“学术”的部分,什么Hindley-Milner推断、协变逆变、Traits约束……但真正把语言用在生产环境里,你会发现类型系统其实是一个“被低估的工程杠杆”。为什么这么说&…

阅读更多 →
DenseUnet腹部多脏器分割实战:数据集、训练评估与推理全流程 2026/9/28 6:39:22

DenseUnet腹部多脏器分割实战:数据集、训练评估与推理全流程

简介:这是一份面向医学图像分割研究与学习场景的实战资源,基于DenseUnet实现腹部多脏器分割,类别覆盖背景、肝脏、右肾、左肾与脾脏,并附带完整代码、数据集和训练结果。压缩包内共31个文件,以Python脚本为主&#xff…

阅读更多 →
揭秘美工工资一般多少,建站安全怎么选才不踩坑 2026/9/28 6:39:16

揭秘美工工资一般多少,建站安全怎么选才不踩坑

揭秘美工工资一般多少,建站安全怎么选才不踩坑 备案流程一头雾水?别慌,先搞懂 美工工资一般多少 这个底牌,再谈网站安全 怎么选…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉