问题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(),问题不大