【Arduino】ST7789 LCDとXPT2046タッチパネルを使う

it

ST7789 LCDの表示制御をします。
IPS方式で広い視野角、高い解像度の表示モジュールです。
多くのラインナップがあり、いくつかを試してみました。
RaspberryPi PicoとESP32-WROOMで表示制御、タッチパネル、SDカードからのJPG表示します。

LCD ST7789

主な製品情報

小型のLCDで高い解像度。
IPS方式の視野角。

◆1.3inch 青基板

◆1.54inch, 1.9inch, 2.0inch 青基板

◆2.4inch 赤基板(タッチパネル、SDカードリーダモジュール有)

今回使ったのは最小1.3inch(240×240)から最大2.4inch(320×240)です。
販売されている最大のLCDドライバIC中ではサイズのカバー範囲が最も広い。

当ページで紹介するST7789の画面インチサイズと解像度の関係です。

基板名サイズ(inch)解像度(w, h)
1.3inch 青基板1.3240, 240
1.54inch 青基板1.5240, 240
1.9inch 青基板1.9170, 320
2.0inch 青基板2.0240, 320
2.4inch 赤基板2.4240, 320

赤基板にはタッチパネルの非搭載のモデル、SDカードリーダの非搭載のモデルがあります。
購入前に製品情報の確認が必要です。

◆その他のLCD

ST7735の記事です。
小型で安価、SPIで通信するLCDをRaspberry Pi Picoで表示、タッチパネル、SDカードリーダを使いました。
Nextion のHMI NX3224T024を使った記事です。
NextionEditorのセットアップと簡単な使い方、Raspberry Pi Picoと連動した画面制御について記事にしました。
ILI9341の記事です。
Arduino環境で使える中型サイズのLCDを使いました。
表示制御、タッチパネルとトラブル、SDカードからのJPG表示を記事にしました。
ILI9488の記事です。
表示制御以外にGT911静電容量式タッチパネルの多点タッチを使いました。
ESP32以外にRaspberry Pi Picoでも使用できるスケッチの修正を紹介しています。
ST7789の記事です。
IPS方式で発色のきれいなLCDです。
表示やタッチ制御以外にTNとIPS方式の視野角についても比べてみました。
SSD1331 カラーOLEDの記事です。
OLEDの鮮やかな発色と広い視野角のディスプレイです。
Raspberry Pi PicoとESP32-WROOM32での表示をしました。

ピン配置

スクリーン上の〇数字はLCD制御ライブラリ「Adafruit ST7735 and ST7789 Library by Adafruit」を使って画面の回転をさせる時、上面方向になる位置とパラメータ値を示しています。

◆1.3inch 青基板

◆1.54inch 青基板

◆1.9inch 赤基板

◆2.0inch 赤基板

◆2.4inch 赤基板

外観

◆1.3inch 青基板

◆1.54inch 青基板

◆1.9inch 赤基板

◆2.0inch 赤基板

◆2.4inch 赤基板

使用感

◆開発環境

Arduino環境で開発しました。
表示制御にRaspberry Pi Pico と ESP32-WROOM32(Node-MCU)を使いました。
LCDの制御ライブラリはAdafruitの「Adafruit ST7735 and ST7789 Library by Adafruit」を使いました。

◆青基板と赤基板

赤基板にはSDカードリーダとタッチパネル付きモデルがあります。
タッチパネルは購入時に「タッチパネル付き」または「タッチパネル無し」を選択します。
主に2.4~3.2inch あたりが販売されているようです。

青基板はLCDパネルのみのモデルのようです。
1inch台から2inch台までが販売されているようです。

青基板のうち1.3inchモデルにはCSピンがありません。
サンプルスケッチではCSが無くても表示できるサンプルで作成しています。

◆表示

ST7789のLCDはIPS方式で視野角が広い。
どの方向から見ても色合いやコントラストの変化が小さい。
同サイズのILI9341 2.4inch LCDとの比較です。

今回使ったのはこちらのST7789とILI9341です。
外観上の違いはあまりなく、タッチパネルや小さなチップ部品の有無で見分けます。

◆タッチ

赤基板にはタッチパネル付きモデルがあります。
搭載されているチップはXPT2046で、小型LCDのタッチパネルにはほとんど同じチップが使われています。
分解能は4k x 4kで、画面の解像度にリスケーリングして使います。
タッチの感度は樹脂のタッチペンで軽く押せば反応する程度で十分な感度だと思います。
座標認識や値のばらつきも小さく使いやすいと感じました。

