ESP32でST7735 TFT LCD液晶ディスプレイを使ってみる
この記事では、ST7735チップ搭載のTFT LCD液晶ディスプレイをESP32で使う方法をまとめました。ディスプレイデバイスとはSPI接続します。ライブラリを使えばプログラミングは簡単です。ESP32だけでなく、他のArduinoでも動作します。
ゴール
こちらの動画のように、ESP32とTFT LCD、ローターリーエンコーダーを使って、数字を表示するまでをこの記事のゴールとします。このシステムはPTCヒーターを使った温度制御に組み込む予定です。
つかうもの
この記事で使うものをご紹介いたします。
TFT LCD(ST7735)
こちらのST7735チップ搭載のTFT LCDを使用しました。Arduino開発では一番よく使っているディスプレイです。ピン端子はあらかじめはんだ付けされてます。
スペックは次のとおりです。
項目 | 値 |
---|---|
サイズ | 1.8インチ |
表示モード | TFT |
入力データ | SPIインタフェース |
ドライブIC | ST7735S |
解像度 | 128RGB×160ポイント |
アクティブエリアLCD | 28.03(W)×35.04(H) |
動作温度 | -20〜70℃ |
前回の ArduinoでTFT LCDディスプレイ(ST7789)を使ってみる で使用したST7789と違って、こちらの製品にはCS(チップセレクト)端子があります。ですから複数のSPIデバイスを接続できます。SPI通信の場合は必ずCSがついているものを選ぶようにしましょう。
▼ 解像度が128x128のものもあります。
ESP32
今回はST7735をESP32で動かしました。以下、私がよく使っている技適が通っているESP32を紹介しておきます。
秋月電子通商さんで販売されているESP32と同じで、38ピン備わってます。
無線通信の必要ない場合は、普通のArduinoでも構いません。
その他
また、ブレッドボードやジャンプワイヤもあると便利です。
TFT LCDとESP32の配線
TFT LCDとESP32は次のとおり配線しました。BLピンは使いません。
TFT LCD | ESP32 | Arduino Uno | 説明 |
---|---|---|---|
BL | 未接続 | 未接続 | バックライト制御 |
CS | 5 | 10 | チップセレクト |
DC | 2 | 8 | データ/コマンド制御 |
RES | 4 | 9 | リセット信号入力 |
SDA | 23 | 11 | シリアルデータ入力 |
SCL | 18 | 13 | シリアルクロック |
VCC | 3.3V | 5V | 電源 |
GND | GND | GND | Ground |
Arduino Unoで使う場合、3.3V端子から電圧を供給すると表示が不安定でした。ですから、5V電源に繋いでいます。TFT LCDにはレギュレーターが設置されているので、5Vの電圧でも大丈夫なようになってます。
ライブラリのインストール
ST7735搭載のTFT LCDを動かすには、最低限 Adafruit_GFX Adafruit_SPITFT Adafruit_ST77xx Adafruit_ST7735 gfxfont が必要になります。事前に下記GitHubリポジトリからインストールしてください。
GitHub - adafruit/Adafruit-GFX-Library: Adafruit GFX graphics core Arduino library, this is the 'core' class that all our other graphics libraries derive from GitHub - adafruit/Adafruit-ST7735-Library: This is a library for the Adafruit 1.8" SPI display http://www.adafruit.com/products/358 and http://www.adafruit.com/products/618
私は最近、VS CodeにPlatformIOを入れてArduino開発してます。そのため下記のような構成でライブラリを配置してます。基本ライブラリマネージャーは使っておらず、ソースコードをそのままダウンロードして配置させてます。ここでは display_test.ino にサンプルプログラムを記述しました。
.
├── include
│ └── README
├── lib
│ ├── README
│ └── TFT_ST7735
│ ├── Adafruit_GFX.cpp
│ ├── Adafruit_GFX.h
│ ├── Adafruit_SPITFT.cpp
│ ├── Adafruit_SPITFT.h
│ ├── Adafruit_ST7735.cpp
│ ├── Adafruit_ST7735.h
│ ├── Adafruit_ST77xx.cpp
│ ├── Adafruit_ST77xx.h
│ ├── examples
│ │ └── test_display
│ │ └── test_display.ino
│ ├── gfxfont.h
│ └── glcdfont.c
├── platformio.ini
├── src
│ └── main.cpp
└── test
└── README
[platformio]
src_dir = lib/TFT_ST7735/examples/test_display
[env:esp32]
platform = https://github.com/platformio/platform-espressif32.git
board = esp32dev
framework = arduino
monitor_speed = 115200
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#2.0.2
[env:uno]
platform = atmelavr
board = uno
framework = arduino
monitor_speed = 115200
ST7735に数字を表示してみる
前回の記事 ArduinoでTFT LCDディスプレイ(ST7789)を使ってみる の最後で紹介したプログラムを、ST7735版に書き換えました。詳しい説明は前回の記事をご覧ください。
ソースコード(test_display.ino)
/**
* @date 2022-11-22
* @author Toshihiko Arai
* @copyright https://101010.fun
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#if defined(ESP32)
#define TFT_RST 4 // IO4
#define TFT_DC 2 // IO2
//#define TFT_MOSI 23 // VSPID
//#define TFT_SCLK 18 // VSPICLK
//#define TFT_BACKLIGHT 7 // IO7
#define TFT_CS 5 // VSPICS0
#else
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
#endif
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
int number = 0;
void setup(void) {
Serial.begin(115200);
tft.initR(INITR_GREENTAB);
tft.fillScreen(ST77XX_MAGENTA);
tft.setRotation(1);
tft.setTextWrap(false);
tft.setTextSize(2);
tft.setCursor(5, 5);
tft.print("Ready...");
delay(3000);
}
void loop() {
char buff[4];
sprintf(buff, "%2d", number); // 数字を右寄せで表示させるため
tft.setTextWrap(false);
tft.fillScreen(ST77XX_MAGENTA);
tft.setCursor(20, 30);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(10);
tft.println(buff);
delay(500);
number++;
}
こちらの動画ではESP32とArduino Unoを使って、ST7735 LCDに文字表示をしている様子がご覧いただけます。
画面のチラつき問題(フリッカー)
TFTディスプレイで文字表示を更新する際に、以前から気になっていた画面のチラつき(フリッカー)。ST7735だとだいぶ改善されてます。Arduino Unoの内部クロック周波数は16MHzだったのに対し、ESP32では標準クロック周波数が240MHzと10倍以上の性能が1つの要因でしょう。動画をみて貰えば分かりますが、ESP32の方は滑らかに数値が表示されるのに対し、Arduino Unoでは若干フリッカーが気になります。とはいえ、前回のST7789ほどではないです。こちらのLCDは128×160ドットだったのに対し、前回は240x240ドットでしたから処理速度の差も大きいのでしょう。
【発展】ロータリーエンコーダーを追加して数値を自在に操る
最初に紹介しました記事のゴールである「ロータリーエンコーダーで数値を自在に操る」ことをやってみましょう。ロータリーエンコーダーの使い方の詳しくは M5StickC PLUSとロータリーエンコーダ をご覧ください。
ESP32とTFT LCDとローターリーエンコーダーの配線
ロータリーエンコーダーは秋月電子通商さんのものを使いました。A、Bの2信号の位相差出力です。 ロータリーエンコーダ(ノンクリックタイプ): パーツ一般 秋月電子通商-電子部品・ネット通販
ロータリーエンコーダーを使うにあたって、プルアップ抵抗が必要になります。ここではESP32内蔵のプルアップ機能を使いました。ただし、ESP32のIO34~IO39はプルアップできないのでご注意ください。
ライブラリのインストール
ロータリーエンコーダーのプログラミングはかなり複雑なので、ライブラリを使うと良いです。
▼ 下記サイトより、RotaryEncoderのライブラリRotaryEncoder.h と RotaryEncoder.cpp 拾ってきます。 GitHub-mathertel / Rotary Encoder : Rotary Encoder Arduino Library
また、Org_01.h を追加してTFT LCDに表示させる文字のフォントを変えてみました。Org_01.h は Adafruit-GFX-Library に同包されてます。 Adafruit-GFX-Library/Fonts at master · adafruit/Adafruit-GFX-Library · GitHub
▼ .ttf フォントからC++のヘッダーファイルに変換してくれるツールも配布されてます。 Adafruit-GFX-Library/fontconvert at master · adafruit/Adafruit-GFX-Library · GitHub
私のPlatform IOのツリー構造は下記の通りです。 with_pot.ino に新しくプログラミングしていきます。
.
├── include
│ └── README
├── lib
│ ├── README
│ └── TFT_ST7735
│ ├── Adafruit_GFX.cpp
│ ├── Adafruit_GFX.h
│ ├── Adafruit_SPITFT.cpp
│ ├── Adafruit_SPITFT.h
│ ├── Adafruit_ST7735.cpp
│ ├── Adafruit_ST7735.h
│ ├── Adafruit_ST77xx.cpp
│ ├── Adafruit_ST77xx.h
│ ├── Org_01.h
│ ├── RotaryEncoder.cpp
│ ├── RotaryEncoder.h
│ ├── examples
│ │ ├── test_display
│ │ │ └── test_display.ino
│ │ └── with_pot
│ │ └── with_pot.ino
│ ├── gfxfont.h
│ └── glcdfont.c
├── platformio.ini
├── src
│ └── main.cpp
└── test
└── README
ソースコード(with_pot.ino)
下記は、最初に紹介した動画のソースコードです。ロータリーエンコーダーを回すことで、TFTディスプレイに映される数値が変化します。ローターリーエンコーダの上限下限を設けるようにしてあります。詳しくはソースコードないの注釈をご覧ください。
/**
* @date 2022-11-22
* @author Toshihiko Arai
* @copyright https://101010.fun
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <RotaryEncoder.h>
#include <SPI.h>
#include <Org_01.h>
/**
* @brief TFT LCD ST7735
*/
#define TFT_RST 4 // IO4
#define TFT_DC 2 // IO2
//#define TFT_MOSI 23 // VSPID
//#define TFT_SCLK 18 // VSPICLK
//#define TFT_BACKLIGHT 7 // IO7
#define TFT_CS 5 // VSPICS0
/**
* @brief Rotary Encoder用のPIN
* ESP32のIO34~IO39はプルアップしないので注意
*/
#define RE_A 25
#define RE_B 26
/**
* @brief LimitedRotator.inoを参考に、ロタリーエンコーダーの上限、下限を設定
* https://github.com/mathertel/RotaryEncoder/blob/master/examples/LimitedRotator/LimitedRotator.ino
*/
#define ROTARYSTEPS 1
#define ROTARYMIN 10
#define ROTARYMAX 60
/**
* @brief ST77XX_REDなどの色がおかしいので自分で定義している
* https://forum.arduino.cc/t/st7735-0-96-160x80-shows-wrong-colors/894996
*/
const uint16_t RED = 0x001f;
const uint16_t BLUE = 0xf800;
const uint16_t GREEN = 0x07e0;
const uint16_t YELLOW = RED | GREEN;
const uint16_t ORANGE = 0x02df;
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
RotaryEncoder encoder(RE_A, RE_B, RotaryEncoder::LatchMode::TWO03);
int lastPos = -1;
void clearDisplay() {
tft.fillScreen(RED);
}
void setup(void) {
Serial.begin(115200);
tft.initR(INITR_GREENTAB);
clearDisplay();
tft.setRotation(1);
tft.setTextWrap(false);
tft.setFont(&Org_01);
tft.setTextSize(2);
tft.setCursor(20, 20);
tft.print("Ready...");
// pinMode(RE_A, INPUT_PULLUP); RotaryEncoderのコンストラクタでプルアップされているので必要ない
// pinMode(RE_B, INPUT_PULLUP);
encoder.setPosition(25 / ROTARYSTEPS);
delay(2000);
}
void loop() {
encoder.tick(); // just call tick() to check the state.
int newPos = encoder.getPosition() * ROTARYSTEPS;
if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;
} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if
if (lastPos != newPos) {
lastPos = newPos;
char buff[5];
sprintf(buff, "%2d", newPos); // 数字を右寄せで表示させるため
tft.setTextWrap(false);
clearDisplay();
tft.setCursor(20, 15);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
tft.println("Target temperature:");
tft.setCursor(20, 80);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(10);
tft.println(buff);
delay(50);
}
}
TFT LCDの色がおかしい
ソースコードのコメントにも書きましたが、ST77XX_RED などの一部の色が青色になってしまい、TFT LCDの色がおかしいバグがあります。そのため、独自で定義して色を反映させてます。
const uint16_t RED = 0x001f;
const uint16_t BLUE = 0xf800;
const uint16_t GREEN = 0x07e0;
const uint16_t YELLOW = RED | GREEN;
const uint16_t ORANGE = 0x02df;