LVGL的核心:lv_timer_handler
文章目录
- 🧠 一句话总结 LVGL 的运行核心:
- 🔁 1. `while(1)` 主循环中的 `lv_task_handler()`
- ⏱️ 2. `lv_timer_handler()` 定时器调度核心
- ✅ 并发控制
- ✅ 关键行为流程:
- 🌀 任务执行逻辑:
- 🧮 计算下一次调用间隔
- 📊 3. 额外性能监控与优化
- 🎯 总结一张图(逻辑关系)
- 🧩 你需要做的最关键一件事
- ✅ 总结重点
LVGL 的运行核心机制其实就围绕两个关键词展开:定时器轮询(Timer Loop)+ 任务处理器(Task Handler)。你贴的这段代码正是 LVGL 运行机制的心脏,下面我会从宏观和细节两个层面帮你理解这套机制的运行流程。
🧠 一句话总结 LVGL 的运行核心:
LVGL 通过定时器轮询机制(
lv_timer_handler
)周期性检查并执行任务(动画、事件、刷新等),由主循环中持续调用lv_task_handler()
驱动系统更新。
🔁 1. while(1)
主循环中的 lv_task_handler()
while(1) {lv_task_handler();usleep(5000); // 每 5ms 调用一次
}
- 这是你在主线程、RTOS 任务或定时器中 周期性调用 的函数;
- 实际内部会调用
lv_timer_handler()
,这是 LVGL 所有内部“定时行为”的核心; - 例:刷新控件、执行动画、检测事件、处理输入设备等,都是靠这里触发。
⏱️ 2. lv_timer_handler()
定时器调度核心
这是 LVGL 的任务调度中心,其关键职责如下:
✅ 并发控制
if(state_p->already_running) return 1;
防止多线程或中断中重复进入,保护调度流程。
✅ 关键行为流程:
lv_timer_t * timer_active = lv_ll_get_head(timer_head);
- LVGL 内部的“任务”是以
lv_timer_t
为单位组织的; - 每一个
lv_timer_t
都有周期(例如 30ms 执行一次); - 所有
timer
被链接在一个链表中,调度器依次遍历并执行;
🌀 任务执行逻辑:
if(lv_timer_exec(timer_active)) {if(state_p->timer_created || state_p->timer_deleted) {break;}
}
- 每次调度,调用
lv_timer_exec()
试图执行任务; - 如果任务内部创建或删除了其他
timer
,则会中断本次遍历,从头再来(保证链表安全);
🧮 计算下一次调用间隔
uint32_t delay = lv_timer_time_remaining(next);
- 执行完任务后,计算距离下一次要执行的任务的最小延迟;
- 这个值可用于指导下一轮
lv_task_handler()
的调用周期优化(例如设置精确定时器)。
📊 3. 额外性能监控与优化
state_p->idle_last = (state_p->busy_time * 100) / idle_period_time;
- LVGL 会统计任务执行耗时,判断 CPU 占用率;
- 可用于分析系统是否卡顿,或优化任务调度频率;
🎯 总结一张图(逻辑关系)
主循环/RTOS任务↓
lv_task_handler()↓
lv_timer_handler()↓
遍历 lv_timer 链表↓
执行注册任务(动画、屏幕刷新、事件分发等)↓
计算下次执行时间 & 性能分析
🧩 你需要做的最关键一件事
在你的系统中,确保 lv_task_handler()
每隔 5~10ms 被调用一次,即可激活 LVGL 的整个图形与事件系统。
当然可以,以下是为 lv_timer_handler()
添加的详细中文注释版,注释尽量保留原有逻辑结构,方便你后续阅读和调试:
// LVGL 的定时器调度主函数,每次被调用会遍历所有注册的定时器并执行到期的任务
LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
{LV_TRACE_TIMER("begin");lv_timer_state_t * state_p = &state;// 避免定时器调度函数被重复进入(多线程或中断中可能会并发调用)if(state_p->already_running) {LV_TRACE_TIMER("already running, concurrent calls are not allow, returning");return 1;}state_p->already_running = true;// 如果定时器已被暂停,直接返回if(state_p->lv_timer_run == false) {state_p->already_running = false; // 释放“互斥锁”return 1;}LV_PROFILER_BEGIN;lv_lock(); // 进入临界区,保护链表等资源不被同时访问// 获取当前时间(单位 ms)uint32_t handler_start = lv_tick_get();// 检查是否调用了 lv_tick_inc()(用于更新系统 tick)if(handler_start == 0) {state.run_cnt++;if(state.run_cnt > 100) {state.run_cnt = 0;LV_LOG_WARN("It seems lv_tick_inc() is not called.");}}/*************** 开始遍历并执行定时器任务 ***************/lv_timer_t * next;lv_timer_t * timer_active;lv_ll_t * timer_head = timer_ll_p; // 定时器链表头指针do {// 每轮遍历前先清空“状态标志”state_p->timer_deleted = false;state_p->timer_created = false;// 获取第一个定时器timer_active = lv_ll_get_head(timer_head);while(timer_active) {// 提前获取下一个指针(因为本 timer 执行后可能会被删除)next = lv_ll_get_next(timer_head, timer_active);// 如果当前定时器已经到期,则执行回调函数if(lv_timer_exec(timer_active)) {// 如果执行期间创建/删除了定时器,链表结构可能被破坏,必须重新从头遍历if(state_p->timer_created || state_p->timer_deleted) {LV_TRACE_TIMER("Start from the first timer again because a timer was created or deleted");break;}}// 进入下一个定时器timer_active = next;}} while(timer_active); // 如果因链表被修改跳出,则重新遍历/*************** 计算下次定时器触发时间 ***************/uint32_t time_until_next = LV_NO_TIMER_READY; // 默认无任务准备next = lv_ll_get_head(timer_head);while(next) {if(!next->paused) {// 获取该定时器距离下一次触发还需等待的时间uint32_t delay = lv_timer_time_remaining(next);if(delay < time_until_next)time_until_next = delay; // 保留最短时间}next = lv_ll_get_next(timer_head, next);}/*************** 统计“空闲率”用于性能分析 ***************/state_p->busy_time += lv_tick_elaps(handler_start); // 本轮花费时间uint32_t idle_period_time = lv_tick_elaps(state_p->idle_period_start);if(idle_period_time >= IDLE_MEAS_PERIOD) {// 计算过去一段时间内的 CPU 空闲率(100% - 忙碌率)state_p->idle_last = (state_p->busy_time * 100) / idle_period_time;state_p->idle_last = state_p->idle_last > 100 ? 0 : 100 - state_p->idle_last;// 重置统计值state_p->busy_time = 0;state_p->idle_period_start = lv_tick_get();}// 保存本次计算的“下次触发间隔”state_p->timer_time_until_next = time_until_next;state_p->already_running = false; // 解锁,允许下次进入LV_TRACE_TIMER("finished (%" LV_PRIu32 " ms until the next timer call)", time_until_next);lv_unlock(); // 退出临界区LV_PROFILER_END;return time_until_next; // 返回最短等待时间,供外部调度参考
}
✅ 总结重点
-
每次调用
lv_timer_handler()
:- 会遍历所有活跃的定时器;
- 执行到期的任务;
- 动态应对中途创建/删除定时器的情况;
- 返回下次最早触发的延时时间。
-
所有动画、控件刷新、事件分发等操作,最终都是通过定时器机制驱动。
相关文章:
LVGL的核心:lv_timer_handler
文章目录 🧠 一句话总结 LVGL 的运行核心:🔁 1. while(1) 主循环中的 lv_task_handler()⏱️ 2. lv_timer_handler() 定时器调度核心✅ 并发控制✅ 关键行为流程:🌀 任务执行逻辑:🧮 计算下一次…...

