文章目录
LVGL 的定时器就是会按照指定周期(单位:毫秒 ms )执⾏的函数。
LVGL 有⼀个内置的计时器系统。我们可以注册⼀个函数,让它定期被调⽤,这个函数我们可以称之为定时器处理任务。这些定时器任务在 lv_task_handler() 中进⾏处理和调⽤,需要每隔 x 毫秒调⽤⼀次。
定时器是⾮抢占式的,这也就是说⼀个定时器不能中断另⼀个定时器。因此,我们可以在定时器回调函数中调⽤任何与 LVGL 相关或⽆关的函数。
一、使用定时器
1、创建定时器
lv_timer_t * timer = lv_timer_create(timer_cb, period_ms, user_data);
可以通过 lv_timer_create 返回的定时器句柄 ”timer“ 变量,修改定时器的参数。
- timer_cb :定时器回调函数原型: void (*lv_timer_cb_t)(lv_timer_t *)
- period_ms :定时器执⾏周期,以毫秒 (ms) 为单位
- user_data :⽤⼾数据, void * 类型的指针
代码示例
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 1000, &user_data); //第二个参数(周期)是以毫秒为单位
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
在codeblocks软件上每隔1s打印一次数据,成功将数据打印出来。
2、准备与重置定时器
2.1 准备定时器
- lv_timer_ready(timer) 使计时器在下⼀次调⽤ lv_timer_handler() 时运⾏。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 10000, &user_data); //第二个参数(周期)是以毫秒为单位
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 1000, &timer1); //第二个参数(周期)是以毫秒为单位
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_ready(timer1); //timer1设置为准备状态
LV_LOG_USER("my_timer2“);//这里不需要加\n是因为该接口会自动在后面加\n
}
一开始timer1每隔10s执行一次,由于timer2执行时设置timer1为准备状态,所以timer1能够不断执行,在timer2执行后timer1就能执行。
2.2 重置定时器
- lv_timer_reset(timer) 重置计时器的周期。在定义的毫秒周期过去后,它将再次被调⽤。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“);//这里不需要加\n是因为该接口会自动在后面加\n
}
timer1执行一次后就不再执行,原因是timer2的执行时间比timer1短,此时timer1正在计时,当计时到100ms时,timer2执行完毕将timer1重置,所以timer2一直在运行,而timer1无法运行。
3、设置定时器的参数
- lv_timer_set_cb(timer, new_cb); // 设置新的回调函数
- lv_timer_set_period(timer, new_period); // 设置新的时间周期
- lv_timer_set_user_data(timer, new_user_data); // 设置新的⽤⼾数据
代码示例
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
}
在将timer1设定新的时间周期之后,timer1的执行周期就为10ms一次,执行时间够快,所以收到timer2的影响不会很大,但timer2执行时,timet1的时间还是会被重置。
4、设置重复次数
使⽤ lv_timer_set_repeat_count(timer, count) 接⼝让指定的定时器指定重复的次数。 当定时器调⽤了定义的次数后,它会⾃动被删除。将计数设置为 -1 表⽰⽆限重复。
代码示例
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, 6); //timer2重复运行6次后删除
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
}
可见timer2重复执行6次后就不再执行,后续进行执行的只有timer1。
5、启用和禁用定时器
使⽤ lv_timer_enable(en) 来启⽤或禁⽤定时器。
代码示例
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, 6); //timer2重复运行6次后删除
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
lv_timer_enable(false);
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
}
timer1执行完毕后调用禁用定时器函数将所有定时器禁用,于是timer2无法得到执行,timer1也无法再次运行。
6、 暂停和恢复
6.1 暂停定时器
- lv_timer_pause(timer); // 暂停指定的定时器。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, 6); //timer2重复运行6次后删除
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
lv_timer_pause(timer1); //暂停timer1
}
timer1先创建所以timer1先执行,执行完毕后timer2执行6次后禁用,同时暂停timer1执行,所以timer2执行完后两个定时器无法再次运行。
6.2 恢复定时器
- lv_timer_resume(timer); // 恢复指定的定时器。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, 6); //timer2重复运行6次后删除
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
lv_timer_pause(timer1); //暂停timer1
lv_timer_resume(timer1); //恢复timer1
}
timer1先创建所以timer1先执行,执行完毕后timer2执行6次后禁用,同时恢复timer1执行,所以timer2执行完后timer1继续执行。
二、其他用法
- 可以通过 lv_timer_create_basic() 在不指定任何参数的情况下创建⼀个新定时器。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
static void my_timer3(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, 6); //timer2重复运行6次后删除
/* 创建第三个timer */
// timer3 = lv_timer_create(NULL, 500, NULL);
timer3 = lv_timer_create_basic(); //这个函数没有任何参数,但其中第二个参数为默认的DEF_PERIOD,时长为500ms
lv_timer_set_cb(timer3, my_timer3); //设置新的回调函数
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
uint32_t idle = lv_timer_get_idle();
LV_LOG_USER("my_timer1 user_data: %d, idle: %d", *user_data, idle);
}
static void my_timer2(lv_timer_t * timer)
{
lv_timer_t * timer1 = lv_timer_get_user_data(timer);
lv_timer_reset(timer1); //timer1设置为重置状态
LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer3(lv_timer_t * timer)
{
LV_LOG_USER("my_timer3");
}
timer1先创建所以先执行,执行完毕后timer2执行6次后删除,接着就是时间比较短的timer1执行,执行一段时间后timer3执行。
- 可以使⽤ lv_timer_get_idle 函数获取 lv_task_handler() 函数的空闲百分⽐时间。 请注意,它并不测量整个系统的空闲时间,仅测量 lv_task_handler() 的空闲时间。 如果在操作系统中使⽤ lvgl 定时器调⽤ lv_task_handler() ,这可能会产⽣误导,因为它实际上不能测量操作系统在空闲线程中的消耗时间。可以调用此函数获得空闲时间百分比,可以检测出哪些定时器比较耗时。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
static void my_timer3(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 105, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, 6); //timer2重复运行6次后删除
/* 创建第三个timer */
// timer3 = lv_timer_create(NULL, 500, NULL);
timer3 = lv_timer_create_basic(); //这个函数没有任何参数,但其中第二个参数为默认的DEF_PERIOD,时长为500ms
lv_timer_set_cb(timer3, my_timer3); //设置新的回调函数
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
lv_timer_enable(false);
}
static void my_timer2(lv_timer_t * timer)
{
//LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
}
static void my_timer3(lv_timer_t * timer)
{
//LV_LOG_USER("my_timer3");
}
当只有timer1执行时,空闲百分比时间为100%。
在上述代码的timer2函数中做出修改如下:
static void my_timer2(lv_timer_t * timer)
{
//LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
sleep(1); //每次睡眠1s
}
可见空闲百分比时间大幅度减小,当timer2执行完6次后删除timer2,只有timer1执行,所以空闲任务时间接近100%。
/* 在主函数调用即可 */
static void my_timer1(lv_timer_t * timer);
static void my_timer2(lv_timer_t * timer);
static void my_timer3(lv_timer_t * timer);
void Timer_deno(void)
{
static int user_data = 100;
lv_timer_t * timer1;
/* 创建第一个timer */
timer1 = lv_timer_create(my_timer1, 100, &user_data); //第二个参数(周期)是以毫秒为单位
lv_timer_set_period(timer1, 10); //设定timer1的周期为10ms
/* 创建第二个timer */
timer2 = lv_timer_create(my_timer2, 100, &timer1); //第二个参数(周期)是以毫秒为单位
lv_timer_set_repeat_count(timer2, -1); //timer2不断重复运行
/* 创建第三个timer */
// timer3 = lv_timer_create(NULL, 500, NULL);
timer3 = lv_timer_create_basic(); //这个函数没有任何参数,但其中第二个参数为默认的DEF_PERIOD,时长为500ms
lv_timer_set_cb(timer3, my_timer3); //设置新的回调函数
}
static void my_timer1(lv_timer_t * timer)
{
int *user_data = lv_timer_get_user_data(timer);
LV_LOG_USER("my_timer1 user_data: %d", *user_data);//这里不需要加\n是因为该接口会自动在后面加\n
lv_timer_enable(false);
}
static void my_timer2(lv_timer_t * timer)
{
static int i = 0;
//LV_LOG_USER("my_timer2“); //这里不需要加\n是因为该接口会自动在后面加\n
usleep(1000 * i++); //每次睡眠增加1us(timer2每100ms执行一次,所以每100ms增加1us)
}
static void my_timer3(lv_timer_t * timer)
{
//LV_LOG_USER("my_timer3");
}
当timer2运行时,占用时间越多,空闲任务时间越少,同时timer1打印的间隔时间越来越长
- 在某些情况下,不能⽴即执⾏某个操作。例如,如果还有其他东西在使⽤该对象,或者不希望阻塞执⾏。 对于这些情况,可以使⽤ lv_async_call(my_function, data_p) 在下⼀次调⽤ lv_task_handler() 时调⽤ my_function 。当调用函数时,将传递 data_p。请注意,只保存数据指针,因此您需要确保在调用函数时变量仍然有效。 它可以是 静态、全局或动态分配的数据。如果您想要取消异步调用,请调用
lv_async_call_cancel(my_function, data_p)
, 它将清除与my_function
和data_p
匹配的所有异步调用。
void my_screen_clean_up(void * scr)
{
/*释放与`scr`相关的一些资源*/
/*最后删除屏幕*/
lv_obj_delete(scr);
}
...
/*在当前屏幕上执行一些操作*/
/*在下一次调用`lv_timer_handler`时删除屏幕,而不是立即删除。*/
lv_async_call(my_screen_clean_up, lv_screen_active());
/*屏幕仍然有效,因此您可以对其进行其他操作*/
如果您只想删除一个对象,而不需要在 my_screen_cleanup
中进行任何清理操作, 可以直接使用 lv_obj_delete_async()
,它将在下一次调用 lv_timer_handler()
时删除该对象。
三、相关API
LVGL相关API以及参数解析在百问网LVGL中文文档有详细描述,这里就不作展开,大家需要自行点击链接了解: