前言
我们在上篇中已经实现了模拟器环境下可变字体字重的设置.
是时候掏出你吃灰已久的ESP32了.
本文会使用PlatformIO创建一个全新的项目,直到显示出现上篇文章末尾的动图为止.
如遇到问题,可参考常见问题内解答.
准备工作
软件准备
为了后续内容顺利进行下去,这里需要你安装好VSCode,并在VSCode上安装PlatformIO插件.
硬件准备
名称 | 数量 | 备注 | 图例 |
:-: | :-: | :-:
ESP32 开发板 | 1 | \ | 
1.54寸LCD | 1 | 驱动ST7789,分辨率240x240 |  
杜邦线若干 | N | \ | 
创建项目
使用PlatformIO创建一个名为lvgl_with_freetype的项目

创建完毕后目录结构如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | .├── include
 │   └── README
 ├── lib
 │   └── README
 ├── platformio.ini
 ├── src
 │   └── main.cpp
 └── test
 └── README
 
 | 
点亮屏幕
由于已经写过一篇点亮屏幕的文章,故本文不做过多赘述,只说明一下区别.
之前的屏幕分辨率是135x240,这次的屏幕分辨率是240x240.
所以需要使用TFT_eSPI里面的Setup24_ST7789.h
同时接线变更为
| ESP32引脚名称 | 液晶屏引脚名称 | 
| VCC | VCC | 
| GND | GND | 
| G23 | SDA | 
| G18 | SCL | 
| G2 | DC | 
| G4 | RES | 
| GND | CS | 
| VCC | BLK | 
对应Setup24_ST7789.h里面内容
Setup24_ST7789.h| 12
 3
 4
 5
 6
 
 | #define TFT_MISO    19#define TFT_MOSI    23
 #define TFT_SCLK    18
 #define TFT_CS      -1
 #define TFT_DC      2
 #define TFT_RST     4
 
 | 
 
随便写点内容.测试下屏幕的点亮.
main.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | #include <Arduino.h>#include <TFT_eSPI.h>
 #include <SPI.h>
 
 TFT_eSPI tft = TFT_eSPI();
 
 void setup() {
 Serial.begin(115200);
 
 tft.init();
 tft.setRotation(0);
 tft.fillScreen(TFT_BLACK);
 }
 
 void loop() {
 tft.print("Ready Perfectly");
 }
 
 | 
 

移植LVGL
屏幕点亮以后,就可以开始移植LVGL了.
当前时间为2021.12.19,GitHub上LVGL最新版本是8.1.1-dev
使用命令
| 1
 | git clone https://github.com/lvgl/lvgl.git
 | 
获取LVGL后将其复制到lib文件夹下.此时文件目录为
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | .├── include
 │   └── README
 ├── lib
 │   └── README
 │   └── lvgl
 │   └── TFT_eSPI
 ├── platformio.ini
 ├── src
 │   └── main.cpp
 └── test
 └── README
 
 | 
platformio.ini文件内容
| 12
 3
 4
 5
 6
 7
 8
 
 | [env:pico32]platform = espressif32
 board = pico32
 framework = arduino
 monitor_speed = 115200
 lib_extra_dirs =
 lib/TFT_eSPI
 lib/lvgl
 
 | 
修改LVGL配置文件
创建LVGL的配置文件,找到lvgl文件夹内的lv_conf_templat.h,复制一份lv_conf_templat.h并重命名为lv_conf.h,然后打开lv_conf.h
为了使配置文件内容生效,找到第15行(其他版本的lvgl行数可能不在这里,需要自行寻找)
改为
找到第30行,修改颜色顺序
| 1
 | #define LV_COLOR_16_SWAP 0
 | 
改为
| 1
 | #define LV_COLOR_16_SWAP 1
 | 
找到第49行,启用自定义内存管理
修改为
找到第88行,设置自定义周期函数
| 1
 | #define LV_TICK_CUSTOM 0
 | 
修改为
| 1
 | #define LV_TICK_CUSTOM 1
 | 
找到第174行,启用LVGL日志功能
修改为
对接LVGL和TFT_eSPI
按照目录
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | .├── include
 │   └── README
 ├── lib
 │   └── README
 │   └── lvgl
 │   └── TFT_eSPI
 ├── platformio.ini
 ├── src
 │   └── main.cpp
 │   └── Port
 │       └── lv_port_disp.cpp
 │       └── lv_port_disp.h
 └── test
 └── README
 
 | 