◆SDカードリーダ

赤基板にはSDカードリーダが搭載されているモデルがあります。
電源はLCDと共通なのでSDカードリーダ側の電源配線を減らすことができますが、SDカードリーダモジュールの電源は5Vです。
SDカードリーダモジュールを使用するときは、LCDの電源も5Vにする必要があります。

準備

ライブラリ

Arduino環境ででST7789を制御するために必要なライブラリをインストールします。
使用するライブラリはST7735と同じライブラリを使用します。

ライブラリ名検索動作確認Ver
Adafruit GFX Library by AdafruitAdafruit GFX1.11.9
Adafruit ST7735 and ST7789 Library by AdafruitAdafruit ST77891.10.3

今回SDカードリーダに保存したJPG画像を表示するため以下のライブラリのインストールをします。
SDカードリーダだけを使用する場合ライブラリのインストールは不要です。

ライブラリ名検索動作確認Ver
TJpg_Decoder by Bodmerjpg1.1.0

タッチパネルを使用する場合は、以下のライブラリをインストールします。

ライブラリ名検索動作確認Ver
XPT2046_Touchscreen by Paul StoffregenXPT20461.4

使い方

RP2040系 RaspberryPi Picoを使った表示

説明

RaspberryPi PicoでのST7789の表示制御をします。
LCDの情報(固定文字列)を表示します。

そのほかの描画サンプルについては
Examples > Adafruit ST7735 and ST7789 Library > graphictest

このスケッチは今回紹介しているLCDすべてで動作します。
スケッチの上部のマクロ定義を対象のLCDだけコメントを解除し、ほかの定義はコメントにします。

#define RED_24INCH      //2.4inch 赤基板
// #define BLUE_13INCH     //1.3inch 青基板
// #define BLUE_154INCH    //1.54inch 青基板
// #define BLUE_177INCH    //1.77inch 青基板
// #define BLUE_19INCH     //1.9inch 青基板
// #define BLUE_20INCH     //2.0inch 青基板

この定義を変更することで、
・LCDの解像度
・ライブラリのSPIモード
・カラー反転状態
・CSピン設定
を各LCDに合わせた設定に変更します。

このうち1.3inchはCSピンが無く、未使用で動作するための設定(-1)にします。
カラー反転状態は2.4inch 赤基板に対してはFalse, それ以外はTrueにします。

配線

LCDモジュールにごとに配線が異なります。

1.3inch 青基板

※1.3inchのこのモデルにはCSピンはありません。

1.54inch 青基板 / 1.9inch 青基板

2.0inch 青基板

2.4inch 赤基板

スケッチ

#include <Adafruit_GFX.h> 
#include <Adafruit_ST7789.h>
#include <SPI.h>

#define TFT_CS     (17)
#define TFT_RST    (22)
#define TFT_DC     (28)
#define TFT_MOSI   (19)
#define TFT_SCK    (18)


#define RED_24INCH      //2.4inch 赤基板
// #define BLUE_13INCH     //1.3inch 青基板
// #define BLUE_154INCH    //1.54inch 青基板
// #define BLUE_19INCH     //1.9inch 青基板
// #define BLUE_20INCH     //2.0inch 青基板

#ifdef RED_24INCH             //2.4inch 赤基板
#define LCD_INCH      "2.4"
#define LCD_INVERT    (false)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

#elif defined(BLUE_13INCH)    //1.3inch 青基板
#define LCD_INCH      "1.3"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (240)
#define LCD_SPIMODE   (SPI_MODE3)
#undef TFT_CS
#define TFT_CS        (-1)

#elif defined(BLUE_154INCH)   //1.54inch 青基板
#define LCD_INCH      "1.54"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (240)
#define LCD_SPIMODE   (SPI_MODE0)

#elif defined(BLUE_19INCH)    //1.9inch 青基板
#define LCD_INCH      "1.9"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (170)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

#elif defined(BLUE_20INCH)    //2.0inch 青基板
#define LCD_INCH      "2.0"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

#endif


Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);

void setup(void) 
{
  tft.init(LCD_WIDTH, LCD_HEIGHT, LCD_SPIMODE);
  tft.invertDisplay(LCD_INVERT);
  tft.fillScreen(ST77XX_BLACK);
  
  tft.setRotation(3);
  tft.setTextSize(4);
  
  tft.setCursor(0, 10);
  tft.setTextColor(ST77XX_GREEN);
  tft.printf("TAMANEGI\n");

  tft.setTextSize(3);
  tft.setTextColor(ST77XX_RED);
  tft.printf("\n%sinch LCD\n", LCD_INCH);
  tft.setTextColor(ST77XX_YELLOW);
  tft.printf("Res=%d x %d\n", LCD_WIDTH, LCD_HEIGHT);
  tft.setTextColor(ST77XX_BLUE);
  tft.printf("ST7789\n");
}

