ESP32 LVGL开发一 移植与例程

简介

LVGL(轻量级和通用图形库)是一个免费和开源的图形库,提供UI通信元素的构建接口与较低资源实现的源码,适用于快速开发UI图形交互页面的应用

官方已经适配了ESP32硬件平台,库版本为v7.11,开箱即用
如有异议,欢迎留言指正

特性
  • 强大的构建块,例如按钮、图表、列表、滑块、图像等。
  • 带有动画、抗锯齿、不透明度、平滑滚动的高级图形
  • 各种输入设备,如触摸板、鼠标、键盘、编码器等。
  • 多语言支持 UTF-8 编码多显示器
  • 支持,即同时使用多个 TFT、单色显示器
  • 具有类似 CSS 样式的完全可定制的图形元素
  • 独立于硬件:与任何微控制器或显示器一起使用
  • 可扩展:能够以很少的内存运行(64 kB Flash,16 kB RAM)
  • 支持但不要求操作系统、外部存储器和 GPU
  • 即使具有高级图形效果,也可进行单帧缓冲区操作
  • 用 C 编写以获得最大的兼容性(C++ 兼容)
  • 在没有嵌入式硬件的 PC 上启动嵌入式 GUI 设计的模拟器
  • 绑定到 MicroPython快速 GUI 设计的教程、示例、主题
  • 文档可在线获取并以 PDF 格式
  • 提供在 MIT 许可下免费和开源
硬件要求
名称 最小配置 建议配置
架构 支持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 或更新版本
软件源码
系统框架

ESP32 LVGL开发一 移植与例程_第1张图片

源码下载

建议IDF使用v4.0以上版本,github仓库地址,克隆到本地并同步子模块

工程结构
  • lvgl:核心图像库
  • lv_drivers:适配显示驱动,适配了主流芯片方案的驱动代码
  • lv_examples:例程代码,内部提供了刷屏与压测的实例
工程配置

使用命令配置工具idf.py menuconfig,通过Kconfig文件,来适配具体的硬件与例程的选择

  • 适配控制器驱动:路径Componenet config-->LVGL TFT Display controller,选择驱动与适配PIN脚
    ESP32 LVGL开发一 移植与例程_第2张图片

  • 修改分辨率与颜色深度:路径Componenet config-->LVGL configuration
    在这里插入图片描述

  • 触摸控制器:路径Componenet config-->LVGL Touch controller,不带触摸的选None
    ESP32 LVGL开发一 移植与例程_第3张图片

  • 选择实例demo:路径Componenet config-->LVGL Touch controller,可以选择需要演示的例程
    在这里插入图片描述

处理流程

ESP32 LVGL开发一 移植与例程_第4张图片

代码解读
  • app_main入口中创建了guiTask任务,截取guiTask内部分代码
    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); //是否互斥信号
        }
    }
  • 运行应用函数lv_demo_widgets,例程执行了小部件动画的演示
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
}
对象结构lv_obj_t

在LVGL中,用户接口的基础构建块是对象(面向对象的编程思想),比如button、lable、image,通过lv_obj_t定义具体的属性,组件子类可继承父类对象
ESP32 LVGL开发一 移植与例程_第5张图片

运行效果

LVGL官方文档下载

你可能感兴趣的:(ESP32,esp32,lvgl,esp32,gui,esp32图形库)