ESP32とタッチパネル付きLCDモニターが一体となった製品でArduinoとLVGLを使った画面デザインを行う方法の基本的な手順。
モジュールはESP32-2432S028Rをベースに説明するが、異なるLCDでもTFT制御が異なるだけでLVGLのデザイン部分は共通。
TFT制御はTFT_eSPIのライブラリを使用、User_Setup.hの設定ファイルにモジュールに合わせてピン等の設定を行う。ESP32-2432S028Rの場合は下記製品ページ
https://www.aliexpress.com/item/1005004502250619.html
の説明ページにライブラリや各種サンプルが入ったファイルへのリンクが貼られており、そこから入手できる。
http://pan.jczn1688.com/directlink/1/ESP32%20module/2.8inch_ESP32-2432S028R.rar
動作に最低限必要なTFT_eSPIとTFT_Touchのみzipしたファイルを下記に置いておく。これらのファイルはarduinoのlibrariesフォルダーに入れておく(C:\Users\ユーザー名\Documents\Arduino\libraries)。
LVGL(Light and Versatile Graphics Library)
LVGLは様々なマイコン等で綺麗で動きのある画面デザインを容易に開発出来るライブラリ。
アニメーションやタッチ操作等も処理してくれるので、マイコンでのUIも難しい事を考えずに綺麗に作る事が出来る。
今回はLVGLをとりあえず動かす説明として、単純な時計表示のみ行う。
画面デザインには画像やフォントの追加、配置等容易に行えるSquareline Studioを使用する。
SquareLine Studio
有償プランもあるが、マイコンの小機能で個人利用であればフリープランで十分使う事が出来る。サイトからソフトをダウンロードしてインストールする。インストール後、起動しデザインを作成、ターゲットとしてArduino、メモリ使用量を抑える為Color Depthを16bitにしておく。

左側に配置出来るウィジェットがあるが、いきなりサンプルにある様な綺麗なUIを作ろうとしてもその様な美麗なUIが最初から入っている訳では無いので、別途準備する必要がある。

今回は背景画像と文字だけの簡単な時計を作成する。背景画像を320×240のサイズで作成し、UI上で追加するかSquareLineのフォルダーのassetsフォルダーに直接コピーする。
適当に背景を書いてみて取り込む。


Assetsに画像を入れたら、上の画面デザインの所にドラッグ&ドロップするだけ。
各ウィジェットの上下関係は左上のツリーで、プロパティは右下で調整する。

時計用の文字をウィジェットのLabelをドラッグして追加する。
右側の設定で位置や文字色、フォント等を設定する。

独自のフォントやフォントサイズを追加する場合は、ttfファイルをassetsに入れる。
フォントの選択には下記サイトを使うと各フォントとテキストのプレビューが一覧表示され便利。フォントにもライセンスや用途により費用がかかるので注意。Windowsに入っているフォントはc:\windows\fonts にある。
ttcファイル等複数のttfファイルが一緒になっているファイルはunitettcで分解可能。
https://qiita.com/maboy/items/9f64d406c830aab548b1
ttfファイルはassetsフォルダー直下に置いても認識されるが、fontsフォルダーを作ってそこに入れておくとごちゃごちゃせずに済む。
右側のタブをFont Managerに切り替え、分かり易いフォント名、フォントファイル、フォントサイズを設定しCreateで作成(変換)する。文字サイズや対象文字(数字やアルファベットのみであればASCII Standardで良い)を増やすとそれだけマイコンのメモリを消費する事になる。

フォント作成後右側のLabelのプロパティのテキストでフォントとして選択出来る様になるので、作成したフォントを指定する。

デザインが出来たらExportメニューからCreate Template Projectを選択し、適当なフォルダーを指定する。

指定したフォルダーにライブラリやサンプルのスケッチが生成される。

Arduino IDEでのビルド
生成された libraries/lvgl/src フォルダーの中にある lv_conf_internal.h のファイル41行目の「../../lv_conf.h」を「../lv_conf.h」に修正しておく。

生成されたファイルのlibrariesフォルダー下にある「lv_conf.h」を「lvgl」のフォルダーの中にコピーし、lvglのフォルダーをArduino/librariesのフォルダーにコピーする。
lv_conf.hは画面デザインのプロジェクト毎にユニークとなるため、スケッチをビルドする度lvglのフォルダーを修正する必要がある(inoのコメントを見るとpreference設定のパスにスケッチの親フォルダー、つまりSquareLine Studioからエクスポートしたフォルダーを設定しろと書かれているがそれも面倒)。

librariesフォルダーにあるuiフォルダーの中には今回作成した画面デザインのデータが入っている。こちらもArduino/librariesフォルダーにコピーしても良いが、プロジェクト毎に変更するのも面倒なのでこちらはスケッチと一緒に管理する。
スケッチ(xxxx.ino)が入っているフォルダーにsrcサブフォルダーを作成し、そこにlibrariesの中にあるuiフォルダーをコピーする。

inoファイルを開き、行頭付近にあるui.hのincludeを修正する
#include <lvgl.h>
#include <TFT_eSPI.h>
#include "src/ui/ui.h"
これでボードをESP32 Dev Moduleとして選択(ESP32のArduino IDE開発については省略)し、ボードに書き込めばデザインした画面が表示される。

NTP時計にする場合、ui.ino をベースにした場合下記の様にWiFi関係と描画更新関係を追加する。
#include <lvgl.h>
#include <TFT_eSPI.h>
#include "src/ui/ui.h"
#include <time.h>
#include <WiFi.h>
const char* ssid = "ssid";
const char* password = "password";
#define JST 3600*9 //日本のタイムゾーン
unsigned long last_time_update;
char chbuff[64];
/*Don't forget to set Sketchbook location in File/Preferencesto the path of your UI project (the parent foder of this INO file)*/
/*Change to your screen resolution*/
static const uint16_t screenWidth = 320;
static const uint16_t screenHeight = 240;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ screenWidth * screenHeight / 10 ];
TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */
////中略/////////////////////////////////
ui_init();
Serial.println( "Setup done" );
Serial.print("Connecting Wifi");
WiFi.mode(WIFI_STA);
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.begin(ssid, password);
}
while (WiFi.status() != WL_CONNECTED) {
delay(5);
}
//NTPサーバーと時計を同期する
configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
}
void loop()
{
lv_timer_handler(); /* let the GUI do its work */
delay(5);
if (millis() - last_time_update >= 1000) {
//1秒毎に描画更新
last_time_update = millis();
time_t t;
struct tm *tm;
t = time(NULL);
tm = localtime(&t);
sprintf(chbuff, "%02d:%02d", tm->tm_hour, tm->tm_min);
lv_label_set_text(ui_Label2, chbuff);
}
}
文字の更新は
lv_label_set_text(ui_Label2, chbuff);
の様に行う。文字の色変更は
lv_obj_set_style_text_color(ui_Label2, lv_color_hex(0xFF7700), LV_PART_MAIN | LV_STATE_DEFAULT );
の様に記述する。
最初の引数のui_Label2はSquareLine Studioでデザインした際のNameがベースとなる。
