littleVGL 自带了一个任务管理系统,此任务系统除了给 littleVGL 内部使用外,还开放出来给我们用户使用,这给我们的应用程序设计带来了极大的便利,它支持6个任务优先级,高优先级的任务可以抢占低优先级的任务,注意,此任务管理系统是非实时的,因为任务的时效性是取决于 lv_task_handler()函数的调用,而 lv_task_handler()函数一般放在 main 函数主循环中进行调用,所以你也要确保 main 函数主循环中不能有其他过大的延时存在,满足上述要求之后,对于一般的应用来说,此任务系统的时效性误差可以忽略不计.对于我们用户而言,littleVGL 的任务管理系统主要是由 3 个数据类型和 13 个 API 接口组成的,下面我们来详细介绍。
1.1 任务回调函数数据类型
申明去定义一种函数指针数据类型,此数据类型就是用来约束任务回调函数的申明,保证我们写的任务回调函数只能有一个 struct _lv_task_t *形参和返回值必须是 void 的。
typedef void (*lv_task_cb_t)(struct _lv_task_t *);
1.2 任务优先级数据类型
enum {
LV_TASK_PRIO_OFF = 0,
LV_TASK_PRIO_LOWEST,
LV_TASK_PRIO_LOW,
LV_TASK_PRIO_MID,
LV_TASK_PRIO_HIGH,
LV_TASK_PRIO_HIGHEST,
_LV_TASK_PRIO_NUM,
};
typedef uint8_t lv_task_prio_t;
任务优先级数据类型的本质就是一个 enum 枚举体,这很简单,总共具有LV_TASK_PRIO_OFF 到 LV_TASK_PRIO_HIGHEST 之间的 6 个优先级,这里需要注意,_LV_TASK_PRIO_NUM(值为 6)对于我们来说没有实际意义,它是归 littleVGL 任务管理内部使用的,用来记录总共有 6 个优先级,然后还可以用作优先级形参的合法性判断。
1.3 任务管理句柄数据类型
typedef struct _lv_task_t
{
uint32_t period; //任务的回调周期
uint32_t last_run; //最近一次的运行时间点
lv_task_cb_t task_cb; //任务回调函数
void * user_data; //用户自定义数据
uint8_t prio : 3; //任务的优先级,占 3 位
uint8_t once : 1; //记录此任务是否只运行一次
} lv_task_t;
2.1 核心初始化
void lv_task_core_init(void);
想要使用 littleVGL 的任务管理系统,就必须得调用lv_task_core_init 进行初始化一下,但是好处在于不需要我们自己去手动调用了,littleVGL 内部已经帮我们完成了初始化调用,如下图所示:
在 lv_init 函数中可以看到 lv_task_core_init 函数的调用,而我们又在 main 函数中调用了lv_init 函数,所以我们完全可以不用去理会 lv_task_core_init 这个 API 接口。
2.2 事务处理器
LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void);
LV_ATTRIBUTE_TASK_HANDLER 是在 lv_conf.h 配置文件中定义的一个宏,默认情况下是为空的,不用理会,lv_task_handler 这个 API 接口是非常重要的,littleVGL 内部的所有事务都是通过这个接口来处理的,所以我称它为事务处理器,它需要不断的被周期性调用,我们通常把它放到 main 函数的主循环中去。
2.3 创建最基本的任务
lv_task_t * lv_task_create_basic(void);
这个函数是用来创建最基本的任务对象,创建完成之后,还需要通过其他的 API 接口来设置其属性,这个 API 接口归 littleVGL 内部使用。
2.4 创建任务
lv_task_t * lv_task_create(lv_task_cb_t task_xcb, uint32_t period, lv_task_prio_t prio, void *user_data);
我们创建任务一般都是通过这个API接口来进行的,可以一步到位,其实 lv_task_create 的实现原理是先通过调用 lv_task_create_basic 来创建最基本的任务,然后再通过其他的 API 接口来对其进行属性设置。
2.5 删除任务
void lv_task_del(lv_task_t * task);
2.6 设置任务回调函数
void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb);
2.7 设置任务优先级
void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio);
2.8 设置任务回调周期
void lv_task_set_period(lv_task_t * task, uint32_t period);
2.9 使任务立即准备就绪
void lv_task_ready(lv_task_t * task);
通过调用此 API 接口,我们可以使刚创建出来的任务立即处于就绪状态,然后在下一个lv_task_handler 调用时,使任务回调函数立即得到运行,而不用去等它的第一个运行周期,注意了这里说的是第一个周期不用等了,但是后面的周期还是要等的。
2.10 使任务回调函数只运行一次
void lv_task_once(lv_task_t * task);
通过调用此 API 接口,我们可以让任务的回调函数只运行一次,而非周期性调用,在一次调用完成之后,littleVGL 内部会通过 lv_task_del 接口来自动删除此任务的。
2.11 复位任务
void lv_task_reset(lv_task_t * task);
2.12 是否使能任务管理系统
void lv_task_enable(bool en);
按理来说,任务管理系统是必须得使能的,否则 littleVGL 的内部事务将会失效,比如界面就不会刷新了,控件的点击事件也会失效,所以千万不要使用这个 API 接口,除非你有特殊的需求。
2.13 获取任务的空闲百分比
uint8_t lv_task_get_idle(void);
注意这个空闲百分比仅仅只能代表 littleVGL 任务管理系统的一个空闲情况,并不能代表我们整个应用的空闲情况。