文章目录

  • 关于LVGL
  • 硬件软件
  • 开发环境
  • 硬件设置
  • 在移植LVGL前驱动LCD
  • TFT_eSPI驱动TFT显示屏
  • 移植LVGL
  • 编辑配置文件
  • 编辑main.cpp文件
  • 编写回调函数
  • 设置功能
  • 教程源码链接及其他

关于LVGL

  简而言之,LVGL是一个具有广泛功能的轻量图形库。基本上适用于所有的显示器,因为其本身不是LCD驱动库—它依赖于其他额外的库来驱动显示器。此外,它还是一个开源库,在此附上开源链接。

硬件软件

硬件:
· ESP32开发板
· 带有SPI接口的LCD
· USB供电线
软件:
· Platform IO(也可以使用Arduino IDE,本教程中使用前者)
· TFT_eSPI或其他显示屏驱动库(例如Adafruit GFX Library

开发环境

  对于本教程,我将使用PlatformIO开发环境。该IDE相较于Arduino IDE,个人使用感觉更加便捷容易。

  要开始使用 PlatformIO,首先,你需要下载它。实际上,它是 Visual Studio Code 的一个附加组件——可扩展的文本编辑器。

安装后,可以创建你的第一个项目。使用方法在此就不赘述。

arduino中esp32配置 arduino esp32 lvgl_arduino中esp32配置

硬件设置

本教程中,使用是的1.44寸TFT屏模块/SPI,驱动IC是ST7735,连接ESP32开发板如下

arduino中esp32配置 arduino esp32 lvgl_arduino中esp32配置_02

在移植LVGL前驱动LCD

  首先,你需要一个在 LVGL 之外工作的显示器——只有它的驱动程序库。根据显示类型(SPI、I2C、并行),有多种选择。如果你使用 Adafruit 的(或具有相同驱动器 IC 的类似 LCD)显示器,则可以使用 Adafruit 库。你还可以使用基于 Adafruit 库的Bodmer 的 TFT_eSPI库。如果你已经熟悉 eSPi 库,则可以使用它。你还可以为显示器编写你自己的几个驱动程序函数——这样你将节省一些程序内存,因为 LVGL 只需要上述库中的一些函数。本教程中使用的是TFT_eSPI。

TFT_eSPI驱动TFT显示屏

  你可以在PlatformIO中直接下载,或从GithubTFT_eSPI获取,也可以直接获取本教程的驱动代码
  将库文件添加至工程后,需要编辑修改User_Setup.h文件以满足你的要求。以下代码为本教程

#define USER_SETUP_INFO "User_Setup"

#define ST7735_DRIVER      // Define additional parameters below for this display

#define TFT_WIDTH  128
#define TFT_HEIGHT 128

#define ST7735_GREENTAB128    // For 128 x 128 display

#define TFT_MOSI 13 // In some display driver board, it might be written as "SDA" and so on.15
#define TFT_SCLK 14 //14
#define TFT_CS   15  // Chip select control pin
#define TFT_DC   27  // Data Command control pin
#define TFT_RST  4  // Reset pin (could connect to Arduino RESET pin)
#define TFT_BL   26  // LED back-ligh t

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts

// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT

#define SPI_FREQUENCY  40000000
#define SPI_READ_FREQUENCY  20000000
// #define SPI_TOUCH_FREQUENCY  2500000

此外,还需实例化一个tft对象并初始化

static const uint16_t screenWidth = 128;
static const uint16_t screenHeight = 128;

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */

/* TFT init */
tft.init(ST7735_BLACK);
tft.setRotation(0);

至此,LCD屏幕驱动完成。

移植LVGL

  当LCD屏幕启动并运行时,下一步就是使LVGL适配你的显示设置。首先,下载LVGL至你的PlatformIO工程中,下载方法同上TFT_eSPI。本教程使用的@8.2.0版本。
ps:并非本教程中所有内容对不同版本的lvgl完全适用。

编辑配置文件

  一开始我们需要配置一些 LVGL 库。转到项目中的 LVGL 文件夹,找到“lv_conf_template.h”文件。将其重命名为“lv_conf.h”。然后,打开它进行编辑。在里面你会发现一行告诉你

/*
 * Copy this file as `lv_conf.h`
 * 1. simply next to the `lvgl` folder
 * 2. or any other places and
 *    - define `LV_CONF_INCLUDE_SIMPLE`
 *    - add the path as include path
 */

“将这个文件复制并重命名为 lv_conf.h并放至lvgl文件夹”。
首先,您应该将第一个定义更改为如下所示:

#if 1

然后,找到一行:

#define LV_TICK_CUSTOM 0

使用 Arduino 时,您需要将其值更改为 1:

#define LV_TICK_CUSTOM 1

  虽然此文件中有更多设置,但需要更改这两行才能在 Arduino 系统上启动一个简单的 LVGL 示例。此外,如果你将 LV_TICK_CUSTOM 的值保留为 0,则屏幕不会定期更新或在屏幕触摸后更新。

编辑main.cpp文件

  包含LVGL库

#include "../lvgl/src/lvgl.h"

  注意到上面的 include 中有一条很长的路径。通常它应该像这样工作:

#include "lvgl.h"

  但有时 PlatformIO 决定不查找所需的头文件,你将不得不从当前文件编写一个相对路径。
  接下来,让我们创建一些变量:

static lv_disp_draw_buf_t draw_buf; //初始化显示缓冲区
static lv_color_t buf_1[screenWidth * screenHeight];//用于LVGL使用的缓冲区

lv_obj_t *screenMain;	//指向所用屏幕的实例化对象
lv_obj_t *labelName;
lv_obj_t *labelTime;
lv_obj_t *labelLocation;
lv_obj_t *labelWeather;
lv_obj_t *labelTemperature;

编写回调函数

  编写回调函数,用于将缓冲区的内容复制到显示器的特定区域。

void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors(&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

设置功能

  当我们完成以上步骤后,需要将所需代码添加至setup()函数中:

/* TFT init */
    tft.init(ST7735_BLACK);
    tft.setRotation(0);
    /*初始化显示*/
    lv_init();  //初始化lvgl库
    lv_disp_draw_buf_init(&draw_buf, buf_1, NULL, screenWidth * screenHeight); //开启双缓冲

    /*Initialize the display*/
    static lv_disp_drv_t disp_drv;  
    lv_disp_drv_init(&disp_drv);
    /*Change the following line to your display resolution*/
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = my_disp_flush;  /*Set your driver function*/
    disp_drv.draw_buf = &draw_buf;      /*Assign the buffer to the display*/
    lv_disp_drv_register(&disp_drv);    //注册显示屏

    screenMain = lv_obj_create(NULL);    //创建一个实际的屏幕对象
    labelName = lv_label_create(screenMain);
    // labelFans = lv_label_create(screenMain);  
    labelTime = lv_label_create(screenMain);
    labelLocation = lv_label_create(screenMain);
    labelWeather = lv_label_create(screenMain);
    labelTemperature = lv_label_create(screenMain);
    // imgHeadPhoto = lv_img_create(screenMain);

    while(1)
    {
        lv_label_set_long_mode(labelName, LV_LABEL_LONG_WRAP); 
        lv_label_set_text(labelName, "Hello! Yogurt");
        lv_obj_set_size(labelName, 120, 20);
        lv_obj_align(labelName, LV_ALIGN_DEFAULT, 0, 0);
        lv_obj_set_style_text_font(labelName,&lv_font_chinese_14, 0);

        lv_label_set_long_mode(labelLocation, LV_LABEL_LONG_WRAP); 
        lv_label_set_text_fmt(labelLocation, "城市: %s", location);
        lv_obj_set_size(labelLocation, 120, 20);
        lv_obj_align(labelLocation, LV_ALIGN_DEFAULT, 0, 40);
        lv_obj_set_style_text_font(labelLocation,&lv_font_chinese_14, 0);

        lv_label_set_long_mode(labelWeather, LV_LABEL_LONG_WRAP); 
        lv_label_set_text_fmt(labelWeather, "天气: %s",weather);
        lv_obj_set_size(labelWeather, 120, 20);
        lv_obj_align(labelWeather, LV_ALIGN_DEFAULT, 0, 60);
        lv_obj_set_style_text_font(labelWeather,&lv_font_chinese_14, 0);

        lv_label_set_long_mode(labelTemperature, LV_LABEL_LONG_WRAP); 
        lv_label_set_text_fmt(labelTemperature, "气温: %s度",temperature);
        lv_obj_set_size(labelTemperature, 120, 20);
        lv_obj_align(labelTemperature, LV_ALIGN_DEFAULT, 0, 80);
        lv_obj_set_style_text_font(labelTemperature,&lv_font_chinese_14, 0);

        // lv_img_set_src(imgHeadPhoto, &head_photo);
        // lv_obj_align(imgHeadPhoto, LV_ALIGN_CENTER, 64, 64);
        // lv_obj_set_size(imgHeadPhoto, 60, 60);

        lv_scr_load(screenMain); 

        lv_task_handler();
        vTaskDelay(1);
    }

  编译代码并烧录,至此,我们的LVGL移植完毕。