LVGL定时器中几个问题

问题1

lv_timer_ready与lv_timer_handler函数什么关系,lv_timer_handler什么作用

回答

lv_timer_ready() 和 lv_timer_handler() 的关系可以理解为:前者"把某个定时器标记为已到期/该执行",后者"真正去扫描并执行到期的定时器回调"。

lv_timer_handler() 的作用

扫描所有已创建的定时器,判断哪些"到期了"(time_remaining==0),然后调用它们的回调函数(比如你的 my_timer1/my_timer2)。

计算并更新一些全局状态:例如 lv_timer_get_idle() 返回的空闲百分比、以及"距离下一个定时器到期还有多久"(lv_timer_get_time_until_next())。

返回值通常是"下一次最早需要处理定时器的剩余毫秒数"(方便上层睡眠/调度)。

lv_timer_ready(timer1) 和它的关系

lv_timer_ready() 不会调用 lv_timer_handler(),它只是改了 timer1 的内部时间戳(last_run),让 timer1 在"下一次 lv_timer_handler() 执行时"被判断为"已经到期",从而立刻执行一次回调。

你可以把它理解为:lv_timer_ready() 负责"让它下次 handler 来了就马上跑";而"下次 handler 什么时候来",取决于你的系统/主循环何时调用 lv_timer_handler()(或 lv_timer_periodic_handler() 间接触发)。

问题2

修改timer2的定时任务的延时时间,为啥会影响定时器1中的idle的值,lv_timer_get_idle是所有所有定时器的空闲时间百分比?

回答

会影响是正常的,因为 lv_timer_get_idle() 统计的不是"某一个 timer 的空闲",而是 整个 LVGL 定时器系统(更准确说:lv_timer_handler() 这条处理链)在最近一段时间内的空闲百分比。

为什么改 timer2 的延时会影响你在 my_timer1 里打印的 idle?

lv_timer_get_idle() 返回的是全局的 state.idle_last,它在 lv_timer.c 里用 busy_time 统计出来。

busy_time 累加的是:每次进入 lv_timer_handler() 后,从开始到结束消耗的时间(包含执行所有到期 timer 的回调时间)。

你在 my_timer2 里做了 lv_delay_ms(load_ms),相当于在 timer 回调里阻塞,这段阻塞时间会被算进 lv_timer_handler() 的忙碌时间里。

忙碌时间变大 ⇒ 空闲百分比变小 ⇒ 你在 my_timer1(或任何地方)调用 lv_timer_get_idle() 看到的值都会下降。

所以回答你的问题:

是的,lv_timer_get_idle() 可以理解为 "所有定时器共同造成的忙碌程度"对应的空闲百分比(更精确:LVGL 定时器处理器在统计窗口内的空闲百分比),不是 timer1 私有的。

因此只要 timer2 更"耗时",即便你在 timer1 的回调里打印,看到的 idle 也会跟着变化。

问题3

如果创建了⼀个控件,⽐如label;还创建了⼀个timer,并且将前⾯创建的label作为⽤⼾数据传递给这个 timer,然后在这个timer的回调函数中这个label进⾏了处理,⽐如刷新显⽰某些数据;那么如何合理、合法 (指针)地删除这个timer

回答

可以"合法、安全"地删掉这个 timer,关键是两条原则:

谁创建谁保存 timer 句柄 :lv_timer_create() 的返回值 lv_timer_t * 一定要保留(全局/static/放到某个上下文结构体里),因为删除 API 就是用这个句柄。
保证 label 生命周期 > timer 的回调使用期: label 一旦被删,timer 回调里就不能再用这个 label 指针,否则就是悬空指针。

LVGL 是有删除 API 的:lv_timer_delete(lv_timer_t * timer)(你截图的 lv_timer.h 里就有)。

下面给你一个最推荐、最"合理"的做法:把 timer 挂到 label 的删除事件上,label 要删时先把 timer 删掉,这样 timer 不可能再去碰已释放的 label。

cpp 复制代码
/* 定时器回调:user_data 里放的是 label 指针 */
static void timer_cb(lv_timer_t * t)
{
    lv_obj_t * label = (lv_obj_t *)lv_timer_get_user_data(t);
    if(!lv_obj_is_valid(label)) {   /* 防御:极端情况下避免悬空 */
        lv_timer_delete(t);
        return;
    }

    lv_label_set_text_fmt(label, "cnt=%" LV_PRIu32, lv_tick_get());
}

/* label 删除事件:user_data 里放的是 timer 句柄 */
static void label_delete_cb(lv_event_t * e)
{
    lv_timer_t * t = (lv_timer_t *)lv_event_get_user_data(e);
    if(t) lv_timer_delete(t);
}

void demo(void)
{
    lv_obj_t * label = lv_label_create(lv_screen_active());
    lv_label_set_text(label, "hello");

    lv_timer_t * t = lv_timer_create(timer_cb, 500, label);

    /* 关键:label 即将删除时,先删 timer,避免 timer 继续使用 label 指针 */
    lv_obj_add_event_cb(label, label_delete_cb, LV_EVENT_DELETE, t);
}

补充几点你可能会踩的坑:

在 timer 自己的回调里删除自己是允许的(LVGL 内部做了处理),但写法要注意:lv_timer_delete(t); return;,删除后不要再访问 t 的任何成员。

如果你从其它线程想删 timer,要确保在 LVGL 线程/持锁环境里操作(否则有并发风险)。在你这个模拟器 demo 一般都在同一线程里跑 lv_timer_handler(),问题不大

相关推荐
工控小龙人4 天前
环保设备HMI:废气处理的浓度监控界面
ui·人机交互·用户界面
工控小龙人5 天前
医疗器械HMI:输液泵的精准控制界面
ui·人机交互·用户界面
工控小龙人6 天前
船舶维修HMI:船舶发动机的检修诊断界面
ui·人机交互·用户界面
rhett. li8 天前
FreeBSD系统中使用clang/clang++编译Skia源码的方法
c++·ui·用户界面
rhett. li8 天前
Windows系统中使用MinGW-W64(gcc/g++或LLVM)编译Skia源码的方法
c++·windows·ui·用户界面
初级代码游戏24 天前
win11任务栏很美,但不好用
用户界面
许泽宇的技术分享2 个月前
A2UI与AG-UI深度对比:两大AI界面协议的异同与选择
用户界面·智能体·ag-ui·a2ui
许泽宇的技术分享2 个月前
当AI学会“画“界面:A2UI如何让智能体拥有UI表达能力
人工智能·生成式ai·前端开发·用户界面·a2ui
唐僧洗头爱飘柔95272 个月前
【软考:程序员(03)】如何考得程序员证书?本片知识点:文件目录、目录结构、文件路径、文件命名规则、系统安全、用户权限、作业调度、用户界面
安全·系统安全·文件管理·用户界面·用户权限·作业调度算法·文件命名规则