esp-idf 移植 lvgl8.3.3

一、准备材料

  1. 开发板:esp32s3
  2. idf版本:4.4.2
  3. lvgl:8.3.3

注意:lvgl不要选择master分支,编译失败时不好确定问题。

二、创建idf项目

方式一

通过 VSCode 创建项目

  1. 在命令面板中搜索 esp-idf new,开始创建项目

  2. 项目配置信息

  3. 选择需要的模板,也可以选择想要的案例

注意: 需要VSCode 中安装 idf 环境的可以看我之前的笔记VSCode 中安装 esp-idf

方式二

通过命令创建项目

  idf.py create-project

方式三

直接在路径 %ESP-IDF%\espressif\frameworks\esp-idf-v4.4.2\examples 中拷贝自己需要的使用案例

三、添加LVGL库

  1. 下载lvgl8.3.3
    GitHub:https://github.com/lvgl/lvgl.git

  2. 将lvgl库添加到项目的 components 文件中,如下图所示

    注意:如果觉得文件比较多的话,可以删除不用的文件,如下图所示:

  3. 将 lv_conf_template.h 重命名为 lv_conf.h ,并将文件中的 #if 0 改为 #if 1

    注意:如果不习惯使用图形配置LVGL信息的话,直接删除文件 Kconfig 即可,并且检查文件 lv_conf.h名称是否正确,否则会提示:Possible failure to include lv_conf.h, please read the comment in this file if you get errors 异常

  4. 设置开发板为esp32s3

  5. 编译

    ** 注意:**如果出现编译错误时,检查一下自己是否下载成了master分支

四、添加显示驱动

  1. 下载lvgl_esp32_drivers
    GitHub:https://github.com/lvgl/lvgl_esp32_drivers

  2. 使用命令 idf.py menuconfig 打开图形配置界面

  3. 进入 Component config → LVGL ESP Drivers → LVGL TFT Display controller 配置显示驱动信息

    注意:可以通过 Display orientation 更改屏幕的显示方向

  4. SPI引脚配置

  5. 进入 Component config → LVGL configguration 配置LVGL信息

  6. 按s键进行保存,完成后按Q退出

  7. 配置屏幕信息和SPI通道数量
    编译后会产生以下错误,如果所示
    未定义显示器的像素宽度和高度

    未定义开发板 SPI 的通道数量

    只需要在文件 lvgl_helpers.h 中添加以下定义即可,如图所示

      #define SPI_HOST_MAX 3 // 开发板 SPI 通道数量
      #define LV_HOR_RES_MAX 240 // 显示器水平像素
      #define LV_VER_RES_MAX 320 // 显示器垂直像素

  8. 编译通过后,在 main.c 文件中添加程序,程序后面附上

  9. SPI 信道错误

    运行后不断重启,并出现图示中的问题,值需要在文件 `` 中将SPI信道改为自动模式 SPI_DMA_CH_AUTO 即可,如下图所示:

到此屏幕就能正常显示了。

五、添加触摸驱动

  1. 使用命令 idf.py menuconfig 打开图形配置界面

  2. 进入 Component config → LVGL ESP Drivers → LVGL Touch controller 打开触摸驱动

  3. 返回上一级,选择I2C通道

  4. 进入 Component config → I2C Port Settings 配置I2C引脚