(41)VTK C++开发示例 ---qt使用vtk最小示例
文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容👉内容导航 👈👉VTK开发 👈 1. 概述 本文演示了在Qt中使用VTK的最小示例程序,使用VTK创建显示一个锥体; 采用Cmake作为构建工具&a…...
⭐️⭐️⭐️【课时1:大模型是什么?】学习总结 ⭐️⭐️⭐️ for《大模型Clouder认证:基于百炼平台构建智能体应用》认证
一、学习目标 概要 通过学习《课时1:大模型是什么?》,全面了解大模型的基础概念、核心特点、发展脉络及阿里云在大模型领域的布局,为后续基于百炼平台构建智能体应用的实践操作打下坚实的理论基础。 具体目标列表 理解人工智能到大模型的演变逻辑,明确大模型在AI发展历…...

OS7.【Linux】基本指令入门(6)
目录 1.zip和unzip 配置指令 使用 两个名词:打包和压缩 打包 压缩 Linux下的操作演示 压缩和解压缩文件 压缩和解压缩目录 -d选项 2.tar Linux下的打包和压缩方案简介 czf选项 xzf选项 -C选项 tzf选项 3.bc 4.uname 不带选项的uname -a选项 -r选项 -v选项…...

国标GB28181视频平台EasyCVR安防系统部署知识:如何解决异地监控集中管理和组网问题
在企业、连锁机构及园区管理等场景中,异地监控集中管控与快速组网需求日益迫切。弱电项目人员和企业管理者亟需整合分散监控资源,实现跨区域统一管理与实时查看。 一、解决方案 案例一:运营商专线方案 利用运营商专线,连接各分…...

