LVGL V8 Demos
介绍
本示例用来演示LVGL V8的官方示例,使用官方提供的demo应用程序。 可以使用menuconfig来选择演示的demo应用程序。包含的应用程序有:
- Show some widget 演示lvgl widget的使用
- Demonstrate the usage of encoder and keyboard 演示键盘
- Benchmark your system 演示benchmark
- Stress test for LVGL 压力测试
- Music player demo 演示音乐播放
工程编译
工程链接:github
- 下载完毕后我们去执行 scons --board=sf32lb52-lchspi-ulp -j8 即可生成工程
- 下载可以执行 build_sf32lb52-lchspi-ulp_hcpu\uart_download.bat 输入下载UART的端口号执行
使用宏定义来选择启动的demo
#if LV_USE_DEMO_WIDGETS
#if LV_USE_DEMO_BENCHMARK
#define lv_demo_main lv_demo_benchmark
#else
#define lv_demo_main lv_demo_widgets
#endif
#elif LV_USE_DEMO_KEYPAD_AND_ENCODER
#define lv_demo_main lv_demo_keypad_encoder
#elif LV_USE_DEMO_MUSIC
#define lv_demo_main lv_demo_music
#elif LV_USE_DEMO_STRESS
#define lv_demo_main lv_demo_stress
#else
#error "Select a demo application to start"
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们可以在menuconfig中选择想使用的demo
程序讲解
main.c 分析 —— 程序入口与主循环
int main(void)
{
rt_err_t ret = RT_EOK;
rt_uint32_t ms;
/* init littlevGL */
ret = littlevgl2rtt_init("lcd"); // 初始化显示驱动和输入设备
if (ret != RT_EOK) {
return ret;
}
lv_ex_data_pool_init(); // 初始化数据池
lv_demo_main(); // 启动指定的 demo(根据宏定义)
while (1)
{
ms = lv_task_handler(); // 处理 LVGL 内部任务调度器
rt_thread_mdelay(ms); // 按帧率延迟
}
return RT_EOK;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
lv_demo_benchmark.c 分析 —— Benchmark 核心逻辑
1、入口函数:lv_demo_benchmark()
void lv_demo_benchmark(void)
{
benchmark_init(); // 初始化界面和监控回调
next_scene_timer_cb(NULL); // 手动触发第一个场景
}
- benchmark_init():
设置屏幕样式
注册性能监控回调
创建标题、副标题、背景对象
- next_scene_timer_cb(NULL):
触发第一个场景加载
2
3
4
5
6
7
8
9
10
11
12
2、场景切换机制
lv_timer_create(next_scene_timer_cb, SCENE_TIME, NULL);//创建定时器切换场景
定时器回调函数
static void next_scene_timer_cb(lv_timer_t *timer)
{
scene_act++; // 场景索引递增
load_scene(scene_act);
if (scenes[scene_act].create_cb == NULL) {
lv_timer_delete(timer);
generate_report(); // 最后一个场景结束,生成报告
} else {
lv_timer_set_period(timer, scenes[scene_act].scene_time);
}
}
2
3
4
5
6
7
8
9
10
11
12
加载场景函数:load_scene(uint32_t scene)
static void load_scene(uint32_t scene)
{
lv_obj_clean(scene_bg); // 清除当前场景内容
if (scenes[scene].create_cb) {
scenes[scene].create_cb(); // 执行创建回调
}
}
2
3
4
5
6
7
3、场景描述结构体:scene_dsc_t
typedef struct
{
const char *name;
void (*create_cb)(void);
uint32_t time_sum_normal; // 正常模式总耗时
uint32_t time_sum_opa; // 半透明模式总耗时
uint32_t refr_cnt_normal; // 正常模式刷新次数
uint32_t refr_cnt_opa; // 半透明模式刷新次数
uint32_t fps_normal; // 正常 FPS
uint32_t fps_opa; // 半透明 FPS
uint8_t weight; // 权重,用于加权计算
} scene_dsc_t;
2
3
4
5
6
7
8
9
10
11
12
示例场景定义
static scene_dsc_t scenes[] =
{
{.name = "Rectangle", .weight = 30, .create_cb = rectangle_cb},
{.name = "Circle border", .weight = 10, .create_cb = border_circle_cb},
...
{.name = "", .create_cb = NULL}
};
2
3
4
5
6
7
4、性能监控模块(LV_USE_PERF_MONITOR)
static scene_dsc_t scenes[] =
{
{.name = "Rectangle", .weight = 30, .create_cb = rectangle_cb},
{.name = "Circle border", .weight = 10, .create_cb = border_circle_cb},
...
{.name = "", .create_cb = NULL}
};
2
3
4
5
6
7
注册观察者:
disp->driver->monitor_cb = monitor_cb;
回调函数:monitor_cb(lv_disp_drv_t *drv, uint32_t time, uint32_t px)
static void monitor_cb(lv_disp_drv_t *drv, uint32_t time, uint32_t px)
{
if (opa_mode) {
scenes[scene_act].time_sum_opa += time;
scenes[scene_act].refr_cnt_opa++;
} else {
scenes[scene_act].time_sum_normal += time;
scenes[scene_act].refr_cnt_normal++;
}
}
2
3
4
5
6
7
8
9
10
5、动画系统详解
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, fall_anim_y_cb); // 绑定执行回调
lv_anim_set_values(&a, 0, target_y); // 设置起始/目标值
lv_anim_set_time(&a, duration); // 设置持续时间
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); // 设置无限循环
lv_anim_start(&a); // 启动动画
2
3
4
5
6
7
动画回调函数示例:
static void fall_anim_y_cb(void *var, int32_t v)
{
lv_obj_set_y(var, v); // 改变 Y 坐标
}
2
3
4
动画类型示例:
颜色变化 color_anim_cb(回调函数:改变背景或文本颜色) 移动动画 fall_anim_y_cb(回调函数:对象从上往下移动) 弧线动画 arc_anim_end_angle_cb(回调函数:弧形进度条动画)
6、UI 组件构建示例:card_create()
static lv_obj_t *card_create(void)
{
lv_obj_t *panel = lv_obj_create(scene_bg); // 创建容器
lv_obj_remove_style_all(panel);
lv_obj_add_style(panel, &style_common, 0);
lv_obj_t *img = lv_image_create(panel); // 添加图片
lv_image_set_src(img, &img_benchmark_cogwheel_rgb);
lv_obj_t *label = lv_label_create(panel); // 添加标签
lv_label_set_text(label, "John Smith");
return panel;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
完整调用链路图
main()
│
├── littlevgl2rtt_init() → 初始化 LVGL 运行环境
│
├── lv_demo_benchmark() → 启动 benchmark demo
│ │
│ ├── benchmark_init() → 初始化界面、样式、性能监控
│ │
│ ├── load_scene(0) → 加载第一个场景
│ │ └── scenes[0].create_cb() => rectangle_cb()
│ │
│ ├── lv_timer_create(...) → 创建定时器,定时切换场景
│ │
│ └── monitor_cb → 性能数据采集回调
│
└── while (1)
└── lv_task_handler() → LVGL 主任务调度
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
LVGL v9 Demo
介绍
本示例用来演示LVGL V9的官方示例,使用官方提供的demo应用程序。 可以使用menuconfig来选择演示的demo应用程序。包含的应用程序有:
- Show some widget 演示lvgl widget的使用
- Benchmark your system 演示benchmark(依赖于“Show some widget”)
- Demonstrate the usage of encoder and keyboard 演示键盘
- Stress test for LVGL 压力测试
- Music player demo 演示音乐播放
工程编译
工程链接:github
- 下载完毕后我们去执行 scons --board=sf32lb52-lchspi-ulp -j8 即可生成工程
- 下载可以执行 build_sf32lb52-lchspi-ulp_hcpu\uart_download.bat 输入下载UART的端口号执行
使用宏定义来选择启动的demo
#if LV_USE_DEMO_WIDGETS
#if LV_USE_DEMO_BENCHMARK
#define lv_demo_main lv_demo_benchmark
#else
#define lv_demo_main lv_demo_widgets
#endif
#elif LV_USE_DEMO_KEYPAD_AND_ENCODER
#define lv_demo_main lv_demo_keypad_encoder
#elif LV_USE_DEMO_MUSIC
#define lv_demo_main lv_demo_music
#elif LV_USE_DEMO_STRESS
#define lv_demo_main lv_demo_stress
#else
#error "Select a demo application to start"
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们可以在menuconfig中选择想使用的demo
程序讲解
main.c 分析 —— 程序入口与主循环
main 函数
int main(void)
{
rt_err_t ret = RT_EOK;
rt_uint32_t ms;
/* init littlevGL */
ret = littlevgl2rtt_init("lcd");//初始化lvgl的显示驱动和输入设备
if (ret != RT_EOK)
{
return ret;
}
lv_demo_main(); // 启动指定的 demo(根据宏定义)
while (1)
{
ms = lv_task_handler(); // 处理 LVGL 内部任务调度器
rt_thread_mdelay(ms);
}
return RT_EOK;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
lv_demo_benchmark.c 分析 —— Benchmark 核心逻辑
1、入口函数:lv_demo_benchmark()
//入口函数
void lv_demo_benchmark(void)
{
scene_act = 0;
lv_obj_t *scr = lv_screen_active();//获取当前屏幕
lv_obj_remove_style_all(scr);//移除样式
...
load_scene(scene_act);//加载场景
lv_timer_create(next_scene_timer_cb, scenes[0].scene_time, NULL);//创建定时器,切换场景
#if LV_USE_PERF_MONITOR
...
#endif
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2、场景加载函数:load_scene(uint32_t scene)
static void load_scene(uint32_t scene)
{
lv_obj_t *scr = lv_screen_active();
lv_obj_clean(scr); // 清除当前屏幕内容
...
if (scenes[scene].create_cb) scenes[scene].create_cb();//执行当前场景的创建回调函数
}
2
3
4
5
6
7
3、场景自动切换next_scene_timer_cb(lv_timer_t *timer)
static void next_scene_timer_cb(lv_timer_t *timer)
{
scene_act++; //增加 scene_act 索引,加载下一个场景
load_scene(scene_act); //如果当前场景时间设为 0,则结束测试并调用 summary_create()
if (scenes[scene_act].scene_time == 0)//
{
lv_timer_delete(timer);
summary_create();
}
else//否则更新定时器周期,继续循环播放场景
{
lv_timer_set_period(timer, scenes[scene_act].scene_time);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
4、场景描述结构体:scene_dsc_t
typedef struct
{
const char *name;
void (*create_cb)(void);
uint32_t scene_time;
uint32_t cpu_avg_usage;
uint32_t fps_avg;
uint32_t render_avg_time;
uint32_t flush_avg_time;
uint32_t measurement_cnt;
} scene_dsc_t;
2
3
4
5
6
7
8
9
10
11
示例场景定义
static scene_dsc_t scenes[] =
{
{.name = "Empty screen", .scene_time = 3000, .create_cb = empty_screen_cb},
{.name = "Moving wallpaper", .scene_time = 3000, .create_cb = moving_wallpaper_cb},
...
{.name = "", .create_cb = NULL}
};
2
3
4
5
6
7
5、性能监控模块: 注册观察者
lv_subject_add_observer_obj(&disp->perf_sysmon_backend.subject, sysmon_perf_observer_cb, title, NULL);
观察者回调函数
static void sysmon_perf_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
const lv_sysmon_perf_info_t *info = lv_subject_get_pointer(subject);//获取系统监控信息(获取当前帧的 FPS、CPU 使用率、渲染/刷新耗时等信息)
...
scenes[scene_act].cpu_avg_usage += info->calculated.cpu;
scenes[scene_act].fps_avg += info->calculated.fps;//累计到当前场景的数据中供后续统计使用
...
}
2
3
4
5
6
7
8
6、总结界面生成:
创建表格控件
lv_obj_t *table = lv_table_create(lv_screen_active());
填充数据
for (i = 0; scenes[i].create_cb; i++)
{
lv_table_set_cell_value(table, i + 2, 0, scenes[i].name);
...
}
2
3
4
5
7、输出日志
LV_LOG("%s, %"LV_PRIu32"%%, %"LV_PRIu32", %"LV_PRIu32", %"LV_PRIu32", %"LV_PRIu32"\r\n",
scenes[i].name,
scenes[i].cpu_avg_usage / cnt,
scenes[i].fps_avg / cnt,
...
);
2
3
4
5
6
8、动画系统详解
传入动画结构体:lv_anim_t,并启动动画 static void color_anim(lv_obj_t *obj) //颜色动画 static void color_anim_cb(void *obj, int32_t v) //颜色动画回调函数
static void arc_anim(lv_obj_t *obj) //弧线动画 static void arc_anim_cb(void *obj, int32_t v) //弧线动画回调函数
static void scroll_anim(lv_obj_t *obj, int32_t y_max)//滚动动画 static void scroll_anim_y_cb(void *var, int32_t v) //滚动动画回调函数
static void shake_anim(lv_obj_t *obj, int32_t y_max) //摇晃动画 static void shake_anim_cb(void *obj, int32_t v) //摇晃动画回调函数
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, color_anim_cb);
...
lv_anim_start(&a);//启动动画
2
3
4
5
动画特性:
- 可以设置动画时长、方向、重复次数等
- 回调函数绑定具体对象属性变化(颜色、位置、角度等)
9、UI 组件构建示例:card_create()
static lv_obj_t *card_create(void)
{
lv_obj_t *panel = lv_obj_create(lv_screen_active());//创建容器
...////添加图像、标签、按钮等子组件
lv_obj_t *child = lv_label_create(panel);
...//设置布局和样式
return panel;
}
2
3
4
5
6
7
8
完整调用链路图
main()
│
├── littlevgl2rtt_init() → 初始化 LVGL 运行环境
│
├── lv_demo_benchmark() → 启动 benchmark demo
│ │
│ ├── load_scene(0) → 加载第一个场景
│ │ └── scenes[0].create_cb() => empty_screen_cb()
│ │
│ ├── lv_timer_create(...) → 创建定时器,定时切换场景
│ │
│ └── sysmon_perf_observer_cb → 性能数据采集回调
│
└── while (1)
└── lv_task_handler() → LVGL 主任务调度
2
3
4
5
6
7
8
9
10
11
12
13
14
15