void loop()
{
}

結果

各モジュール用にマクロ定義を変更して実行しました。
結果の画像サイズの画像は合っていません。

発色が良くLCDを斜めから見ても色味の変化が小さくきれいな表示です。
小さな画面サイズでも高い解像度なのでピクセルが細い。

ESP32系 ESP32-WROOMを使った表示

説明

ST7789 LCDをESP32-WROOM32(NODE-MCU)を使って表示制御します。
使用するLCDは代表してST7789 2.4inch 赤基板を使います。

ESP32-WROOMのSPIではデフォルトVSPIピンを使用します。
変更する場合はピン定義マクロのピン番号を変更し、スケッチ63行目のコメントを解除します。
// SPI.begin(TFT_SCK, -1, TFT_MOSI, TFT_CS);
※ボードライブラリは「esp32 by Espressif Systems」の「ESP32 Dev Module」です。

配線

VSPIを使った配線

スケッチ

#include <Adafruit_GFX.h> 
#include <Adafruit_ST7789.h>
#include <SPI.h>

#define TFT_CS     (5)
#define TFT_RST    (27)
#define TFT_DC     (26)
#define TFT_MOSI   (23)
#define TFT_SCK    (18)


#define RED_24INCH       //2.4inch 赤基板
// #define BLUE_13INCH     //1.3inch 青基板
// #define BLUE_154INCH    //1.54inch 青基板
// #define BLUE_19INCH     //1.9inch 青基板
// #define BLUE_20INCH     //2.0inch 青基板

#ifdef RED_24INCH             //2.4inch 赤基板
#define LCD_INCH      "2.4"
#define LCD_INVERT    (false)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

#elif defined(BLUE_13INCH)    //1.3inch 青基板
#define LCD_INCH      "1.3"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (240)
#define LCD_SPIMODE   (SPI_MODE3)
#undef TFT_CS
#define TFT_CS        (-1)

#elif defined(BLUE_154INCH)   //1.54inch 青基板
#define LCD_INCH      "1.54"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (240)
#define LCD_SPIMODE   (SPI_MODE0)

#elif defined(BLUE_19INCH)    //1.9inch 青基板
#define LCD_INCH      "1.9"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (170)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

#elif defined(BLUE_20INCH)    //2.0inch 青基板
#define LCD_INCH      "2.0"
#define LCD_INVERT    (true)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

#endif


Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);

void setup(void) 
{
  //SPI ピン変更をする場合コメントを解除
//  SPI.begin(TFT_SCK, -1, TFT_MOSI, TFT_CS);
  tft.init(LCD_WIDTH, LCD_HEIGHT, LCD_SPIMODE);
  tft.invertDisplay(LCD_INVERT);
  tft.fillScreen(ST77XX_BLACK);
  
  tft.setRotation(3);
  tft.setTextSize(4);
  
  tft.setCursor(0, 10);
  tft.setTextColor(ST77XX_GREEN);
  tft.printf("TAMANEGI\n");

  tft.setTextSize(3);
  tft.setTextColor(ST77XX_RED);
  tft.printf("\n%sinch LCD\n", LCD_INCH);
  tft.setTextColor(ST77XX_YELLOW);
  tft.printf("Res=%d x %d\n", LCD_WIDTH, LCD_HEIGHT);
  tft.setTextColor(ST77XX_BLUE);
  tft.printf("ST7789\n");
}

void loop()
{
}

結果

ESP32-WROOM(NODE-MCU)でST7789のLCD制御ができました。

XPT2046タッチパネル

説明

ST7789 LCDのタッチパネルXPT2046を使います。
タッチパネルを使えるST7789は 2.4inch 赤基板を使います。

タッチした箇所にドットを表示しドットをスクロールさせます。
画面の解像度は240×320ドット、タッチパネルの分解能は4Kx4Kです。
タッチ位置と画面の位置関係をリスケーリングしますが、ズレ量は現物合わせでオフセットしています。

配線

スケッチ

#include <Adafruit_GFX.h> 
#include <Adafruit_ST7789.h>
#include <SPI.h>

