尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
LVGL仪表盘控件lv_gauge用法详解:从机制到实践
做嵌入式HMI项目总绕不开一类UI元素仪表盘。温度、电压、转速、液位凡是要把一维数据变成直观状态的场景都会想到指针表盘。LVGL里对应这个需求的就是lv_gauge。这篇笔记是我在折腾littleVGL期间整理的第18篇专门聊lv_gauge的用法、参数取舍和实际踩坑记录适合正在做屏幕交互、仪器面板、控制台监控的同学参考。我会从控件机制讲起再给完整可跑的示例代码最后把调试时遇到的坑都列出来尽量让你不用走弯路。1. 为什么一个仪表盘控件值得单独写一篇笔记1.1 一个很常见但容易被想简单的需求我之前接过一个模拟项目X要在彩屏上显示设备当前的水温、压力和电压。刚开始拿到需求时我脑子里第一反应是“画圆弧、画几条线、转一下角度就行”结果真正动手才发现自己写指针旋转的数学、刻度线的均匀排布、数值文本的居中计算一套搞下来不仅代码量爆炸刷新还有残影。后来我在网上看到有人推荐lv_gauge才意识到LVGL早就把表盘做成了独立控件。它不只是“画个扇形”而是把表盘背景、刻度线、刻度文本、指针、临界值提醒、动画过渡都集成好了。你要做的只是创建控件、设置数值范围、设置刻度参数然后调用一个接口把指针拨到目标值刷新和重绘都交给LVGL内部处理。1.2 用lv_gauge和“自己画”的本质区别自己画表盘时麻烦集中在几个地方角度映射要自己做、刻度线要按步长排、数字的位置要按半径计算、指针旋转时要处理坐标系方向。这些小逻辑单看都不难但拼在一起之后每改一个参数都要重新算一遍特别容易出错。lv_gauge把这些都抽象成了属性。你告诉它数值最小值是0、最大值是120它自动把角度范围映射好你告诉它主刻度10格、次刻度5格它自动给你画均匀分布的刻度线。最关键的是它把“数值”和“显示”解耦了你只需要维护业务数据界面表现完全不用操心。提示LVGL现在官方统一叫LVGL早期版本的名字是LittlevGL不少老教程和论坛帖还沿用旧称呼搜资料时记得新旧名都要试一下。2. 先搞懂lv_gauge的工作机制再动手写代码2.1 它内部其实是三套独立逻辑的组合lv_gauge表面看就是一个圆形控件但内部有三套东西在协同工作表盘弧线、刻度系统、指针系统。表盘弧线是控件最底层的背景它决定了整个仪表盘的轮廓。默认情况下LVGL画的是一个带缺口的扇形缺口通常留在下方这样指针在中间转起来才像真实仪表。这个弧线的样式由主部分的样式控制你可以改颜色、改粗细、改端点圆角。刻度系统负责把数值范围均匀映射到弧线上。这里要理解一个关键点刻度永远围绕中心点做圆周分布而不是线性分布。也就是说刻度的位置由角度决定角度的范围由控件的起始角和终止角决定每个刻度之间相差的度数完全相等。指针系统则是从圆心向外延伸的线段它的旋转角度由当前值计算得出。多指针模式下你可以同时显示多个指针每个指针可以独立设置颜色。2.2 角度映射的计算逻辑这是理解lv_gauge的重中之重。无论表盘长什么样内部都是把这个公式跑了一遍angle start_angle (value - value_min) * (end_angle - start_angle) / (value_max - value_min)举个例子你设置的数值范围是0到120默认角度跨度大约是240度起始角度在左下角终止角度在右下角。当value等于60时指针正好落在中间value等于0时指针停在下左起点value等于120时指针停在下右终点。我最初不明白为什么表盘默认会有一个大缺口后来才反应过来这正是为了模拟真实仪表的下方布局。缺口部分放的是表盘中心、品牌文字、或者不重要的装饰信息刻度线全部集中在上半部分读起来更符合人的视觉习惯。2.3 刷新机制为什么指针动起来会“卡”LVGL本身不是一个实时渲染引擎它走的是无效区域重绘机制。当指针角度变化时控件只是把自己标记为“需要重绘”真正的绘制发生在下一次lv_timer_handler周期里。所以你在主循环里连续调用十次lv_gauge_set_value屏幕上可能只看到最后一次的结果中间过程被合并了。这带来一个实际结论想要指针平滑转动不要一次把目标值设到终点而要在一段时间内逐步修改数值。LVGL的动画系统就是为了解决这个问题而存在的lv_gauge_set_value的最后一个参数就是给这个控件“从当前指针位置走一段动画”用的。3. 常用API拆解与参数选型3.1 创建和基础属性设置创建lv_gauge的接口非常直接lv_obj_t * gauge lv_gauge_create(parent_obj);创建出来只是一个空壳接下来必须设置它的数值范围不然默认的0到100范围可能跟你的业务对不上lv_gauge_set_range(gauge, 0, 120);这两个数字代表的是“业务值范围”不是角度范围。你要显示电压0到220就传0和220要显示温度-20到80就传-20和80。lv_gauge内部会自动计算每个值对应的指针角度。注意范围设置要尽量贴近实际业务场景不要夸大范围。比如实际温度最多到90你却设成0到999刻度会非常密指针只能在小范围内摆动视觉上很不好看。3.2 刻度参数别急着改先理解每个参数的作用刻度设置是我见过最容易让人蒙圈的API因为参数多名称还不统一lv_gauge_set_scale(gauge, 刻度总数, 主刻度数量, 次刻度数量, 主刻度长度, 次刻度长度);这里每个参数都值得聊一下刻度总数量整个表盘上要画多少个刻度位置。这个数一般等于“主刻度数量”乘以“每主刻度之间夹着的次刻度数”再加一比如主刻度10个、每格之间5个次刻度总刻度数就是51。主刻度数量带数字标注的刻度个数。它决定了读数的主要参照。次刻度数量每两个主刻度之间的小分格数量。次刻度越多表盘能表达的精度越高但太密会糊在一起。主刻度长度和次刻度长度以像素为单位的线段长度。主刻度通常较长较粗次刻度短一些。我给水温表设置的是总刻度数从0到120主刻度每隔10一个次刻度5个小格这样每个小格代表2度读取精度刚好符合需求。3.3 临界值和指针配置lv_gauge有一个很强的提醒功能叫“临界值”lv_gauge_set_critical_value(gauge, 100);设置之后超过临界值的刻度区域会用不同的样式呈现操作员一眼就能看出当前进入危险区间。配合指指针颜色和背景色设置整个表盘的警示效果非常明显。指针配置的接口是lv_gauge_set_needle_count(gauge, 1, needle_colors);注意第二个参数传入的是一个颜色数组这是lv_gauge支持多指针的原因。你想在同一个表盘上同时显示“当前值”和“目标值”或者显示“实测温度”和“设定温度”就可以把指针数量设为2。颜色数组要保证指针数量和颜色数量一致否则会出现指针颜色错位甚至崩溃。3.4 版本坑同一套代码在不同版本里编译不过我刚开始学习时被这个坑折腾过挺久。LVGL v8和v9的lv_gauge接口有变化尤其是v9把一些参数从函数参数改成了样式属性。例如指针颜色v8里是lv_gauge_set_needle_count时传入颜色数组v9里则建议通过样式PART来设置。如果你用的是旧教程里的代码在新版本上编译会报出各种“参数不匹配”的错误。碰到这种情况不要硬改代码先确认你的LVGL版本对应的官方头文件再对齐函数签名。经验遇到lv_gauge相关的问题先查头文件里的函数声明永远比搜旧帖快。4. 实操0到120℃水温表完整示例4.1 从创建到显示一个完整表盘下面这段代码是我在模拟项目X里实际跑过的完整流程基本上把上面的知识点串起来了/* 创建仪表盘 */ lv_obj_t * gauge lv_gauge_create(lv_scr_act()); lv_obj_set_size(gauge, 200, 200); lv_obj_center(gauge); /* 设置数值范围 */ lv_gauge_set_range(gauge, 0, 120); /* 设置刻度 */ lv_gauge_set_scale(gauge, 61, 13, 4, 15, 8); /* 设置临界值 */ lv_gauge_set_critical_value(gauge, 100); /* 设置单指针颜色为蓝色 */ static lv_color_t needle_colors[1]; needle_colors[0] lv_palette_main(LV_PALETTE_BLUE); lv_gauge_set_needle_count(gauge, 1, needle_colors); /* 初始指针在0度 */ lv_gauge_set_value(gauge, 0, 0, LV_ANIM_OFF);运行后你会看到一个带刻度和蓝色指针的表盘刻度从0到120超过100的部分有临界值提醒。这里有个细节lv_gauge_set_scale的第一个参数我写61是因为0到120范围主刻度每隔10一格总共13个主刻度每个主刻度之间4个次刻度总刻度数61。4.2 用定时器模拟动态数据并驱动指针动画静态表盘肯定不够通常要接入实时数据。这里我推荐用lv_timer来做周期性更新而不是在主循环里死等延时因为lv_timer能配合LVGL的调度机制不会阻塞界面刷新。static void gauge_timer_cb(lv_timer_t * timer) { static int32_t temp 30; lv_obj_t * gauge (lv_obj_t *)lv_timer_get_user_data(timer); /* 模拟温度波动 */ temp (rand() % 7) - 3; if (temp 0) temp 0; if (temp 120) temp 120; /* 指针动画时长给200ms */ lv_gauge_set_value(gauge, 0, temp, LV_ANIM_ON); } lv_timer_create(gauge_timer_cb, 500, gauge);这里我在定时器回调里保存了gauge指针避免每次重新查找。之所以把动画时长设为200ms是因为我的刷新周期是500ms指针用200ms走完目标位置剩下的300ms保持静止看起来最自然。如果动画时间太短会显得指针跳变太长则来不及指示新数据。4.3 触摸交互进阶点击表盘直接调数值lv_gauge默认不是一个交互控件但你可以自己给它加点击事件。我在实际项目里做过一个功能点击表盘的某个位置指针直接跳到你点的刻度。做法是把点击坐标转换成角度再反算数值思路如下static void gauge_click_cb(lv_event_t * e) { lv_obj_t * gauge lv_event_get_target(e); lv_indev_t * indev lv_indev_get_act(); lv_point_t point; lv_indev_get_point(indev, point); lv_area_t coords; lv_obj_get_coords(gauge, coords); int32_t cx coords.x1 lv_obj_get_width(gauge) / 2; int32_t cy coords.y1 lv_obj_get_height(gauge) / 2; float angle atan2f((float)(cy - point.y), (float)(point.x - cx)); angle angle * 180.0f / 3.14159f; /* 将角度映射到数值范围需要结合自己仪表的起始角 */ int32_t value (int32_t)((angle / 240.0f) * 120.0f); if (value 0) value 0; if (value 120) value 120; lv_gauge_set_value(gauge, 0, value, LV_ANIM_ON); } lv_obj_add_flag(gauge, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_event_cb(gauge, gauge_click_cb, LV_EVENT_CLICKED, NULL);这个功能做出来以后操作人员可以直接在表盘上点一个大概温度系统就自动把目标值设到那里不用再按键加减体验提升不少。角度到数值的换算公式看起来简单实际调试时要注意坐标系方向和四象限问题不同仪表的起始角不同映射关系要多测几个点。5. 常见问题与排查技巧实录5.1 指针不显示或显示位置不对指针不显示十有八九是颜色问题。我在几个项目里都遇到指针颜色跟背景色相同的情况看起来就像没有指针。排查时先把指针颜色设成高对比色比如红色或白色再确认lv_gauge_set_needle_count的颜色数组是否有效。颜色数组如果定义成函数内局部变量作用域结束后指针引用了一个无效地址极端情况下还会出异常。指针位置不对先检查数值范围设置。lv_gauge内部会用带符号的int32存储当前值如果你的业务值是负数范围设置里也要包含负区间否则内部转换会出现意料之外的偏移。5.2 刻度线糊成一团刻度线太密是常见问题。我调试时发现当总刻度数超过60且控件尺寸只有120像素时相邻刻度线之间的距离已经小于线宽了画出来的效果就是一团黑。解决办法有两个方向一是减少总刻度数让每格对应的角度更大二是把控件的尺寸调大比如200像素以上让刻度线之间有足够的间隔。对比效果如下控件尺寸总刻度数实际效果120px61刻度线密集部分重叠200px61刻度清晰可正常读数200px121刻度再次变密建议调整这个表格是我实际测试得到的背后逻辑是显示密度问题。任何仪表盘总刻度数乘以刻度线宽度不能超过表盘周长否则必然重叠。5.3 指针动画不生效lv_gauge_set_value的最后一个动画参数如果传的是LV_ANIM_OFF指针会瞬间跳过去传LV_ANIM_ON才会有平滑效果。有些版本在动画过程中再调用新值会打断当前动画这时最好等上次动画完成后再设置新值或者用LVGL动画组来管理。我还遇到一个情况定时器回调里改数值但主循环里没有调用LVGL的处理函数。LVGL刷新都由lv_timer_handler驱动如果你只定时改数值却不刷新屏幕指针当然不动。确认你的主循环中有类似while (1) { lv_timer_handler(); my_delay_ms(5); }这个小细节经常被忽略但90%“画面不更新”的故障都跟它有关。5.4 样式设置后没有生效lv_gauge的样式分区比普通控件复杂它有主区域PART_MAIN、刻度区域PART_TICKS、指针区域PART_INDICATOR。我在学习初期习惯用lv_obj_set_style_xxx直接改主样式结果发现刻度线颜色根本没变因为刻度和数字文本使用的是TICKS区域的样式。正确做法是基于PART来设置lv_obj_set_style_bg_color(gauge, lv_palette_main(LV_PALETTE_GREY), LV_PART_MAIN); lv_obj_set_style_line_color(gauge, lv_palette_main(LV_PALETTE_ORANGE), LV_PART_INDICATOR);理解PART机制之后你就能精确控制表盘的每一块颜色。LVGL把控件的各个子视觉元素拆成了不同分区改表盘就找MAIN改指针就找INDICATOR改刻度就找TICKS改数字文本也找TICKS。5.5 动态修改临界值后不刷新lv_gauge_set_critical_value调用后理论上控件会自动标记为无效但某些版本在临界值变化前后若刻度显示模式没有重新计算可能出现旧值残留。解决方法是强制调用一次lv_obj_invalidate(gauge)让整个控件下一帧全部重绘。5.6 多指针模式下颜色对应关系混乱多个指针时lv_gauge_set_needle_count的第二个参数是颜色数组指针的编号从0开始。我在项目里试过同时显示“当前水温”和“设定温度”两个指针分别用红色和绿色区分。一开始颜色总对不上后来才发现数组的顺序要跟指针编号一一对应static lv_color_t needle_colors[2]; needle_colors[0] lv_palette_main(LV_PALETTE_RED); needle_colors[1] lv_palette_main(LV_PALETTE_GREEN); lv_gauge_set_needle_count(gauge, 2, needle_colors);设定值指针我用虚线效果跟当前值指针区分开操作员看表时不用费力辨认。6. 一点实用总结之外的建议分享一个我琢磨出来的小技巧lv_gauge虽然是仪表盘但它的设计思路也可以迁移到其他“一维数据环形显示”的场景。比如用它显示剩余电量范围设成0到100临界值设成20指针颜色根据电量高低动态切换效果不比专门做电池图标差。另外如果硬件性能比较吃紧表盘刷新频率不用追求太高。lv_gauge的动画默认走LVGL的动画框架由CPU插值计算角度对低主频单片机来说把动画时间控制在300ms左右、关闭大范围阴影效果运行起来会很流畅。我在几个不同项目里反复用过lv_gauge之后最大的感受是仪表盘控件不在于“画得多像”而在于“读起来是否直观、改起来是否方便”。只要掌握了它的范围和刻度机制再复杂的表盘需求也能用几行代码实现。希望这篇笔记能让你少走一些弯路更快把仪表盘控件用起来。
RELATED

相关推荐

微信小程序登录注册全流程:前端界面与后端接口设计

微信小程序登录注册全流程:前端界面与后端接口设计

微信小程序登录/注册这套东西,我做过不止一版了,从最开始的“只有账号密码”到后来的“微信授权一键登录”再到混合模式,踩过的坑基本上能写一本书。这篇文章是系列的第二篇,上一篇我已经把界面布局和基本交互讲了一部分&#xff…

📅 2026/10/15 17:18:42
二维前缀和详解:从暴力超时到O(1)子矩阵求和模板

二维前缀和详解:从暴力超时到O(1)子矩阵求和模板

刷题刷到"子矩阵的和"的时候,我一开始真没当回事:不就是一个矩阵里反复求和嘛,for循环一套不就完事了?直到数据范围拉满、评测超时的那一秒,我才意识到二维前缀和这套模板必须从头啃透。后来我把这道经典题—…

📅 2026/10/15 17:18:42
IMX6ULL嵌入式Linux下Qt交叉编译与linuxfb部署实战

IMX6ULL嵌入式Linux下Qt交叉编译与linuxfb部署实战

第一次把 Qt 程序跑在 IMX6ULL 开发板的 LCD 屏幕上时,我盯着那个白色窗口愣了好一会儿——不是因为它跑得多流畅,而是这整个过程远比我想象中要绕:先要交叉编译 tslib 做触摸校准,给 Qt 源码配置一大堆构建开关,把几百…

📅 2026/10/15 17:13:41
MORE NEWS

更多资讯

📰

SHT3x温湿度传感器驱动开发:从原理到避坑全指南

简介:SHT3x 温湿度传感器代码包面向嵌入式开发初学者与物联网应用工程师,围绕盛思锐 SHT3x 高精度温湿度传感器,提供一套基于 STM32 平台的完整示例工程,帮助解决环境监测、智能家居、工业自动化等场景中温湿度数据精确采集与解析…

📰

C8051F与Keil的DFP驱动包:从设备识别到C2调试的完整排坑指南

简介:这是一份面向使用SILICON LABS C8051F系列单片机并在KEIL环境下开发的配套驱动资源包,适合嵌入式工程师、单片机爱好者及需要搭建C8051F调试环境的开发者。资源重点解决通过USB转串口连接目标板时,CP210x驱动缺失、版本不兼容导致下载与…

📰

RabbitMQ 官方教程多语言代码仓库(rabbitmq-tutorials)实战指南

示例工程 【免费下载链接】rabbitmq-tutorials Tutorials for using RabbitMQ in various ways 项目地址: https://gitcode.com/gh_mirrors/ra/rabbitmq-tutorials 点击查看 免费下载 本篇技术指南围绕开源仓库 rabbitmq-tutorials 展开,它是 RabbitMQ …

📰

部署 Hermes Agent:Windows 原生与 WSL2 完全指南(TaoToken 统一 Key 接入)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

GPT-6 Astra 与 GPT-6.1 Sol并列84.99分:2026-10-12 Smoke快测数据简报

2026-10-12 赢政指数 Smoke 快测覆盖 14 个模型,GPT-6 Astra 与 GPT-6.1 Sol 以 84.99 分并列当日首位。Smoke 为每日 10 题快测,适合观察短期信号,不等同 Full 周榜结论。 本次 Smoke 评测只覆盖代码执行和材料约束两个主榜维度,…

📰

物流管理系统前后台全栈解析:运单、权限与状态机设计

简介:一份物流管理系统前台后台的完整项目资源,面向物流信息化学习者、Java Web开发者及课程设计/毕业设计人群,用于理解订单、仓储、运输调度、货物跟踪等核心业务的前后端协作实现。压缩包共2000个文件、约65.88MB,包含以png、h…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