1
1

More than 1 year has passed since last update.

メトロ02系のモニタ装置を液晶ディスプレイで再現しよう

Last updated at Posted at 2022-05-07

東京メトロ02系の運転席の横にあるモニタ装置液晶ディスプレイを作ってみましょう。
使用した液晶ディスプレイは3.5インチの解像度320x480、SPI接続のものを選択しました。
タッチパネル機能がありますが、今回は使用していません。

画面イメージ

最初に画面イメージを作成します。
ポンチ絵でも構いませんが作る事をお勧めします。
(扉の開閉の文字は、本来開いたら が正しいと思いますが閉としています)
02系TFT.png

構成

今回は、メインマイコンとしてESP32を使用します。
液晶ディスプレイを動かすライブラリには TFT_eSPI を使用します。

配線

3.5インチTFT液晶ディスプレイの仕様は以下のようです。

今回使用する3.5インチ液晶ディスプレイに搭載しているディスプレイドライバILI948xはタッチパネルを使用する際にMISOを接続しないようにしてください。
映像が映らなくなります。
ピンは以下につなげています。

  • MOSI23
  • MISO 19
  • SCLK 18
  • CS 5
  • DC 17
  • RST なし

ライブラリの導入

Arduinoに TFT_eSPI のライブラリを追加します。
スケッチ⇒ライブラリをインクルード⇒ライブラリを管理⇒TFT_eSPI をインストールします。
image.png
image.png
User_Setup.h のピン設定を変更します。

//#define ILI9486_DRIVER
//#define ILI9488_DRIVER     // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)

//#define TFT_MISO 19
//#define TFT_MOSI 23
//#define TFT_SCLK 18
//#define TFT_CS   15  // Chip select control pin
//#define TFT_DC    2  // Data Command control pin
//#define TFT_RST   4  // Reset pin (could connect to RST pin)
//#define TFT_RST  -1  // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST

を以下に変更しました。
ピン設定は各自の環境に合わせてください。
リセットピンは使用しないので -1 とします。

#define ILI9486_DRIVER
//#define ILI9488_DRIVER     // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)

#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS   5  // Chip select control pin
#define TFT_DC   17  // Data Command control pin
//#define TFT_RST   4  // Reset pin (could connect to RST pin)
#define TFT_RST  -1  // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST

動作確認

最初に、キチンと動くか確認をするためにサンプルプログラムを動かしてみましょう。
image.png

プログラム

サンプルプログラムが動いたら画面イメージを元に画面を作って行きましょう。
線や丸、四角を開始位置、終了位置、色を設定します。

 線:tft.drawLine(x, y, width, hight, Color);
 四角(塗りつぶし無し):tft.drawRect(x, y, width, hight, Color);
 四角(塗りつぶしあり): tft.fillRect(x, y, width, hight, Color);

日本語フォントファイルの準備

この段階で、例えば以下を画面出力すると日本語の文字が文字化けします。

    tft.loadFont("使用フォント名");
    tft.setTextColor(Color);
    tft.drawString("表示内容", x, y);

ここからは Watako さんの M5Stackで好きなフォントを使う を参考にフォントファイルを作ります。

最初に Processing をダウンロードします。

image.png
ファイル⇒スケッチ例⇒TFT_eSPI⇒Tools⇒Create_Smooth_Font⇒Create_font を開き
image.png
プログラムを丸ごと Processing に貼り付け実行します。
スクリーンショット 2022-04-14 115327.png
image.png
実行後パソコンに搭載しているフォントが表示されます。
image.png

Unicodeの準備

今回のプログラムではUnicodeの番号を指定する必要があります。
使用する日本語を羅列し、変換します。

image.png
生成されたUnicodeをProcessingの該当箇所を