#include <XPT2046_Touchscreen.h>

#define TFT_CS     (17)
#define TFT_RST    (22)
#define TFT_DC     (28)
#define TFT_MOSI   (19)
#define TFT_SCK    (18)

#define TOUCH_SCK  (TFT_SCK)
#define TOUCH_MOSI (TFT_MOSI)
#define TOUCH_MISO (16)
#define TOUCH_CS   (20)
#define RADIUS     (2)

#define LCD_INCH      "2.4"
#define LCD_INVERT    (false)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);
XPT2046_Touchscreen ts(TOUCH_CS);

void setup(void) 
{
  tft.init(LCD_WIDTH, LCD_HEIGHT, LCD_SPIMODE);
 
  tft.setRotation(3);
  tft.invertDisplay(LCD_INVERT);
  tft.fillScreen(ST77XX_BLACK);
  ts.begin();
  ts.setRotation(1);
}

void loop()
{
  const int16_t Offset_x = 150;
  const int16_t Offset_y = 150;

  const int16_t tableMax = 128;
  int16_t tableX[tableMax];
  int16_t tableY[tableMax];
  boolean tableON[tableMax];
  const int16_t Radius = 3;

  memset(tableX, 0, sizeof(tableX));
  memset(tableY, 0, sizeof(tableY));

  while(1)
  {
    boolean bTouch = ts.touched();

    if (bTouch == true)
    {
      float RateX = (float)320 / (3700 - Offset_x);
      float RateY = (float)240 / (3700 - Offset_y);

      TS_Point tPoint = ts.getPoint();

      int16_t x = (float)(tPoint.x - Offset_x) * RateX;
      int16_t y = (float)(tPoint.y - Offset_y) * RateY;

      for(int16_t i = 0; i < tableMax; i ++)
      {
        if(tableON[i] == false)
        {
          tableX[i] = x;
          tableY[i] = y;
          tableON[i] = true;;
          break;
        }
      }
    }

    for(int16_t i = 0; i < tableMax; i ++)
    {
      if(tableON[i] == true)
      {
        tft.fillCircle(tableX[i], tableY[i], Radius, ST77XX_BLACK);

        if(tableX[i] > 0)
        {
          tableX[i] -= 5;
          tft.fillCircle(tableX[i], tableY[i], Radius, ST77XX_WHITE);
        }
        else
        {
           tableON[i] = false;
        }
      }
    }
    delay(10);
  }
}

結果

タッチ位置にドットを表示しスクロールできました。

表示(SDカードからjpgファイルの表示)

説明

SDカードリーダよりjpgファイル”tamanegi.jpg”を読み取り、LCDに表示をします。

SDカードのルートフォルダには”tamanegi.jpg”ファイルを保存してください。
jpgファイルのサイズは480 x 320で作成します。

こちらは今回使用したjpgファイルです。

読み出したjpg画像をランダムに決めた座標に次々表示します。

配線

SDカードリーダモジュールを使用する場合、LCDへの電源にも5Vを使用します。

スケッチ

#include <SPI.h>
#include <SD.h>

#include <TJpg_Decoder.h>
#include <Adafruit_ST7789.h>
#include <Adafruit_GFX.h>

#define TFT_CS        (17)
#define TFT_RST       (22)
#define TFT_DC        (28)
#define TFT_MOSI      (19)
#define TFT_SCK       (18)

#define LCD_INVERT    (false)
#define LCD_WIDTH     (240)
#define LCD_HEIGHT    (320)
#define LCD_SPIMODE   (SPI_MODE0)


#define SD_MOSI       TFT_MOSI
#define SD_SCK        TFT_SCK
#define SD_CS         (21)  
#define SD_MISO       (16)

#define FILENAME      "/tamanegi64.jpg"

#define JPG_SIZE_MAX (100 * 1024) //MAX 100KByteを想定

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);

struct jpg_file
{
  size_t size;
  uint8_t buf[JPG_SIZE_MAX];
};

jpg_file jpg;

bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap)
{
  if (y >= tft.height())
    return 0;

  tft.drawRGBBitmap(x, y, bitmap, w, h);

  return 1;
}

