LVGL——(3)定时器


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一直在运行,而timer2无法运行。

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_functiondata_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中文文档有详细描述,这里就不作展开,大家需要自行点击链接了解:

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值