O2O上门服务如何颠覆传统足浴行业?真实案例分析
在湖南经营传统足浴店的张总最近遇到了件让他哭笑不得的事。原本他的门店生意还算稳定,虽然这两年行情不好,但靠着老顾客还能勉强维持。可谁想到,一次好心帮忙,竟让他发现了行业的新天地。 几年前,张总的一位做砂石生意…...

金仓数据库永久增量备份技术原理与操作
先用一张图说明一下常见的备份方式 为什么需要永久增量备份 传统的数据库备份方案通常是间隔7天对数据库做一次全量备份(完整备份),每天会基于全量备份做一次增量备份,如此循环,这种备份方案在全备数据量过大场景下…...

19、HashTable(哈希)、位图的实现和布隆过滤器的介绍
一、了解哈希【散列表】 1、哈希的结构 在STL中,HashTable是一个重要的底层数据结构, 无序关联容器包括unordered_set, unordered_map内部都是基于哈希表实现 哈希表又称散列表,一种以「key-value」形式存储数据的数据结构。哈希函数:负责将…...
函数级重构:如何写出高可读性的方法?
1. 引言:为什么方法级别的重构如此重要? 在软件开发中,方法(函数)是程序逻辑的基本单元。一个高质量的方法不仅决定了程序是否能正常运行,更直接影响到: 代码的可读性:能否让其他开发者快速理解可维护性:未来修改是否容易出错可测试性:是否便于编写单元测试协作效率…...

mysql中int(1) 和 int(10) 有什么区别?
困惑 最近遇到个问题,有个表的要加个user_id字段,user_id字段可能很大,于是我提mysql工单alter table xxx ADD user_id int(1)。领导看到我的sql工单,于是说:这int(1)怕是不够用吧,接下来是一通解…...

FreeRTOS如何实现100%的硬实时性?
实时系统在嵌入式应用中至关重要,其核心在于确保任务在指定时间内完成。根据截止时间满足的严格程度,实时系统分为硬实时和软实时。硬实时系统要求任务100%满足截止时间,否则可能导致灾难性后果,例如汽车安全系统或医疗设备。软实…...
深度学习 ----- 数据预处理
常用的高级数据预处理的方法总结 🧠 一、图像数据高级预处理方法汇总表 方法原理常用参数适用场景图像增强(Augmentation)改变图像外观/几何结构,提升泛化能力翻转、旋转、缩放、色调扰动等分类、检测、分割等Mixup / CutMix合成…...
Cluster Interconnect in Oracle RAC
Cluster Interconnect in Oracle RAC (文档 ID 787420.1)编辑转到底部 In this Document Purpose Scope Details Physical Layout of the Private Interconnect Why Do We Need a Private Interconnect ? Interconnect Failure Interconnect High Availability Private Inte…...
【Spring Boot 注解】@SpringBootApplication
文章目录 SpringBootApplication注解一、简介二、使用1.指定要扫描的包 SpringBootApplication注解 一、简介 SpringBootApplication 是 Spring Boot 提供的一个注解,通常用于启动类(主类)上,它是三个注解的组合: 1.…...
angular的cdk组件库
目录 一、虚拟滚动 一、虚拟滚动 <!-- itemSize相当于每个项目的高度为30px --><!-- 需要给虚拟滚动设置宽高,否则无法正常显示 --> <cdk-virtual-scroll-viewport [itemSize]"40" class"view_scroll"><div class"m…...

element-ui日期时间选择器禁止输入日期
需求解释:时间日期选择器,下方日期有禁止选择范围,所以上面的日期输入框要求禁止输入,但时间输入框可以输入,也就是下图效果,其中日历中的禁止选择可以通过【picker-options】这个属性实现,此属…...
HarmonyOS Next~HarmonyOS应用测试全流程解析:从一级类目上架到二级类目专项测试
HarmonyOS Next~HarmonyOS应用测试全流程解析:从一级类目上架到二级类目专项测试 引言:HarmonyOS生态下的质量保障挑战 在万物互联的智能时代,HarmonyOS作为分布式操作系统,为开发者带来了前所未有的创新空间&#x…...
网络安全体系架构:核心框架与关键机制解析
以下是关于网络安全体系架构设计相关内容的详细介绍: 一、开放系统互联安全体系结构 开放系统互联(OSI)安全体系结构是一种基于分层模型的安全架构,旨在为开放系统之间的通信提供安全保障。它定义了安全服务、安全机制以及它们在…...
一种安全不泄漏、高效、免费的自动化脚本平台
在数字化转型加速的今天,自动化脚本工具已成为提升效率的重要助手。然而,用户在选择这类工具时,往往面临两大核心关切:安全性与成本。冰狐智能辅助(IceFox Intelligent Assistant)作为一款新兴的自动化脚本…...

[论文阅读]Deeply-Supervised Nets
摘要 我们提出的深度监督网络(DSN)方法在最小化分类误差的同时,使隐藏层的学习过程更加直接和透明。我们尝试通过研究深度网络中的新公式来提升分类性能。我们关注卷积神经网络(CNN)架构中的三个方面:&…...

多模态大语言模型arxiv论文略读(六十二)
MileBench: Benchmarking MLLMs in Long Context ➡️ 论文标题:MileBench: Benchmarking MLLMs in Long Context ➡️ 论文作者:Dingjie Song, Shunian Chen, Guiming Hardy Chen, Fei Yu, Xiang Wan, Benyou Wang ➡️ 研究机构: The Chinese Univers…...

现代框架对SEO的深度影响
第8章:现代框架对SEO的深度影响 1. 引言 Next 和 Nuxt 是两个 🔥热度和使用度都最高 的现代 Web 开发框架,它们分别基于 ⚛️React 和 🖖Vue 构建,也代表了这两个生态的 🌐全栈框架。 Next 是由 Vercel 公司…...

密码学--RSA
一、实验目的 1.随机生成明文和加密密钥 2.利用C语言实现素数选择(素性判断)的算法 3.利用C语言实现快速模幂运算的算法(模重复平方法) 4.利用孙子定理实现解密程序 5.利用C语言实现RSA算法 6.利用RSA算法进行数据加/解密 …...

如何选择自己喜欢的cms
选择内容管理系统cms what is cms1.whatcms.org2.IsItWP.com4.Wappalyzer5.https://builtwith.com/6.https://w3techs.com/7. https://www.netcraft.com/8.onewebtool.com如何在不使用 CMS 检测器的情况下手动检测 CMS 结论 在开始构建自己的数字足迹之前,大多数人会…...

BUUCTF——杂项渗透之赛博朋克
下载附件,是一个txt。打开查看,数据如下: 感觉这个像是用十六进制编辑器打开后的图片数据。为了验证此想法,我用010editor打开,发现文件头的确是png图片的文件头。 把txt文件后缀改成png格式,再双击打开&am…...
【c++】 我的世界
太久没更新小游戏了 给个赞和收藏吧,求求了 要游戏的请私聊我 #include <iostream> #include <vector>// 定义世界大小 const int WORLD_WIDTH 20; const int WORLD_HEIGHT 10;// 定义方块类型 enum BlockType {AIR,GRASS,DIRT,STONE };// 定义世界…...

React 中集成 Ant Design 组件库:提升开发效率与用户体验
React 中集成 Ant Design 组件库:提升开发效率与用户体验 一、为什么选择 Ant Design 组件库?二、基础引入方式三、按需引入(优化性能)四、Ant Design Charts无缝接入图标前面提到了利用Redux提供全局维护,但如果在开发时再自己手动封装组件,不仅效率不高,可能开发的组件…...
HunyuanCustom, 腾讯混元开源的多模态定制视频生成框架
HunyuanCustom是一款由腾讯混元团队开发的多模态驱动定制视频生成框架,能够支持图像、音频、视频和文本等多种输入方式。该框架专注于生成高质量的视频,能够实现特定主体和场景的精准呈现。 HunyuanCustom是什么 HunyuanCustom是腾讯混元团队推出的一种…...
Lightweight App Alternatives
The tech industry’s business model thrives on constant churn: new features, fancier designs, and heavier apps — not because they’re essential, but because they keep consumers upgrading. Stripping your phone back to basics is an act of tech self-defense.…...
STM32F103RCT6 + MFC实现网口设备搜索、修改IP、固件升级等功能
资源下载链接:https://download.csdn.net/download/qq_35831134/90712875?spm=1001.2014.3001.5501 一.大概逻辑: // 网口搜索大概逻辑: // ************************************************************************** // 一.环境: // 上位机用MFC下位机用STM32F103R…...