LGVL配合FreeType为可变字体设置字重-ESP32篇

前言

我们在上篇中已经实现了模拟器环境下可变字体字重的设置.

是时候掏出你吃灰已久的ESP32了.

本文会使用PlatformIO创建一个全新的项目,直到显示出现上篇文章末尾的动图为止.
如遇到问题,可参考"常见问题"内解答.

准备工作

软件准备

为了后续内容顺利进行下去,这里需要你安装好VSCode,并在VSCode上安装PlatformIO插件.

硬件准备

名称 数量 备注 图例
ESP32 开发板 1 \
ESP32
1.54寸LCD 1 驱动ST7789,分辨率240x240
LCD
杜邦线若干 N \
wires

创建项目

使用PlatformIO创建一个名为lvgl_with_freetype的项目


create project

创建完毕后目录结构如下:

.
├── 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里面内容

#define TFT_MISO    19
#define TFT_MOSI    23
#define TFT_SCLK    18
#define TFT_CS      -1
#define TFT_DC      2
#define TFT_RST     4

随便写点内容.测试下屏幕的点亮.

#include <Arduino.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>

TFT_eSPI tft = TFT_eSPI(); // Invoke custom library

void setup() {
  Serial.begin(115200); // Set to a high rate for fast image transfer to a PC

  tft.init();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);
}

void loop() {
  tft.print("Ready Perfectly");
}
lcd_ready_perfect

移植LVGL

屏幕点亮以后,就可以开始移植LVGL了.

当前时间为2021.12.19,GitHub上LVGL最新版本是8.1.1-dev

使用命令

git clone https://github.com/lvgl/lvgl.git

获取LVGL后将其复制到lib文件夹下.此时文件目录为

.
├── include
│   └── README
├── lib
│   └── README
│   └── lvgl
│   └── TFT_eSPI
├── platformio.ini
├── src
│   └── main.cpp
└── test
    └── README

platformio.ini文件内容

[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行数可能不在这里,需要自行寻找)

#if 0 /*Set it to "1" to enable content*/

改为

#if 1 /*Set it to "1" to enable content*/

找到第30行,修改颜色顺序

#define LV_COLOR_16_SWAP 0

改为

#define LV_COLOR_16_SWAP 1

找到第49行,启用自定义内存管理

#define LV_MEM_CUSTOM 0

修改为

#define LV_MEM_CUSTOM 1

找到第88行,设置自定义周期函数

#define LV_TICK_CUSTOM 0

修改为

#define LV_TICK_CUSTOM 1

找到第174行,启用LVGL日志功能

#define LV_USE_LOG 1

修改为

#define LV_USE_LOG 1

对接LVGL和TFT_eSPI

按照目录

.
├── 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.cpplv_port_disp.h

#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
{% endcodeblock %}

{% codeblock "lv_port_disp.cpp" lang:cpp%}
#include "lv_port_disp.h"

// 用于初始化完毕后启用LVGL显示的TaskHandle_t
TaskHandle_t handleTaskLvgl;
// lvgl显示驱动
static lv_disp_drv_t disp_drv;

// lvgl更新任务
void TaskLvglUpdate(void* parameter) {
  // 阻塞在此处,直到xTaskNotifyGive
  ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  for (;;) {
    lv_task_handler();

    delay(5);
  }
}

/**
 * @brief  显示初始化
 * @param  无
 * @retval 无
 */
void Port_Init() {
  static TFT_eSPI screen;

  /* 屏幕初始化 */
  screen.begin();
  screen.initDMA(true);
  screen.setRotation(0);
  screen.fillScreen(TFT_BLACK);

  /* lvgl初始化 */
  lv_init();
  lv_port_disp_init(&screen);
  printf("lvInitDone\n");
  // 在核心2上执行LVGL
  xTaskCreatePinnedToCore(TaskLvglUpdate, "LvglThread", 20480, nullptr,
                          configMAX_PRIORITIES, &handleTaskLvgl, 1);
}

/**
 * @brief  自定义打印函数
 * @param  无
 * @retval 无
 */
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();
}

/**
 * @brief  屏幕刷新回调函数
 * @param  disp:屏幕驱动地址
 * @param  area:刷新区域
 * @param  color_p:刷新缓冲区地址
 * @retval 无
 */
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);
}


/**
 * @brief  屏幕初始化
 * @param  无
 * @retval 无
 */
void lv_port_disp_init(TFT_eSPI* scr) {
  lv_log_register_print_cb(reinterpret_cast<lv_log_print_g_cb_t>(
      my_print)); /* register print function for debugging */
  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);

  /*Initialize the display*/
  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);
}
{% endcodeblock %}


再写个简单例子测试下LVGL能不能运行
{% codeblock "main.cpp" lang:cpp%}
#include <Arduino.h>
#include "./Port/lv_port_disp.h"

void setup() {
  Serial.begin(115200); // Set to a high rate for fast image transfer to a PC
  Port_Init();


  lv_obj_t *label = lv_label_create(lv_scr_act());
  lv_label_set_text(label, "Toou.\nAnata wa watashi no masuta ka?");
  
  // 一切就绪, 启动LVGL任务
  xTaskNotifyGive(handleTaskLvgl);
}

void loop() {

}

Toou.Anata wa watashi no masuta ka?

lvgl_ready_perfect

施工中,待更新

常见问题

Q:点亮屏幕时候,编译器报找不到TFT_eSPI

A:检查TFT_eSPI是否集成
将TFT_eSPI放置在lib文件夹内,并向platformio.ini文件末尾添加

lib_extra_dirs =  lib/TFT_eSPI

Q:在移植LVGL时候,屏幕颜色异常

A:可能与lv_conf.h文件内#define LV_COLOR_16_SWAP 0有关
可以尝试将此处的0改成1,或1改回0

环境:

Espressif 32 (3.4.0) > ESP32 Pico Kit
framework-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

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容