static final int[] specificUnicodes = {

以下へ貼り付けます。
この際に

\u4eca\u65e5

となっているものは

0x4eca
0x65e5

と書き換えます。

int fontNumber = 258; // << Use [Number] in brackets from the fonts listed.

int  fontSize = 28;

static final int[] specificUnicodes = {

image.png

image.png

以上を必要なフォントごとに実行すると下記のようなフォントファイルが出来上がっていると思います。
image.png

フォントファイルのアップロード

上記で作成したフォントファイルを Arduinoプログラムフォルダ 内に dataフォルダ を作成しにコピーします。
image.png
次に Arduino ESP32 filesystem uploader をダウンロードします。

image.png
ダウンロードした ESP32FS.javaUserフォルダ⇒Arduino⇒Toolsフォルダ にコピーします。
ESP32 Sketch Data Upload が表示されていると思います。
ESP32 Sketch Data Upload をクリックしファイルをアップロードします。
image.png
以上でフォントファイルがアップロードされました。
なお、フォントの色を以下で指定しています。

tft.setTextColor(文字色,背景色);

最後に、プログラムをコンパイルして実行し、動作確認をしましょう。

/*
  Sketch to demonstrate using the print class with smooth fonts

  Sketch is writtent for a 240 x 320 display

  Load the font file into SPIFFS first by using the Arduino IDE
  Sketch Data Upload menu option. Font files must be stored in the
  sketch data folder (Ctrl+k to view).
  https://github.com/esp8266/arduino-esp8266fs-plugin
  https://github.com/me-no-dev/arduino-esp32fs-plugin

  New font files in the .vlw format can be created using the Processing
  sketch in the library Tools folder. The Processing sketch can convert
  TrueType fonts in *.ttf or *.otf files.

  Note: SPIFFS does not accept an underscore _ in filenames!

  The library supports 16 bit unicode characters:
  https://en.wikipedia.org/wiki/Unicode_font

  The characters supported are in the in the Basic Multilingal Plane:
  https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane

  Make sure all the display driver and pin connenctions are correct by
  editing the User_Setup.h file in the TFT_eSPI library folder.

  #########################################################################
  ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
  #########################################################################
*/

// Font file is stored in SPIFFS
#define FS_NO_GLOBALS
#include <FS.h>

// Graphics and font library
#include <TFT_eSPI.h>
#include <SPI.h>

TFT_eSPI tft = TFT_eSPI();  // Invoke library

// -------------------------------------------------------------------------
// Setup
// -------------------------------------------------------------------------
void setup(void) {
  Serial.begin(115200); // Used for messages

  tft.init();
  tft.setRotation(1);

  if (!SPIFFS.begin()) {
    Serial.println("SPIFFS initialisation failed!");
    while (1) yield(); // Stay here twiddling thumbs waiting
  }
  Serial.println("\r\nInitialisation done.");

  listFiles(); // Lists the files so you can see what is in the SPIFFS

}

// -------------------------------------------------------------------------
// Main loop
// -------------------------------------------------------------------------
void loop() {

  int xpos =  0;
  int ypos = 50;


  // Wrap test at right and bottom of screen
  tft.setTextWrap(true, true);

  // Name of font file (library adds leading / and .vlw)
  String fileName = "msgothic-28";

  // Font and background colour, background colour is used for anti-alias blending
  tft.setTextColor(TFT_WHITE, TFT_BLACK);

  // Load the font
  tft.loadFont(fileName);

  // Display all characters of the font
  tft.showFont(2000);

  // Set "cursor" at top left corner of display (0,0)
  // (cursor will move to next line automatically during printing with 'tft.println'
  //  or stay on the line is there is room for the text with tft.print)
  tft.setCursor(0, 0);
  tft.drawRect(0, 0, 375, 95, TFT_WHITE);

  tft.drawLine(0, 35, 375, 35, TFT_WHITE);
  tft.drawLine(0, 65, 375, 65, TFT_WHITE);
  tft.drawRect(0, 95, 480, 280, TFT_WHITE);
  tft.loadFont("msgothic-36");
  tft.fillRect(375, 0, 480, 95, TFT_YELLOW);
  tft.setTextColor(TFT_BLACK, TFT_YELLOW);
  tft.drawString("状態", 390, 30);
  tft.fillRect(20, 195, 95, 70, TFT_DARKGREEN);
  tft.fillRect(115, 195, 350, 70, TFT_WHITE);
  tft.fillRect(0, 275, 480, 45, TFT_WHITE);
  tft.fillRect(0, 280, 105, 35, TFT_CYAN);
  tft.fillRect(125, 280, 105, 35, TFT_CYAN);
  tft.fillRect(250, 280, 105, 35, TFT_CYAN);
  tft.fillRect(375, 280, 105, 35, TFT_CYAN);

  tft.loadFont("msgothic-28");
  // Set the font colour to be white with a black background, set text size multiplier to 1
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawString("運行 : 21  行先 : 荻窪", 10, 7);
  tft.drawString("地点 :     池袋", 10, 37);
  tft.drawString("終端戸締 :  1 側", 10, 67);
  tft.drawString("車内 :   ", 10, 100);
  tft.drawString(" 1      2      3      4      5      6", 135, 165);
  tft.drawString(" 1側扉 ", 25, 200);
  tft.drawString(" 2側扉 ", 25, 235);
  tft.setTextColor(TFT_WHITE, TFT_RED);
  tft.drawString("  閉    閉    閉    閉    閉    閉  ", 120, 200);
  tft.setTextColor(TFT_BLACK, TFT_WHITE);
  tft.drawString("  閉    閉    閉    閉    閉    閉  ", 120, 235);
  delay(10000);
}


// -------------------------------------------------------------------------
// List files in ESP8266 or ESP32 SPIFFS memory
// -------------------------------------------------------------------------
void listFiles(void) {
  Serial.println();
  Serial.println("SPIFFS files found:");

#ifdef ESP32
  listDir(SPIFFS, "/", true);
#else
  fs::Dir dir = SPIFFS.openDir("/"); // Root directory
  String  line = "=====================================";

  Serial.println(line);
  Serial.println("  File name               Size");
  Serial.println(line);

  while (dir.next()) {
    String fileName = dir.fileName();
    Serial.print(fileName);
    int spaces = 25 - fileName.length(); // Tabulate nicely
    if (spaces < 0) spaces = 1;
    while (spaces--) Serial.print(" ");
    fs::File f = dir.openFile("r");
    Serial.print(f.size()); Serial.println(" bytes");
    yield();
  }

  Serial.println(line);
#endif
  Serial.println();
  delay(1000);
}

#ifdef ESP32
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
  Serial.printf("Listing directory: %s\n", dirname);

  fs::File root = fs.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return;
  }

  fs::File file = root.openNextFile();
  while (file) {

    if (file.isDirectory()) {
      Serial.print("DIR : ");
      String fileName = file.name();
      Serial.print(fileName);
      if (levels) {
        listDir(fs, file.name(), levels - 1);
      }
    } else {
      String fileName = file.name();
      Serial.print("  " + fileName);
      int spaces = 32 - fileName.length(); // Tabulate nicely
      if (spaces < 1) spaces = 1;
      while (spaces--) Serial.print(" ");
      String fileSize = (String) file.size();
      spaces = 8 - fileSize.length(); // Tabulate nicely
      if (spaces < 1) spaces = 1;
      while (spaces--) Serial.print(" ");
      Serial.println(fileSize + " bytes");
    }

    file = root.openNextFile();
  }
}
#endif
// -------------------------------------------------------------------------

画面が表示されない・再起動する

フォントファイルをキチンとアップロードできていないと液晶が表示されないだけでなくESP32がリブートを繰り返します。

調整

文字や線などの配置を確認しながら進めていきます。
特に文字が抜けていて文字化けすることなどあるので注意しましょう。

BVE連携する

以上で、液晶画面にモニタ装置の情報が表示できたと思います。
それでは最後に、BVEと連携させてみましょう。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1