void setup()
{
  // SPI.setTX(COMMON_MOSI);
  // SPI.setRX(SD_MISO);
  // SPI.setSCK(COMMON_SCK);
  Serial.begin(115200);
  tft.init(LCD_WIDTH, LCD_HEIGHT, LCD_SPIMODE);
  tft.setRotation(3);
  tft.invertDisplay(LCD_INVERT);
  tft.fillScreen(ST77XX_BLACK);

  delay(1000);
  
  if (!SD.begin(SD_CS, SD_SCK_MHZ(8)))
  {
    Serial.println("SD initialization failed!");
    while(1);
  }

  TJpgDec.setCallback(tft_output);

  File jpgFile = SD.open(FILENAME, FILE_READ);
  if (!jpgFile)
  {
    Serial.printf("Open file failed [%s]\r\n", FILENAME);
    while(1);
  }

  jpg.size = jpgFile.size();

  if(sizeof(jpg.buf) < jpg.size) 
  {
    Serial.println("File size over");
    return;
  }

}

void loop()
{
    File jpgFile = SD.open(FILENAME, FILE_READ);
  if (!jpgFile)
  {
    Serial.printf("Open file failed [%s]\r\n", FILENAME);
    while(1);
  }

  jpg.size = jpgFile.size();

  if(sizeof(jpg.buf) < jpg.size) 
  {
    Serial.println("File size over");
    return;
  }

  uint16_t w = 0, h = 0;

  jpgFile.readBytes((char *)jpg.buf, jpg.size);
  TJpgDec.getJpgSize(&w, &h, jpg.buf, jpg.size);
  TJpgDec.setJpgScale(1);

  int16_t posX;
  int16_t posY;

  while(1)
  {
    posX = random(LCD_WIDTH);
    posY = random(LCD_HEIGHT);
    TJpgDec.drawJpg(posX, posY, jpg.buf, jpg.size);    
  }
    jpgFile.close();

}

結果

SDカード内のjpgファイルの表示をしました。
SDカードモジュールへの配線はスルーホールに秋月のテストワイヤを使っています。
配線の図とは違うワイヤー色を使っているので注意。

ST7789とILI9341表示比較

説明

RaspberryPi PicoでのST7789とILI9341を表示制御をします。
LCDにそれぞれのモジュール情報(固定文字列)を表示します。

SPI0を使いCSによりLCDモジュールを選択しています。
隣り合わせで同等程度のテキスト情報を表示し、映り具合や視野角の違いを確認します。

配線

CS以外は共通の配線。

スケッチ

#include <Adafruit_GFX.h> 
#include <Adafruit_ST7789.h>
#include <Adafruit_ILI9341.h>
#include <SPI.h>

#define TFT_CS      (17)
#define TFT_RST     (22)
#define TFT_DC      (28)
#define TFT_MOSI    (19)
#define TFT_SCK     (18)

#define ILI9341_CS  (16)
Adafruit_ST7789 st7789 = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);
Adafruit_ILI9341 ili9341 = Adafruit_ILI9341(&SPI, TFT_DC, ILI9341_CS, TFT_RST);

void setup(void) 
{

  ili9341.begin();

  st7789.init(240, 320, 0);
  st7789.invertDisplay(false);
  st7789.fillScreen(ST77XX_BLACK);
  
  st7789.setRotation(3);
  st7789.setTextSize(4);
  
  st7789.setCursor(0, 10);
  st7789.setTextColor(ST77XX_GREEN);
  st7789.printf("TAMANEGI\n");

  st7789.setTextSize(3);
  st7789.setTextColor(ST77XX_RED);
  st7789.printf("\n2.4inch LCD\n");
  st7789.setTextColor(ST77XX_YELLOW);
  st7789.printf("Res=240 x 320\n");
  st7789.setTextColor(ST77XX_BLUE);
  st7789.printf("ST7789\n");

  ili9341.fillScreen(ILI9341_BLACK);
  ili9341.setRotation(1);
  ili9341.setTextSize(4);
  
  ili9341.setCursor(0, 10);
  ili9341.setTextColor(ILI9341_GREEN);
  ili9341.printf("TAMANEGI\n\n");

  ili9341.setTextSize(3);
  ili9341.setTextColor(ILI9341_RED);
  ili9341.printf("2.4inch LCD\n");
  ili9341.setTextColor(ILI9341_YELLOW);
  ili9341.printf("Res=320 x 240\n");
  ili9341.setTextColor(ILI9341_BLUE);
  ili9341.printf("ILI9341\n");
}

void loop()
{
}

結果

ST7789LCDとILI9341LCDを同時に表示制御しました。
同じ解像度です。

横並びでST7789のIPSとILI9341のTNを比較すると視野角にはっきりとした違いがあります。

コメント

タイトルとURLをコピーしました