ESP32联动LVGL开发日记(二)-简单显示任务创建

ESP32联动LVGL开发日记(二)-简单显示任务创建

上一章,我安装了软件和简单演示了一下使用例程,有兴趣的话也可以切换一下其他例程进行一下显示。在开始之前推荐一个LVGL学习的网站:百问网-LVGL,这个网站简直是学习LVGL的利器。

一.近期学习成果(显示+按键操作,本节只讲创建一个显示)

按键显示及特效操作视频:

ESP32联动LVGL学习开发日记(二)

二.lv_port_esp32中的LVGL组件介绍

①主目录:
在这里插入图片描述
②components:
在这里插入图片描述
③LVGL的整体系统框架

转载自百问网
④本教程主要讲解如何使用LVGL创建显示一个区域及显示一个按键

三.显示一个屏幕区域

①要使用LVGL在屏幕上创建一个显示,需要先初始化以下几个部分:

a-初始化lvgl,初始化驱动屏幕的外设(ST7789使用的是SPI)
 	 /* Initialize lvgl */ 
    lv_init();
    /* Initialize SPI or I2C bus used by the drivers */
    lvgl_driver_init();
b-设置显示的缓存buf,一个或者两个,并初始化他们:

(此处的代码可以直接用demo里的代码,注释掉guitask里面的create_demo_application()函数,开始修改guitask函数。)

    lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1 != NULL);

    /* Use double buffered when not working with monochrome displays */
#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
c-初始化lvgl的显示组件

(这里也可以直接使用demo里面的函数部分)

    /* Initialize the working buffer depending on the selected display.
     * NOTE: buf2 == NULL when using monochrome displays. */
    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;

    /* When using a monochrome display we need to register the callbacks:
     * - rounder_cb
     * - set_px_cb */
#ifdef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    disp_drv.rounder_cb = disp_driver_rounder;
    disp_drv.set_px_cb = disp_driver_set_px;
#endif

    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

d-创建并启动一个周期性计时器中断来调用lv_tick inc

(非常重要,非常重要,不创建启动,LVGL显示就无法更新,血的教训)

    /* Create and start a periodic timer interrupt to call lv_tick_inc */
    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));
至此显示所需要的基础初始化就设置完成了,接下来要进行屏幕的创建了

②在屏幕上创建一个显示:

a-创建一个显示,并加载,设置显示的区域大小。并在此显示区域上创建一个label文本,编辑文本的位置和内容(具体的API函数请在文章顶部的百问网详细了解)
    lv_obj_t *scr1 = lv_obj_create(lv_scr_act(), NULL); //创建scr
                                                        //    lv_obj_set_pos(scr1, 10, 7);                        //set scr pos
    lv_obj_set_size(scr1, 240, 135);                    //creat btn size
    lv_scr_load(scr1);                                  /* 加载屏幕*/
    lv_scr_act();                                       /* 活动屏幕*/
    lv_obj_t *label1 = lv_label_create(scr1, NULL);     //    /*Create a Label on the currently active screen*/
    lv_obj_set_pos(label1, 70, 5);                      /* 移动父类对象,子类对象跟着移动 .*/
    lv_label_set_text(label1, "Hello lclr8air");

显示效果:
在这里插入图片描述

b-使用类似方式在创建一个按键显示

在屏幕scr1上创建一个按键,使能根据内容自动设置大小,设置位置。在上面创建一个文本,设置显示内容,位置

    //==============btn1=================
    lv_obj_t *btn1 = lv_btn_create(scr1, NULL);          //创建子对象btn1在父类对象中
    lv_btn_set_fit(btn1, true);                          /* 使能自动设置大小根据内容 */
    lv_obj_set_pos(btn1, 20, 30);                        //creat btn pos
    lv_obj_t *labelA = lv_label_create(btn1, NULL); //创建子对象btn1在父类对象中
    lv_obj_set_pos(labelA, 0, 0);                   /* 移动父类对象,子类对象跟着移动 .*/
    lv_label_set_text(labelA, "AaBbCcDd");

显示效果:
在这里插入图片描述

四.附上主函数全部代码

/* LVGL Example project
 *
 * Basic project to test LVGL on ESP32 based projects.
 *
 * This example code is in the Public Domain (or CC0 licensed, at your option.)
 *
 * Unless required by applicable law or agreed to in writing, this
 * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.
 */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_types.h"

/* Littlevgl specific */
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif

#include "lvgl_helpers.h"

/*********************
 *      DEFINES
 *********************/
#define Test 1

#define TAG "demo"
#define GPIO_KEY_NUM1 0
#define GPIO_KEY_NUM2 35
#define GPIO_KEY_PR 37
#define GPIO_KEY_UP 38
#define GPIO_KEY_DN 39

#define GPIO_INPUT_PIN_SEL ((1ULL << GPIO_KEY_PR) | (1ULL << GPIO_KEY_UP) | (1ULL << GPIO_KEY_DN)) //选定gpio
#define ESP_INTR_FLAG_DEFAULT 0                                                                    //设置一个flag标志位
static xQueueHandle gpio_evt_queue = NULL;                                                         //消息队列

#define LV_TICK_PERIOD_MS 1
uint16_t Counts_Gui = 0;
uint16_t Counts_Key = 0;
uint16_t DIR_Flag = 0;
gpio_config_t KeyGPIO;
/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lv_tick_task(void *arg);
static void guiTask(void *pvParameter);

/* Creates a semaphore to handle concurrent call to lvgl stuff
 * If you wish to call *any* lvgl function from other threads/tasks
 * you should lock on the very same semaphore! */
