目录
前言
一、数据类型
二、页面调度
三、页面显示
四、视频展示
前言
最近在用LVGL写一个简单的UI界面,需要进行几个页面的切换,所以就自己写了一个简单页面切换代码,方便进行页面切换,同时使UI代码结构更加清晰。这个结构主要用于嵌入式MCU上使用,所以结构比较简单。
一、数据类型
typedef struct ui_show_t
{
struct ui_show_t *last;
uint32_t *ui;
}ui_show_t;
这个页面切换代码会用到一个类似链表的结构,每个界面都会定义一个这样的数据数据结构,用来保存上一个页面的指针。如下图所示:
这样每切换到下一页面的时候都可以根据需要来切换到上一页面。
同时我定义了页面的函数类型:
typedef struct ui_show_t * (*ui_show_fun)(ui_show_t* ui_show,ui_opera_t ui_opera)
除了上面提到ui_show_t类型,还有一个ui_opera_t,这个类型定义了页面的操作设备,例如触摸屏、实体按键、旋转按钮等等,我的设备是旋转按钮,所以就定义了如下的类型:
typedef struct
{
int8_t dir_cnt; //旋转方向计数
btn_sta_t btn_sta; //按键状态
}ui_opera_t;
这样就可以操作我的屏幕进行页面切换了。
二、页面调度
对于页面的调用是单独创建了一个任务,在这个任务的循环里面获取旋转按钮的状态以及进行页面的显示。可以看到最终显示的是 my_show_ui->ui 这个页面,这个页面在初始化的时候被赋值了ln_lvgl_mainwindow这个函数指针,这个函数就是用来显示主页面的函数。
#include "ln_lvgl_ui.h"
lv_ui guider_ui;
static ui_show_t my_start_ui;
static ui_show_t *my_show_ui = NULL;
ui_opera_t my_ui_opera;
static OS_Thread_t g_lvgl_ui_thread;
#define LVGL_UI_TASK_STACK_SIZE 4*40*256 //Byte
void ui_show_scheduler(void *params);
ui_show_t* ln_lvgl_mainwindow(ui_show_t* ui_show,ui_opera_t ui_opera);
ui_show_t* ln_lvgl_lightwindow(ui_show_t* ui_show,ui_opera_t ui_opera);
int ln_lvgl_ui_init()
{
ln_drv_rotate_btn_init(); //旋转按钮初始化
lv_init(); //LVGL初始化
lv_port_disp_init(); //显示设备初始化
setup_ui(&guider_ui); //第一个页面初始化
//创建页面显示调度任务
if(OS_OK != OS_ThreadCreate(&g_lvgl_ui_thread, "LVGL Task", ui_show_scheduler, NULL, OS_PRIORITY_BELOW_NORMAL, LVGL_UI_TASK_STACK_SIZE)) {
return HAL_ERROR;
}
return HAL_OK;
}
void ui_show_scheduler(void *params)
{
//对第一个页面的链表进行数据初始化
my_start_ui.last = NULL;
my_start_ui.ui = (uint32_t*)ln_lvgl_mainwindow;
my_show_ui = &my_start_ui;
while(1)
{
//获取旋转按钮的旋转方向计数以及按键状态
my_ui_opera.dir_cnt = ln_drv_rotate_btn_get_dir();
my_ui_opera.btn_sta = (btn_sta_t)ln_drv_rotate_btn_get_press();
if(my_ui_opera.dir_cnt != 0){
LOG(LOG_LVL_ERROR, "cnt :%d \r\n", my_ui_opera.dir_cnt);
}
//显示对应UI
my_show_ui = (ui_show_t*)(*((ui_show_fun)(my_show_ui->ui)))((ui_show_t*)my_show_ui,my_ui_opera);
//LVGL函数
lv_timer_handler();
//延时1ms
OS_MsDelay(1);
}
}
三、页面显示
#include "ln_lvgl_mainwindow.h"
//在这里定义了一个这个页面的链表方便存储上一个页面的指针
static ui_show_t my_mainwindow_ui;
ui_show_t* ln_lvgl_mainwindow(ui_show_t* ui_show,ui_opera_t ui_opera)
{
static uint8_t show_flag = 0;
static int8_t cur_show_item = 0;
static int8_t last_show_item = -1;
if(show_flag == 0){
//显示页面,只需要显示一次就可以
show_flag = 1;
}
//根据旋转编码器不同的值,来执行不同的操作
cur_show_item += 0 - ui_opera.dir_cnt;
if(cur_show_item != last_show_item){
switch(cur_show_item){
case 0:{
break;
}
case 1:{
break;
}
}
}
last_show_item = cur_show_item;
//按键长按和短按也都可以执行不同的操作,例如长按返回上一个页面,短按进入下一页面
if(ui_opera.btn_sta == SHORT_PRESS){
//短按进入下一个页面,下一个页面自行定义,直接赋值就好
switch(cur_show_item){
case 0:{
my_mainwindow_ui.last = ui_show;
my_mainwindow_ui.ui = (uint32_t*)ln_lvgl_lightwindow;//例如此处显示灯光页面
ui_show = &my_mainwindow_ui;
show_flag = 0;
break;
}
case 3:{
my_mainwindow_ui.last = ui_show;
my_mainwindow_ui.ui = (uint32_t*)ln_lvgl_timewindow;//例如此处显示时间页面
ui_show = &my_mainwindow_ui;
show_flag = 0;
break;
}
}
}
if(ui_opera.btn_sta == LONG_PRESS){
//长按进入上一个页面(如果有的话)
if(ui_show->last != NULL){
//直接赋值
ui_show = ui_show->last;
}
}
//返回赋值后的指针地址
return ui_show;
}