六、main.c文件

  #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 "driver/gpio.h"
   
  /* Littlevgl specific */
  #ifdef LV_LVGL_H_INCLUDE_SIMPLE
  #include "lvgl.h"
  #else
  #include "lvgl/lvgl.h"
  #endif
   
  #include "lvgl_helpers.h"
   
  /*********************
  * DEFINES
  *********************/
  #define TAG "main"
  #define LV_TICK_PERIOD_MS 1
   
  /**********************
  * STATIC PROTOTYPES
  **********************/
  static void lv_tick_task(void *arg);
  static void guiTask(void *pvParameter);
  static void create_demo_application(void);
   
  /**********************
  * APPLICATION MAIN
  **********************/
  void app_main() {
   
  /* 使用任务创建图形时,必须使用固定任务创建
  * 注意:不使用Wi-Fi或蓝牙时,可以将gui任务固定到核心0 */
  xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 0, NULL, 1);
  }
   
  /* 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;
   
  static void guiTask(void *pvParameter) {
   
  (void) pvParameter;
  xGuiSemaphore = xSemaphoreCreateMutex();
   
  lv_init();
   
  /* 初始化驱动程序使用的SPI或I2C总线 */
  lvgl_driver_init();
   
  /* 创建堆内存,用过图形缓冲区buf1 */
  lv_color_t* buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_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_draw_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_draw_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.draw_buf = &disp_buf;
  lv_disp_drv_register(&disp_drv);
   
  /* Register an input device when enabled on the menuconfig */
  #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
   
  /* 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));
   
  /* Create the demo application */
  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();
  xSemaphoreGive(xGuiSemaphore);
  }
  }
   
  /* A task should NEVER return */
  free(buf1);
  #ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
  free(buf2);
  #endif
  vTaskDelete(NULL);
  }
   
  /**
  * @brief 创建标签
  */
  void lvgl_lable_test(){
  /* 创建一个标签 */
  lv_obj_t* label = lv_label_create(lv_scr_act());
  if (NULL != label)
  {
  // lv_obj_set_x(label, 90); // 设置控件的X坐标
  // lv_obj_set_y(label, 100); // 设置控件的Y坐标
  // lv_obj_set_size(label, 60, 20); // 设置控件大小
  lv_label_set_text(label, "Counter"); // 初始显示 0
  // lv_obj_center(label); // 居中显示
  lv_obj_align(label, LV_ALIGN_CENTER, 0, -50); // 居中显示后,向上偏移50
  }
  }
   
  /**
  * @brief 按钮事件回调函数
  */
  static void btn_event_callback(lv_event_t* event)
  {
  static uint32_t counter = 1;
   
  lv_obj_t* btn = lv_event_get_target(event); //获取事件对象
  if (btn != NULL)
  {
  lv_obj_t* btn_parent = lv_obj_get_parent(btn);
  lv_obj_t* label = lv_obj_get_child(btn_parent, 0);
  lv_label_set_text_fmt(label, "%d", counter); //设置显示内容
  lv_obj_align(label, LV_ALIGN_CENTER, 0, -50); // 居中显示后,向上偏移50
  counter++;
  }
  }
   
  /**
  * @brief 创建按钮
  */
  void lvgl_button_test(){
  /* 在当前界面中创建一个按钮 */
  lv_obj_t* btn = lv_btn_create(lv_scr_act()); // 创建Button对象
  if (btn != NULL)
  {
  lv_obj_set_size(btn, 80, 20); // 设置对象宽度和高度
  // lv_obj_set_pos(btn, 90, 200); // 设置按钮的X和Y坐标
  lv_obj_add_event_cb(btn, btn_event_callback, LV_EVENT_CLICKED, NULL); // 给对象添加CLICK事件和事件处理回调函数
  lv_obj_align(btn, LV_ALIGN_CENTER, 0, 50); // 居中显示后,向下偏移50
   
  lv_obj_t* btn_label = lv_label_create(btn); // 基于Button对象创建Label对象
  if (btn_label != NULL)
  {
  lv_label_set_text(btn_label, "button"); // 设置显示内容
  lv_obj_center(btn_label); // 对象居中显示
  }
  }
  }
   
  static void create_demo_application(void)
  {
  /* 加载标签 */
  lvgl_lable_test();
  /* 加载按钮 */
  lvgl_button_test();
   
  }
   
  static void lv_tick_task(void *arg) {
  (void) arg;
   
  lv_tick_inc(LV_TICK_PERIOD_MS);
  }
   

问题

  1. LVGL 字体显示不清晰
    出现是字体不清晰,并且白色背景时,颜色不是纯白的现象

    解决办法
    将文件 lv_conf.h 中的 LV_COLOR_16_SWAP RGB565 字节交换打开,这个现象应该是大小端导致的,具体原因我没有深究,如下图所示:

本文来自博客园,作者:浇筑菜鸟,转载请注明原文链接:https://www.cnblogs.com/jzcn/p/16759863.html

如本博客的内容侵犯了你的权益,请与以下地址联系,本人获知后,马上删除。同时本人深表歉意,并致以崇高的谢意! cn_jiaozhu@qq.com

posted @ 2024-04-03 15:37  苍月代表我  阅读(208)  评论(0)    收藏  举报