SemaphoreHandle_t xGuiSemaphore;

//------------------------------TOOLS----------------------------------

//---------------------------TASK-------------------------------------
static void lv_tick_task(void *arg)
{
    (void)arg;

    lv_tick_inc(LV_TICK_PERIOD_MS);
}

static void guiTask(void *pvParameter)
{

    (void)pvParameter;
    xGuiSemaphore = xSemaphoreCreateMutex();

    lv_init();
    /* Initialize SPI or I2C bus used by the drivers */
    lvgl_driver_init();

    lv_color_t *buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1 != NULL);

    /* Use double buffered when not working with monochrome displays */
#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;

    uint32_t size_in_px = DISP_BUF_SIZE;

#if defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_IL3820
    || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_JD79653A || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_UC8151D || defined CONFIG_LV_TFT_DISPLAY_CONTROLLER_SSD1306

                                                                                                                    /* Actual size in pixels, not bytes. */
                                                                                                                    size_in_px *= 8;
#endif

    /* Initialize the working buffer depending on the selected display.
     * NOTE: buf2 == NULL when using monochrome displays. */
    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;

    /* When using a monochrome display we need to register the callbacks:
     * - rounder_cb
     * - set_px_cb */
#ifdef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    disp_drv.rounder_cb = disp_driver_rounder;
    disp_drv.set_px_cb = disp_driver_set_px;
#endif

    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);


    /* Create and start a periodic timer interrupt to call lv_tick_inc */
    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));


    //-----------------------Creat Obj--------------------------------
    //==============scr=================
    //    lv_obj_t *scr1 = lv_scr_act();//创建scr
    lv_obj_t *scr1 = lv_obj_create(lv_scr_act(), NULL); //创建scr
                                                        //    lv_obj_set_pos(scr1, 10, 7);                        //set scr pos
    lv_obj_set_size(scr1, 240, 135);                    //creat btn size
    lv_scr_load(scr1);                                  /* 加载屏幕*/
    lv_scr_act();                                       /* 活动屏幕*/
    lv_obj_t *label1 = lv_label_create(scr1, NULL);     //    /*Create a Label on the currently active screen*/
    lv_obj_set_pos(label1, 70, 5);                      /* 移动父类对象,子类对象跟着移动 .*/
    lv_label_set_text(label1, "Hello lclr8air");

    //==============btn1=================
    lv_obj_t *btn1 = lv_btn_create(scr1, NULL);          //创建子对象btn1在父类对象中
    lv_btn_set_fit(btn1, true);                          /* 使能自动设置大小根据内容 */
    lv_obj_set_pos(btn1, 20, 30);                        //creat btn pos

    lv_obj_t *labelA = lv_label_create(btn1, NULL); //创建子对象btn1在父类对象中
    lv_obj_set_pos(labelA, 0, 0);                   /* 移动父类对象,子类对象跟着移动 .*/
    lv_label_set_text(labelA, "AaBbCcDd");
    //-----------------------Begin--------------------------------

    //    MY_GUI();
    //    lv_demo_benchmark();
    printf("LVGL init OK!\r\n"); /* 获取BOOT按键电平并打印 */
                                 //    create_demo_application();
    while (1)
    {
        /* Delay 1 tick (assumes FreeRTOS tick is 10ms */
        vTaskDelay(pdMS_TO_TICKS(10));
        // Counts_Gui++;
        // if (Counts_Gui == 100)
        // {
        //     printf("Toggle!\r\n"); /* 获取并打印 */
        //     lv_btn_toggle(btn2);
        //     Counts_Gui = 0;
        // }
        /* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY))
        {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
        }
    }
    /* A task should NEVER return */
    free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    free(buf2);
#endif
    vTaskDelete(NULL);
}


/**********************
 *   APPLICATION MAIN
 **********************/

void app_main()
{
    /* If you want to use a task to create the graphic, you NEED to create a Pinned task
     * Otherwise there can be problem such as memory corruption and so on.
     * NOTE: When not using Wi-Fi nor Bluetooth you can pin the guiTask to core 0 */
    xTaskCreatePinnedToCore(guiTask, "gui", 4096 * 2, NULL, 0, NULL, 0); //注册中断函数
}
  • 4
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
ESP32 ESP-IDF LVGL 是一种用于嵌入式系统的开发框架,LVGL 则是一个用于创建嵌入式图形界面的开源图形库。关于视频流的处理,可以通过调用 ESP-IDF 中的函数来实现。在这个项目中,作者使用了 JPEG 流封装 AVI 视频的方法,将实时读取的图片写入 AVI 文件,并保存到 SD 卡中。通过调用相关函数,如 `jpeg2avi_start`、`jpeg2avi_add_frame` 和 `jpeg2avi_end`,可以实现将一帧帧的图片构成的视频保存下来。这个方法结合了作者原理的讲解和详细的代码示例,非常值得参考和感谢作者原野追逐的贡献。在这个项目中,ESP32 通过 LVGL 图形库提供的界面,可以实时读取摄像头数据,并将视频流传输到网页上,同时将读取的图片写入 SD 卡中的 AVI 文件中。然而,由于 ESP32 的处理能力有限,同时完成读取摄像头数据、传输到网页、写入 SD 卡这三个功能对其来说是一项挑战。在测试中,视频流的帧率较低,不够流畅。因此,需要进行性能优化或者考虑其他解决方案来改善视频流的流畅度。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [VScode+esp-idf:例程(esp32-web-camera)保存视频到sd卡(附源码)](https://blog.csdn.net/hwd00001/article/details/126679619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值