最近在将LVGL移植到GD32的过程中发现动画效果在RT thread 上运行的不好,非常卡顿,似乎是没有起作用。先看一下错误的使用方法。
注意以下是LVGL 定时器的错误用法
在配置文件中将 LV_TICK_CUSTOM 选项打开,将获取时钟间隔的函数配置为 rt thread 操作系统的 rt_tick_get() 函数
/*Use a custom tick source that tells the elapsed time in milliseconds.
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
#define LV_TICK_CUSTOM 0
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "rtthread.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (rt_tick_get()) /*Expression evaluating to current system time in ms*/
#endif /*LV_TICK_CUSTOM*/
然后在rt thread 中创建一个 10ms 定时线程,定时调用 lv_task_handler();
while(1)
{
rt_thread_mdelay(10);
lv_task_handler();
}
到此,LVGL定时部分已经可以工作了,编写了一个动画显示程序,尝试去显示动画效果
1. 首先新建一个LVGL 定时器,定时500个周期调用屏幕运行函数,更新屏幕上显示控件。
lv_timer_t * UI_timer = lv_timer_create((lv_timer_cb_t)Screen_run, 500, NULL);
2. 在 Screen_run() 函数内创建一个动画效果
void Screen_run(void)
{
static short pre_value = 0;
/*Create an animation to set the value*/
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, set_Heading_value); /*设置动画回调函数*/
lv_anim_set_var(&a, Heading_meter_indic);
lv_anim_set_values(&a, pre_value, value); /* 设置开始和结束值。 */
lv_anim_set_time(&a, 2000); /* 动画时长[ms] */
lv_anim_set_path_cb(&a, &lv_anim_path_overshoot); /* 设置路径(曲线) */
lv_anim_start(&a); /*动画开始*/
pre_value = value;
}
其中动画回调函数为set_Heading_value(),这个函数就是动画效果自动去调用的函数,自动去完成插值显示。
static void set_Heading_value(void* indic, int32_t v)
{
lv_meter_set_scale_range(Heading_meter, scale_min, 0, 3600, 360, (6300-v)%3600);
lv_meter_set_scale_range(Heading_meter, scale_deg, 0, 270, 270, (630 - (v/10))%360);
}
3. 经过以上设置,以为动画效果会很平滑,结果运行起来之后和没有动画效果一样。问题出在那里了?
可能的原因分析
LVGL的运行机理就是自己管理了定时函数,实现自己的一套任务切换逻辑,当和其他操作系统联合使用时,就需要注意任务的优先级,传入LVGL 时间间隔的精度。
当LV_TICK_CUSTOM 选项打开后,原本是不需要再手动去调用lv_tick_inc(tick_period)函数(tick_period 为间隔时间,单位ms),lv_task_handler() 中会定时读取时间间隔,但是这样带来一个问题,在低优先级任务中,lv_task_handler的执行间隔不能被保证,会影响LVGL定时器的执行。从而影响了动画效果。
为了精确地知道经过的毫秒数,lv_tick_inc 应该在比 lv_task_handler() 更高优先级的例程中被调用(例如在中断中)。
以下为正确设置
1. 取消掉 LV_TICK_CUSTOM 选项,设置值为0 ;
2.在 SysTick_Handler 定时中断中手动调用 lv_tick_inc(1000/RT_TICK_PER_SECOND);
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
rt_tick_increase();
lv_tick_inc(1000/RT_TICK_PER_SECOND);
/* leave interrupt */
rt_interrupt_leave();
}
3. 其他程序照旧
结果验证
动画效果正常显示