ESP32でST7735 TFT LCD液晶ディスプレイを使ってみる

ESP32でST7735 TFT LCD液晶ディスプレイを使ってみる

この記事では、ST7735チップ搭載のTFT LCD液晶ディスプレイをESP32で使う方法をまとめました。ディスプレイデバイスとはSPI接続します。ライブラリを使えばプログラミングは簡単です。ESP32だけでなく、他のArduinoでも動作しますのでぜひご参考ください。

ゴール

こちらのツイートのように、ESP32とTFT LCD、ローターリーエンコーダーを使って、数字を表示するまでをこの記事のゴールとします。このシステムはPTCヒーターを使った温度制御に組み込む予定です。

つかうもの

この記事で使うものをご紹介いたします。

TFT LCD(ST7735)

こちらの、ST7735チップ搭載のTFT LCDを使用しました。ピン端子はあらかじめ半田付けされていました。

スペックは次のとおりです。

項目
サイズ 1.8インチ
表示モード TFT
入力データ SPIインタフェース
ドライブIC ST7735S
解像度 128RGB×160ポイント
アクティブエリアLCD 28.03(W)×35.04(H)
動作温度 -20〜70℃

前回のArduinoでTFT LCDディスプレイ(ST7789)を使ってみるで使用したST7789と違って、こちらの製品にはCS(チップセレクト)端子があります。ですから複数のSPIデバイスを接続できます。画面も1.8インチと若干大きめですが、ドット数は128×160になります。

ESP32

今回はST7735のLCDを、ESP32で動かしてみます。こちらのWayinTopさんから販売されているESP32を使ってみました。技適マークも刻印されていますので、安心して使えますね。GPIOの役割図は 商品ページ に詳しく掲載されています。

2個セットで値段も安く、秋月電子通商さんのESP32と同じ形で38ピンあります。

WayinTopのESP32
WayinTopのESP32

▼ WiFiやBluetooth接続が必要なければ、他のArduinoでも構いません。こちらの記事で色々な種類のArduinoをご紹介していますので、ご参考になさってみてください。

その他

また、ブレッドボードやジャンプワイヤもあると便利です。

TFT LCDとESP32の配線

TFT LCDとESP32は次のとおり配線しました。BKLピンは使いません。

ESP32とTFT LCDの配線
ESP32とTFT LCDの配線

Arduino Unoで使う場合、3.3V端子から電圧を供給すると表示が不安定でした。ですから、5V電源に繋いでいます。TFT LCDにはレギュレーターらしきものが設置されているので、5Vの電圧でも大丈夫かと。

TFT LCD ESP32 Arduino Uno 説明
BLK 未接続 未接続 バックライト制御
CS 5 10 チップセレクト
DC 2 8 データ/コマンド制御
RES 4 9 リセット信号入力
SDA 23 11 シリアルデータ入力
SCL 18 13 シリアルクロック
VCC 3.3V 5V 電源
GND GND GND Ground

ライブラリのインストール

ST7735搭載のTFT LCDを動かすには、最低限 Adafruit_GFX Adafruit_SPITFT Adafruit_ST77xx Adafruit_ST7735 gfxfont が必要になります。下記GitHubリポジトリからインストールするなりしてください。

私は最近、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.ini には次のように記述し、test_display.inoを対象にESP32とArduino Unoの開発環境でビルドできるようにしています。

[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

数字をカウントアップして表示させる

前回の記事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倍以上です。動画のように、ESP32の方は滑らかに数値が表示されますが、Arduino Unoの方は若干フリッカーが気になります。とはいえ、前回のST7789ほどではないです。こちらのLCDは128×160ドットだったのに対し、前回は240x240ドットでしたから、その分の負荷の差も大きいでしょう。

ロータリーエンコーダーを追加して数値を自在に操る

最後にこの記事のゴールである、ロータリーエンコーダーで数値を自在に操ることをやってみましょう。ロータリーエンコーダーの使い方の詳しくはM5StickC PLUSとロータリーエンコーダをご覧ください。

ESP32とTFT LCDとローターリーエンコーダーの配線

ロータリーエンコーダーは秋月電子通商さんのものを使いました。A、Bの2信号の位相差出力となっています。

ロータリーエンコーダーを使うにあたって、プルアップ抵抗が必要になります。ここではESP32内蔵のプルアップ機能を使いました。ESP32のIO34~IO39はプルアップしないので、他の配線に変更する際はご注意ください。

ESP32とTFT LCDとローターリーエンコーダーの配線
ESP32とTFT LCDとローターリーエンコーダーの配線

ライブラリのインストール

ロータリーエンコーダーのプログラミングはかなり複雑なので、素直にライブラリを使いましょう。

▼ 下記サイトより、RotaryEncoderのライブラリRotaryEncoder.hRotaryEncoder.cpp 拾ってきます。

また、Org_01.h を追加してTFT LCDに表示させる文字のフォントを変えてみました。Org_01.hAdafruit-GFX-Library に同包されています。

.ttf フォントからC++のヘッダーファイルに変換してくれるツールも配布されています。

さて、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)

最初で紹介した、Twitter動画のソースコードです。ロータリーエンコーダーを回すことで、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;
記事に関するご質問などがあれば、お問い合わせ までご連絡ください。
関連記事