LVGL(轻量级和通用图形库)是一个免费和开源的图形库,提供UI通信元素的构建接口与较低资源实现的源码,适用于快速开发UI图形交互页面的应用
官方已经适配了ESP32硬件平台,库版本为v7.11,开箱即用
如有异议,欢迎留言指正
名称 | 最小配置 | 建议配置 |
---|---|---|
架构 | 支持16位、32位、64位 | |
时钟 | >16 MHz | >48 MHz |
Flash/ROM | >64 kB | >180 kB |
静态 RAM | >2 kB | >4 kB |
栈空间 | >2 kB | >8 kB |
堆空间 | >2 kB | >8 kB |
显示缓存 | “水平分辨率”像素(建议 > 1× “水平分辨率” ) | “水平分辨率”像素(建议 > 10× “水平分辨率” ) |
编译器 | C99 或更新版本 |
建议IDF使用v4.0以上版本,github仓库地址,克隆到本地并同步子模块
使用命令配置工具idf.py menuconfig
,通过Kconfig文件,来适配具体的硬件与例程的选择
适配控制器驱动:路径Componenet config-->LVGL TFT Display controller
,选择驱动与适配PIN脚
触摸控制器:路径Componenet config-->LVGL Touch controller
,不带触摸的选None
选择实例demo:路径Componenet config-->LVGL Touch controller
,可以选择需要演示的例程
xGuiSemaphore = xSemaphoreCreateMutex();//创建互斥变量(限制多线程的访问lvgl接口)
lv_init(); //初始化 lvgl 库
lvgl_driver_init(); //初始化驱动(SPI、IIC总线)
lv_color_t* buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);//开辟支持dma服务的缓存
assert(buf1 != NULL);
//双缓存
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
lv_color_t* buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
assert(buf2 != NULL);
#else
static lv_color_t *buf2 = NULL;
#endif
static lv_disp_buf_t disp_buf;//lvgl显示缓存区
lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);//初始化工作缓存区
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.flush_cb = disp_driver_flush;//刷屏实现接口
//触摸控制器
#if CONFIG_LV_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.read_cb = touch_driver_read;
indev_drv.type = LV_INDEV_TYPE_POINTER;
lv_indev_drv_register(&indev_drv);
#endif
//创建软定时器, 内部实现 lv_tick_inc定时,处理相关lvgl任务操作
const esp_timer_create_args_t periodic_timer_args = {
.callback = &lv_tick_task,
.name = "periodic_gui"
};
esp_timer_handle_t periodic_timer;
ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));
//具体应用
create_demo_application();
while (1)
{
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
vTaskDelay(pdMS_TO_TICKS(10));
/* Try to take the semaphore, call lvgl related function on success */
if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY))//获取互斥信号
{
lv_task_handler(); //lv任务处理器
xSemaphoreGive(xGuiSemaphore); //是否互斥信号
}
}
void lv_demo_widgets(void)
{
tv = lv_tabview_create(lv_scr_act(), NULL); //创建表格对象tv
//主题设置
#if LV_USE_THEME_MATERIAL
if(LV_THEME_DEFAULT_INIT == lv_theme_material_init) {
lv_disp_size_t disp_size = lv_disp_get_size_category(NULL);
if(disp_size >= LV_DISP_SIZE_MEDIUM) {
lv_obj_set_style_local_pad_left(tv, LV_TABVIEW_PART_TAB_BG, LV_STATE_DEFAULT, LV_HOR_RES / 2);
lv_obj_t * sw = lv_switch_create(lv_scr_act(), NULL);
if(lv_theme_get_flags() & LV_THEME_MATERIAL_FLAG_DARK)
lv_switch_on(sw, LV_ANIM_OFF);
lv_obj_set_event_cb(sw, color_chg_event_cb);
lv_obj_set_pos(sw, LV_DPX(10), LV_DPX(10));
lv_obj_set_style_local_value_str(sw, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, "Dark");
lv_obj_set_style_local_value_align(sw, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, LV_ALIGN_OUT_RIGHT_MID);
lv_obj_set_style_local_value_ofs_x(sw, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, LV_DPI/35);
}
}
#endif
t1 = lv_tabview_add_tab(tv, "Controls");//新增tv1表格控件
t2 = lv_tabview_add_tab(tv, "Visuals"); //新增tv2表格控件
t3 = lv_tabview_add_tab(tv, "Selectors");//新增tv3表格控件
//初始化box样式与位置
lv_style_init(&style_box);
lv_style_set_value_align(&style_box, LV_STATE_DEFAULT, LV_ALIGN_OUT_TOP_LEFT);
lv_style_set_value_ofs_y(&style_box, LV_STATE_DEFAULT, - LV_DPX(10));
lv_style_set_margin_top(&style_box, LV_STATE_DEFAULT, LV_DPX(30));
controls_create(t1);//创建t1对象具体的组件
visuals_create(t2); //创建t2对象具体的组件
selectors_create(t3);//创建t3对象具体的组件
#if LV_DEMO_WIDGETS_SLIDESHOW
lv_task_create(tab_changer_task_cb, 8000, LV_TASK_PRIO_LOW, NULL);//创建动画切换刷新任务
#endif
}
在LVGL中,用户接口的基础构建块是对象(面向对象的编程思想),比如button、lable、image,通过lv_obj_t定义具体的属性,组件子类可继承父类对象