创建lv_port_disp.cpp和lv_port_disp.h
lv_port_disp.h| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | #ifndef LV_PORT_DISP_H_#define LV_PORT_DISP_H_
 
 #include "TFT_eSPI.h"
 #include "lvgl.h"
 
 #define DISP_HOR_RES 240
 #define DISP_VER_RES 240
 #define DISP_BUF_SIZE (DISP_HOR_RES*DISP_VER_RES/4)
 
 extern TaskHandle_t handleTaskLvgl;
 void Port_Init();
 void lv_port_disp_init(TFT_eSPI* scr);
 
 #endif
 
 | 
 
lv_port_disp.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 
 | #include "lv_port_disp.h"
 
 TaskHandle_t handleTaskLvgl;
 
 static lv_disp_drv_t disp_drv;
 
 
 void TaskLvglUpdate(void* parameter) {
 
 ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
 for (;;) {
 lv_task_handler();
 
 delay(5);
 }
 }
 
 
 
 
 
 
 void Port_Init() {
 static TFT_eSPI screen;
 
 
 screen.begin();
 screen.initDMA(true);
 screen.setRotation(0);
 screen.fillScreen(TFT_BLACK);
 
 
 lv_init();
 lv_port_disp_init(&screen);
 printf("lvInitDone\n");
 
 xTaskCreatePinnedToCore(TaskLvglUpdate, "LvglThread", 20480, nullptr,
 configMAX_PRIORITIES, &handleTaskLvgl, 1);
 }
 
 
 
 
 
 
 void my_print(lv_log_level_t level, const char *file, uint32_t line,
 const char *fun, const char *dsc) {
 Serial.printf("%s@%d %s->%s\r\n", file, line, fun, dsc);
 Serial.flush();
 }
 
 
 
 
 
 
 
 
 static void disp_flush_cb(lv_disp_drv_t *disp, const lv_area_t *area,
 lv_color_t *color_p) {
 TFT_eSPI *screen = (TFT_eSPI *)disp->user_data;
 
 int32_t w = (area->x2 - area->x1 + 1);
 int32_t h = (area->y2 - area->y1 + 1);
 
 screen->startWrite();
 screen->setAddrWindow(area->x1, area->y1, w, h);
 screen->pushPixelsDMA((uint16_t *)(&color_p->full), w * h);
 screen->endWrite();
 
 lv_disp_flush_ready(disp);
 }
 
 
 
 
 
 
 
 void lv_port_disp_init(TFT_eSPI* scr) {
 lv_log_register_print_cb(reinterpret_cast<lv_log_print_g_cb_t>(
 my_print));
 DMA_ATTR static lv_color_t *lv_disp_buf =
 static_cast<lv_color_t *>(heap_caps_malloc(
 DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA));
 static lv_disp_draw_buf_t disp_buf;
 lv_disp_draw_buf_init(&disp_buf, lv_disp_buf, nullptr,
 DISP_BUF_SIZE);
 
 
 lv_disp_drv_init(&disp_drv);
 disp_drv.hor_res = DISP_HOR_RES;
 disp_drv.ver_res = DISP_VER_RES;
 disp_drv.flush_cb = disp_flush_cb;
 disp_drv.draw_buf = &disp_buf;
 disp_drv.user_data = scr;
 lv_disp_drv_register(&disp_drv);
 }
 
 | 
 
再写个简单例子测试下LVGL能不能运行
main.cpp| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | #include <Arduino.h>#include "./Port/lv_port_disp.h"
 
 void setup() {
 Serial.begin(115200);
 Port_Init();
 
 
 lv_obj_t *label = lv_label_create(lv_scr_act());
 lv_label_set_text(label, "Toou.\nAnata wa watashi no masuta ka?");
 
 
 xTaskNotifyGive(handleTaskLvgl);
 }
 
 void loop() {
 
 }
 
 | 
 
Toou.Anata wa watashi no masuta ka?

施工中,待更新
常见问题
Q:点亮屏幕时候,编译器报找不到TFT_eSPI
A:检查TFT_eSPI是否集成
将TFT_eSPI放置在lib文件夹内,并向platformio.ini文件末尾添加
| 1
 | lib_extra_dirs =  lib/TFT_eSPI
 | 
Q:在移植LVGL时候,屏幕颜色异常
A:可能与lv_conf.h文件内#define LV_COLOR_16_SWAP 0有关
可以尝试将此处的0改成1,或1改回0
环境:
| 12
 3
 4
 5
 6
 7
 
 | Espressif 32 (3.4.0) > ESP32 Pico Kitframework-arduinoespressif32 3.10006.210326 (1.0.6)
 tool-esptoolpy 1.30100.210531 (3.1.0)
 toolchain-xtensa32 2.50200.97 (5.2.0)
 <lvgl> 8.1.1-dev
 <TFT_eSPI> 2.3.89
 esptool.py v3.1
 
 | 
参考资料