RT thread 中 LVGL 动画效果不起作用的原因及解决办法

最近在将LVGL移植到GD32的过程中发现动画效果在RT thread 上运行的不好,非常卡顿,似乎是没有起作用。下面记录一下排查方法。

使用自定义定时器

在配置文件中将 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, int value)
{

    lv_meter_indicator_t *bar = indic;
    if (value > 0)
    {
        bar->start_value = 0;
        bar->end_value = value;
        bar->type_data.arc.color = lv_palette_main(LV_PALETTE_GREEN);
    }
    else if (value < 0)
    {
        bar->start_value = value;
        bar->end_value = 0;
        bar->type_data.arc.color = lv_palette_main(LV_PALETTE_RED);
    }
    else
    {
        bar->start_value = -1;
        bar->end_value = 1;
        bar->type_data.arc.color = lv_palette_main(LV_PALETTE_YELLOW);
    }
}

 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. 其他程序照旧

结果验证

动画效果仍然不能正常显示。

查找源码解决

分析源码了解到,不管lv_tick_inc以哪种方式调用,LVGL 都能执行定时刷新函数_lv_disp_refr_timer,刷新周期按照LV_DISP_DEF_REFR_PERIOD ,LVGL 已经注册了屏幕刷新定时器(lv_disp_drv_register)和动画定时器(_lv_anim_core_init)。

可能出问题的地方还是在应用程序这边。

分析_lv_disp_refr_timer 可以看到,LVGL是可以根据_lv_inv_area()指定的区域进行局部刷新,如果应用程序中没有按照LVGL提供的函数修改,而是直接修改了显示控件的参数,很有可能漏掉了指定刷新区域这一个步骤,我就是在应用程序中直接修改了控件的属性变量,没有使用LVGL提供的set 函数。

修改动画回调函数

在动画回调函数中,使用LVGL提供的接口函数修改控件值,将set_Heading_value() 函数修改为

static void set_Heading_value(void *indic, int value)
{

    if (value > 0)
    {
		lv_meter_set_indicator_start_value(ROT_meter, ROT_meter_indic, 0);
		lv_meter_set_indicator_end_value(ROT_meter, ROT_meter_indic, value);
        bar->type_data.arc.color = lv_palette_main(LV_PALETTE_GREEN);
    }
    else if (value < 0)
    {
		lv_meter_set_indicator_start_value(ROT_meter, ROT_meter_indic, value);
		lv_meter_set_indicator_end_value(ROT_meter, ROT_meter_indic, 0);
        bar->type_data.arc.color = lv_palette_main(LV_PALETTE_RED);
    }
    else
    {
        lv_meter_set_indicator_start_value(ROT_meter, ROT_meter_indic, -1);
		lv_meter_set_indicator_end_value(ROT_meter, ROT_meter_indic, 1);
        bar->type_data.arc.color = lv_palette_main(LV_PALETTE_YELLOW);
    }
}

验证结果

动画效果可以正常显示,就是刷新区域标志没有更新的原因。

同样的,如果其他控件显示正常,某几个控件不正常,即局部不刷新问题,很有可能是跳过了LVGL提供的函数,导致刷新标志没有正常更新导致的。

你可能感兴趣的:(单片机,动画,LVGL,GD32)