入门 ESP-IOT-SOLUTION 专题四:通过 lvgl_example 示例及 lv_sim_eclipse_sdl 示例来理解 LittlevGL

在这篇博客中,我们将根据 esp-iot-solution 中的示例 lvgl_example 和 LittlevGL 中的示例 littlevgl/lv_sim_eclipse_sdl。我们在这里使用的 esp-iot-solution 版本 commit为: 40cec13

可通过以下命令确认:

git log --oneline -1

结果为:

40cec13 Merge branch 'master' of https://github.com/espressif/esp-iot-solution

lv_sim_eclipse_sdl 可以无需使用开发板,直接在 PC 端上模拟运行 LittlevGL,具体教程见 ESP32 快速入门(五): LittlevGL PC Simulator 使用入门。

1. LittlevGL 介绍

如果需要了解具体的 LittlevGL 向导,请参考 LittlevGL Guide。


2. lvgl_example 示例浅析

我们先查看 app_main 函数:

extern "C" void app_main()
{
    /* Initialize LittlevGL GUI */
    lvgl_init();

#ifdef LVGL_EXAMPLE
    /* littlevgl demo */
    littlevgl_demo();

    xTaskCreate(
        user_task,   //Task Function
        "user_task", //Task Name
        1024,        //Stack Depth
        NULL,        //Parameters
        1,           //Priority
        NULL);       //Task Handler
#endif

#ifdef LVGL_TEST_THEME
    lv_theme_t *th = lv_theme_alien_init(100, NULL);
    lv_test_theme_1(th);
#endif

    ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
    ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
}

此示例首先使用 lvgl_init() 函数来初始化 LittlevGL,然后通过两个 ifdef 来决定是否进入 LVGL_EXAMPLE 示例与 LVGL_TEST_THEME 示例。在这里,我们可以分别查看这两个示例的具体内容。

注意:使用 LittlevGL 时别忘了添加对应的头文件,在程序开头添加 #include "iot_lvgl.h"

2.1 LVGL_EXAMPLE 示例

在上述的 app_main 函数中,我们可以看到此函数里运行了 littlevgl_demo() 函数配置 demo 与 xTaskCreate() 函数来创建任务进行定时刷新数据。

2.1.1 littlevgl_demo()

在此函数中,首先就是 screen 等对象的创建:

    lv_obj_t *scr = lv_obj_create(NULL, NULL);
    lv_scr_load(scr);

    lv_theme_t *th = lv_theme_alien_init(100, NULL);
    lv_theme_set_current(th);

    lv_obj_t *tabview = lv_tabview_create(lv_scr_act(), NULL);

    lv_obj_t *tab1 = lv_tabview_add_tab(tabview, SYMBOL_LOOP);
    lv_obj_t *tab2 = lv_tabview_add_tab(tabview, SYMBOL_HOME);
    lv_obj_t *tab3 = lv_tabview_add_tab(tabview, SYMBOL_SETTINGS);
    lv_tabview_set_tab_act(tabview, 1, false);

我们可以看到这段代码创建了 screen,theme 和 tab 对象,并设置了初始状态。然后此示例就开始在添加的三个 tab 中进行进一步的操作,在这里我们以后续的 tab 2 为例:

    chart = lv_chart_create(tab2, NULL);
    lv_obj_set_size(chart, 300, 150);
    lv_chart_set_point_count(chart, 20);
    lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);
    lv_chart_set_type(chart, (lv_chart_type_t)(LV_CHART_TYPE_POINT | LV_CHART_TYPE_LINE));
    lv_chart_set_series_opa(chart, LV_OPA_70);
    lv_chart_set_series_width(chart, 4);
    lv_chart_set_range(chart, 0, 100);
    series = lv_chart_add_series(chart, LV_COLOR_RED);

我们可以看到这里创建了一个 chart,然后将 chart 的一系列属性进行设置,比如 size, type, range 等。

2.1.2 xTaskCreate()

我们日常先看相关代码:

static void user_task(void *pvParameter)
{
    uint8_t value = 0;
    while (1)
    {
        value = esp_random() % 100;
        lv_chart_set_next(chart, series, value);
        lv_gauge_set_value(gauge, 0, value);
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

在这段代码中,我们可以发现此任务每隔 500 ms 就设置新的 chart 和 gauge 值,设置的值 value 通过 esp_random() % 100 随机生成。

2.2 LVGL_TEST_THEME 示例

在上述的 app_main 函数中,我们可以看到此函数里运行了 lv_theme_alien_init() 函数与 lv_test_theme_1() 函数。

2.2.1 lv_theme_alien_init()

这个函数主要就是 fond 与 style 的配置,然后再初始化一系列需要用到的组件,比如 gauge_init()btn_init() 等。

2.2.2 lv_test_theme_1()

这函数里的内容较少,所以我们直接贴出代码:

void lv_test_theme_1(lv_theme_t * th)
{
    lv_theme_set_current(th);
    th = lv_theme_get_current();    /*If `LV_THEME_LIVE_UPDATE  1` `th` is not used directly so get the real theme after set*/
    lv_obj_t * scr = lv_cont_create(NULL, NULL);
    lv_scr_load(scr);
    lv_cont_set_style(scr, th->bg);


    lv_obj_t * tv = lv_tabview_create(scr, NULL);
    lv_obj_set_size(tv, LV_HOR_RES, LV_VER_RES);
    lv_obj_t * tab1 = lv_tabview_add_tab(tv, "Tab 1");
    lv_obj_t * tab2 = lv_tabview_add_tab(tv, "Tab 2");
    lv_obj_t * tab3 = lv_tabview_add_tab(tv, "Tab 3");

    create_tab1(tab1);
    create_tab2(tab2);
    create_tab3(tab3);
}

这个函数的功能是创建一个包含很多对象的测试屏幕,并在其上应用给定的主题。比如他创建了一个 screen 对象,在此基础上又创建了 tabview 等。


3. lv_sim_eclipse_sdl 示例浅析

我们仍然直接查看 main 函数:

int main(int argc, char ** argv)
{
    (void) argc;    /*Unused*/
    (void) argv;    /*Unused*/

    /*Initialize LittlevGL*/
    lv_init();

    /*Initialize the HAL (display, input devices, tick) for LittlevGL*/
    hal_init();

    /*Create a demo*/
    demo_create();

    while(1) {
        /* Periodically call the lv_task handler.
         * It could be done in a timer interrupt or an OS task too.*/
        lv_task_handler();
        usleep(5 * 1000);

#ifdef SDL_APPLE
        SDL_Event event;

        while(SDL_PollEvent(&event)) {
#if USE_MOUSE != 0
            mouse_handler(&event);
#endif

#if USE_KEYBOARD
            keyboard_handler(&event);
#endif

#if USE_MOUSEWHEEL != 0
            mousewheel_handler(&event);
#endif
        }
#endif
    }

    return 0;
}

我们可以很清晰地看出首先通过 lv_init()hal_init() 进行了 LittlevGL 和 HAL 的初始化。然后就使用 demo_create() 函数创建 demo,在这个函数中与 lvgl_example 示例类似,也是初始化一些基础参数和 img,tabview 等对象的创建与配置,最后通过 while(1) 循环检测是否使用了 mouse, keyboard 和 mousewheel。

你可能感兴趣的:(ESP32)