SSD1306 OLEDで日本語表示 lovyanGFXの使い方

lovyanGFX液晶表示OLED SSD1306 2画面

有機ELディスプレイ(OLED)「SSD1306」で日本語表示を行う方法を紹介します。

以前、以下のリンクで「SSD1306」についてと使用方法を紹介しました。
この時は「Adafruit社」から提供されているライブラリを使用しましたが、日本語の表示については ひと手間必要で詳しく紹介できず紹介のみとなってしまいました。

SSD1306有機ELディスプレイOLEDの使い方、簡単2画面表示の方法も紹介
SSD1306はライブラリを準備してI2C通信と簡単なコマンドで表示可能。ATOM LITEやESP32、Arduino等に表示器を追加したい時に手軽に安価で実現できるのでとても便利です。

今回は簡単に日本語表示ができる、らびやんさん作の「lovyanGFX」を使用させていただきました。

OLEDは「SSD1306」を使用しましたが「lovyanGFX」はたくさんの表示器に対応しており、他のOLEDでも初期設定を変えるだけで表示できてとても便利です。

また、シリアルポートごとに個別に設定を行うことが出来るため、2系統のシリアル通信のあるボードならOLEDの通信アドレスが同じものでも違う内容で2画面表示できるので、こちらも紹介したいと思います。

「lovyanGFX」を使用して「M5Stackシリーズ」の「CORE2」や「M5StickC Plus」で日本語や図形等の基本的な表示を行う方法は以下のリンクで詳しく紹介しています。
lovyanGFXの使い方 M5Stackシリーズ編 基本的な表示(日本語、図形)方法
lovyanGFXで簡単日本語表示、データ更新やグラフ表示で「チラツキ」を抑えるための「スプライト」について、コピペ用サンプルプログラムでCORE2,M5Stick Plus,GRAYで表示して詳しく紹介します。

スポンサーリンク

1.サンプル画面の紹介

「SSD1306」はM5Stackシリーズの「ATOM LITE」と接続して動作確認を行いました。

「ATOM LITE」については以下のリンクで詳しく詳しく紹介しています。

ATOM LITE プログラミング初心者におすすめ超小型で高機能!
マイコンボードはRaspberry Pi、Arduino、M5Stack等がありますが、一通りやってみてそれぞれの良さはあるものの「最初に何を?」と聞かれたらATOM LITEが一番お手軽♪プログラミング初心者におすすめ

lovyanGFX液晶表示OLED SSD1306

サンプル画面には上から「日本語表示」「本体ボタンのON/OFF状態表示(BTN)」「本体ボタンを押した回数カウント表示(CNT)」「横線2本」「縦線1本」「円、三角、四角」を並べて表示しています。

lovyanGFX液晶表示OLED SSD1306

「SSD1306」と「ATOM LITE」は上画像のように端子を合わせて接続します。
それぞれの「5V」と「0V(G)」端子の配列が同じため直接差し込み「SSD1306」の「SDA」と「SCL」端子に合わせて「ATOM LITE」の「G21」と「G25」端子をプログラムで割り付けます。

スポンサーリンク

2.サンプルプログラム(コピペ)

 ・サンプル画面プログラム

サンプル画面のプログラムは以下のようになります。「コピペ」で動作確認してみましょう。

※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#include <M5Atom.h>       // Atomのヘッダファイル(Arduino.h /Wire.h /FastLED.h含む)
#define LGFX_USE_V1       // v1.0.0 を有効にします(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)
#include <LovyanGFX.hpp>  // lovyanGFXのヘッダを準備

// 独自の設定を行うクラスを、LGFX_Deviceから派生して作成します。
// クラス名はLGFXからLGFX_SSD1306に変更してます。(コンストラクタ名も)
class LGFX_SSD1306 : public lgfx::LGFX_Device {
  // 接続するOLED表示器にあったインスタンスを準備します。
  lgfx::Panel_SSD1306   _panel_instance;  // SSD1306を使用する場合
  lgfx::Bus_I2C   _bus_instance;          // I2Cバスのインスタンス (ESP32のみ)

  // コンストラクタを作成し、ここで各種設定を行います。
  public:
    LGFX_SSD1306() {  // コンストラクタ名はクラス名に合わせてLGFXからLGFX_SSD1306に変更してます。(クラス名と同じにする)
      { // バス制御の設定を行います。
        auto cfg = _bus_instance.config();  // I2Cバス設定用の構造体を取得します。
        cfg.i2c_port    = 1;          // 使用するI2Cポートを選択 (0 or 1)
        cfg.freq_write  = 400000;     // 送信時のクロック
        cfg.freq_read   = 400000;     // 受信時のクロック
        cfg.pin_sda     = 21;         // SDAを接続しているピン番号
        cfg.pin_scl     = 25;         // SCLを接続しているピン番号
        cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス

        _bus_instance.config(cfg);    // 設定値をバスに反映します。
        _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
      }
      { // 表示パネル制御の設定を行います。
        // 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。
        auto cfg = _panel_instance.config();  // 表示パネル設定用の構造体を取得します。
        cfg.memory_width  = 128;      // ドライバICがサポートしている最大の幅
        cfg.memory_height =  64;      // ドライバICがサポートしている最大の高さ

        _panel_instance.config(cfg);  // 設定をパネルに反映
      }
      setPanel(&_panel_instance);     // 使用するパネルをセットします。
    }
};
static LGFX_SSD1306 lcd; // LGFX_SSD1306のインスタンス(クラスLGFX_SSD1306を使ってlcdでいろいろできるようにする)を作成
static LGFX_Sprite canvas(&lcd);  // スプライトを使うためのLGFX_Spriteのインスタンスを作成

// 変数宣言
int cnt;    // 本体ボタンON回数格納用
// 初期設定 ------------------------------------------------------
void setup() {
  M5.begin(true, true, true); // 本体初期化(UART, I2C, LED)
  //LCD初期設定
  lcd.init();                                     // 表示器初期化
  canvas.setTextWrap(false);                      // 右端到達時のカーソル折り返しを禁止(true)で許可
  canvas.createSprite(lcd.width(), lcd.height()); // スプライト用の仮想画面を画面幅を取得して準備
}
// メイン --------------------------------------------------------
void loop() {
  M5.update();  // 本体ボタン状態更新
 // 表示処理(メモリ描画領域canvasに描画)
  canvas.fillScreen(TFT_BLACK);    // 背景塗り潰し
  canvas.setTextColor(TFT_WHITE);  // 文字色と背景を指定(文字色, 背景)
  // 日本語表示
  canvas.setCursor(0, 0);                         // 座標を指定(x, y)
  canvas.setFont(&fonts::lgfxJapanGothic_16);     // ゴシック体(8,12,16,20,24,28,32,36,40)
  canvas.println("液晶表示ゴシック");                // 表示内容をcanvasに準備
  canvas.setCursor(0, 14);                        // 座標を指定(x, y)
  canvas.setFont(&fonts::lgfxJapanMincho_16);     // 明朝体P(8,12,16,20,24,28,32,36,40)
  canvas.println("液晶表示 明朝体");                // 表示内容をcanvasに準備

  // 本体ボタンON/OFF状態表示
  if (M5.Btn.isPressed()) {                       // ボタンを押していれば(AtomはBtn必要に応じて変更)
    canvas.drawString("BTN=ON", 3, 32, &Font2);   // 本体ボタンON表示
  } else {                                        // ボタンを押してなければ
    canvas.drawString("BTN=OFF", 3, 32, &Font2);  // 本体ボタンOFF表示
  }
  // 本体ボタンON回数カウント表示
  if (M5.Btn.wasPressed()) {          // ボタンが押されていたら(AtomはBtn必要に応じて変更)
    cnt++;                            // カウント+1
  }
  canvas.setCursor(65, 32, &Font2);   // 座標とフォントを指定(x, y, フォント)
  canvas.print("CNT=");               //「CNT=」表示
  canvas.setTextSize(0.3);            // 文字倍率変更
  canvas.setCursor(100, 32, &Font7);  // 座標とフォントを指定(x, y, フォント)
  canvas.printf("%03d", cnt);         // カウント数表示
  canvas.setTextSize(1);              // 文字倍率を戻す
  // 線
  canvas.drawLine(0, 30, 128, 30, TFT_WHITE);  // 線(始点x,始点y,終点x,終点y,色)
  canvas.drawFastVLine(60, 31, 16, TFT_WHITE); // 線(始点x,始点y,始点からの垂線長さ,色)
  canvas.drawFastHLine(0, 47, 128, TFT_WHITE); // 線(始点x,始点y,始点からの平行線長さ,色)
  // 円
  canvas.drawCircle(7, 57, 6, TFT_WHITE);      // 円(始点x,始点y,半径,色)
  canvas.fillCircle(23, 57, 6, TFT_WHITE);     // 塗り潰し円(始点x,始点y,半径,色)
  // 三角
  canvas.drawTriangle(34, 62, 41, 50, 47, 62, TFT_WHITE);  // 三角(点1 x,点1 y,点2 x,点2 y,点3 x,点3 y,色)
  canvas.fillTriangle(51, 62, 58, 50, 65, 62, TFT_WHITE);  // 塗り潰し三角(点1 x,点1 y,点2 x,点2 y,点3 x,点3 y,色)
  // 円
  canvas.drawRect(70, 51, 12, 12, TFT_WHITE);  // 四角(始点x,始点y,縦長さ,横長さ)
  canvas.fillRect(86, 51, 12, 12, TFT_WHITE);  // 塗り潰し四角(始点x,始点y,縦長さ,横長さ)

  canvas.pushSprite(0, 0);    // メモリ内に描画したcanvasを座標を指定して表示する

  delay(100);
}

 ・日本語表示部のみ抜粋

サンプル画面のプログラムはいろいろ書いてありますが、日本語表示だけを抜粋すると以下のようになります。

※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#include <M5Atom.h>       // Atomのヘッダファイル(Arduino.h /Wire.h /FastLED.h含む)
#define LGFX_USE_V1       // v1.0.0 を有効にします(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)
#include <LovyanGFX.hpp>  // lovyanGFXのヘッダを準備

// 独自の設定を行うクラスを、LGFX_Deviceから派生して作成します。
// クラス名はLGFXからLGFX_SSD1306に変更してます。(コンストラクタ名も)
class LGFX_SSD1306 : public lgfx::LGFX_Device {
  // 接続するOLED表示器にあったインスタンスを準備します。
  lgfx::Panel_SSD1306   _panel_instance;  // SSD1306を使用する場合
  lgfx::Bus_I2C   _bus_instance;          // I2Cバスのインスタンス (ESP32のみ)

  // コンストラクタを作成し、ここで各種設定を行います。
  public:
    LGFX_SSD1306() {  // コンストラクタ名はクラス名に合わせてLGFXからLGFX_SSD1306に変更してます。(クラス名と同じにする)
      { // バス制御の設定を行います。
        auto cfg = _bus_instance.config();  // I2Cバス設定用の構造体を取得します。
        cfg.i2c_port    = 1;          // 使用するI2Cポートを選択 (0 or 1)
        cfg.freq_write  = 400000;     // 送信時のクロック
        cfg.freq_read   = 400000;     // 受信時のクロック
        cfg.pin_sda     = 21;         // SDAを接続しているピン番号
        cfg.pin_scl     = 25;         // SCLを接続しているピン番号
        cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス

        _bus_instance.config(cfg);    // 設定値をバスに反映します。
        _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
      }
      { // 表示パネル制御の設定を行います。
        // 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。
        auto cfg = _panel_instance.config();  // 表示パネル設定用の構造体を取得します。
        cfg.memory_width  = 128;      // ドライバICがサポートしている最大の幅
        cfg.memory_height =  64;      // ドライバICがサポートしている最大の高さ

        _panel_instance.config(cfg);  // 設定をパネルに反映
      }
      setPanel(&_panel_instance);     // 使用するパネルをセットします。
    }
};
static LGFX_SSD1306 lcd; // LGFX_SSD1306のインスタンス(クラスLGFX_SSD1306を使ってlcdでいろいろできるようにする)を作成
static LGFX_Sprite canvas(&lcd);  // スプライトを使うためのLGFX_Spriteのインスタンスを作成

// 初期設定 ------------------------------------------------------
void setup() {
  M5.begin(true, true, true); // 本体初期化(UART, I2C, LED)
  //LCD初期設定
  lcd.init();                                     // 表示器初期化
  canvas.setTextWrap(false);                      // 右端到達時のカーソル折り返しを禁止(true)で許可
  canvas.createSprite(lcd.width(), lcd.height()); // スプライト用の仮想画面を画面幅を取得して準備
}
// メイン --------------------------------------------------------
void loop() {
 // 表示処理(メモリ描画領域canvasに描画)
  canvas.fillScreen(TFT_BLACK);    // 背景塗り潰し
  canvas.setTextColor(TFT_WHITE);  // 文字色と背景を指定(文字色, 背景)

  // 日本語表示
  canvas.setCursor(0, 0);                         // 座標を指定(x, y)
  canvas.setFont(&fonts::lgfxJapanGothic_16);     // ゴシック体(8,12,16,20,24,28,32,36,40)
  canvas.println("液晶表示ゴシック");                // 表示内容をcanvasに準備
  canvas.setCursor(0, 14);                        // 座標を指定(x, y)
  canvas.setFont(&fonts::lgfxJapanMincho_16);     // 明朝体P(8,12,16,20,24,28,32,36,40)
  canvas.println("液晶表示 明朝体");                // 表示内容をcanvasに準備

  canvas.pushSprite(0, 0);    // メモリ内に描画したcanvasを座標を指定して表示する

  delay(100);
}
スポンサーリンク

3.メモリ描画領域(スプライト)について

「スプライト」とはメモリ内の仮想画面上に文字や画像を合成してから出力する技術です。
これによって表示データの更新時に発生する「チラツキ」を抑えることができます。

まず、サンプル画面のプログラムでは49行目で以下のように「canvas」という名前で「createSprite」でメモリ内に仮想画面を画面サイズを指定して準備しています。

canvas.createSprite(lcd.width(), lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)

canvas」としてメモリ内に準備した仮想画面に文字や図形の指定が終わった後で、サンプル画面のプログラム95行目のように「pushSprite」を実行して画面への表示を行います。

canvas.pushSprite(0, 0);  // メモリ内に描画したcanvasを座標を指定して表示する

仮想画面に描画せず、直接液晶画面に表示させる場合は各種表示コマンドの「canvas」の部分を「lcd」で指定します。


試しにサンプルプログラム65行目~74行目の本体ボタンのON/OFF状態を表示するプログラムを「lcd」で指定して表示してみましょう。

下コードをコピーしてサンプルプログラム65行目~74行目と置き換えみてください。

// 本体ボタンON/OFF状態表示(直接出力表示)
lcd.drawString("         ", 3, 32, &Font2);  // 本体ボタン状態表示消去

if (M5.Btn.isPressed()) {                    // ボタンを押していれば
  lcd.setTextColor(TFT_WHITE);               // 文字色指定
  lcd.drawString("BTN=ON", 3, 32, &Font2);   // 本体ボタンON表示
} else {                                     // ボタンを押してなければ
  lcd.setTextColor(TFT_WHITE);               // 文字色指定
  lcd.drawString("BTN=OFF", 3, 32, &Font2);  // 本体ボタンOFF表示
}

本体ボタンの使い方、ボタン操作関数一覧については以下のリンクで詳しく紹介しています。

M5Stack 本体ボタンの使い方、ボタン操作関数一覧(Arduinoプログラミング)
M5Stackシリーズの本体ボタンは Arduino のコマンドで簡単に制御できます。「Lチカ」のサンプルプログラムを使用して紹介しますので用途に応じて使い分けられるようになりましょう♪

書き込んで実行すると「BTN= 」の部分の表示だけが点滅していると思います。

この表示部は「ON」と「OFF」の表示文字数が違うため「OFF」のあとに「ON」を指定すると「OFF」の上に「ON」が表示されるため、重なって「ONF」となってしまいます。

こうならないように事前に「”         “」スペースで全文消去を行っており、消去と表示が繰り返し表示されることになります。

canvas」で指定すると「全文消去してから表示した結果」が出力されますが
lcd」で指定すると「全文消去してから表示するという過程」も表示されるため点滅するように表示される「チラツキ」が発生してしまいます。

canvas」で指定した仮想画面内で画像を処理してから表示させることで画面の「チラツキ」を抑えることができます。

処理速度の遅いプログラムで高速で表示させたい時は「lcd」で指定した方が良い場合もあるので用途に応じて使い分けましょう。
今回の場合は「”         “」のようにスペースで「ON/OFF」表示部を全文消去しましたが、文字の背景色を設定して「ON」の後にスペースを入れて「ON 」として「OFF」と文字数を合わせれば問題なく表示できます。
書き方によっては少ないコードで同じ動作をさせることができるので、いろいろ工夫してみましょう。

以前紹介した以下リンクのストップウオッチを作るプログラムでは、タイマー割込みを使用して0.01秒の表示を高速で行いたいため「lcd」を採用しています。(lovyanGFXではなくM5GFXライブラリ使用)

タイマー割込みをストプウォッチの動作で紹介「ATOM LITE + OLED液晶」
タイマー割込みを使用したストップウオッチでタイマー割り込みの動作を紹介。正確な時間で処理を行うにはひと手間必要で、非常に動作が複雑ですが一つづつ詳しく紹介します。

4.ヘッダーとOLEDの通信設定について

ヘッダー部では機種ごとのヘッダーファイル(今回は「M5Atom.h)に続けて「lovyanGFX」のバージョン設定とヘッダーファイルを下コードの通り記入します。

#include <M5Atom.h>       // Atomのヘッダファイル(Arduino.h /Wire.h /FastLED.h含む)
#define LGFX_USE_V1       // v1.0.0 を有効にします(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)
#include <LovyanGFX.hpp>  // lovyanGFXのヘッダを準備

次に下コードのように、OLEDの設定を行うクラスを作成していきます。

3行目でクラス名を設定しますが「LGFX」はボードの自動判別を行う場合に使用されるため、別のわかりやすい名前に変更します。今回は「LGFX_SSD1306」としました。
10行目のコンストラクタ名も同じ名前にします。)

5行目で使用するOLEDのインスタンスを準備します。
後で紹介しますが、ここはあらかじめ対応しているOLEDの設定がコメントアウトされて準備されてますので、使用するものを有効にするだけです。

6行目で接続するバスのインスタンスを準備します。
今回は「I2C」を選択しましたが「SPI」や「8ビットパラレル」の選択も可能です。

詳細は以下リンクのGitHubで詳しく紹介されています。

https://github.com/lovyan03/LovyanGFX/blob/master/examples/HowToUse/2_user_setting/2_user_setting.ino

11〜22行目でバス制御の設定として、通信ポート番号や送受信速度、使用端子の割り付け、通信アドレスの設定を行います。

23〜42行目でOLEDの制御設定を行います。
「SSD1306」では表示サイズのみの設定で動作しましたが、他の表示器を使用して正常に表示されない場合は他の項目も有効にして設定してみてください。

// 独自の設定を行うクラスを、LGFX_Deviceから派生して作成します。
// クラス名はLGFXからLGFX_SSD1306に変更してます。(コンストラクタ名も)
class LGFX_SSD1306 : public lgfx::LGFX_Device {
  // 接続するOLED表示器にあったインスタンスを準備します。
  lgfx::Panel_SSD1306   _panel_instance;  // SSD1306を使用する場合
  lgfx::Bus_I2C   _bus_instance;          // I2Cバスのインスタンス (ESP32のみ)

  // コンストラクタを作成し、ここで各種設定を行います。
  public:
    LGFX_SSD1306() {  // コンストラクタ名はクラス名に合わせてLGFXからLGFX_SSD1306に変更してます。(クラス名と同じにする)
      { // バス制御の設定を行います。
        auto cfg = _bus_instance.config();  // I2Cバス設定用の構造体を取得します。
        cfg.i2c_port    = 1;          // 使用するI2Cポートを選択 (0 or 1)
        cfg.freq_write  = 400000;     // 送信時のクロック
        cfg.freq_read   = 400000;     // 受信時のクロック
        cfg.pin_sda     = 21;         // SDAを接続しているピン番号
        cfg.pin_scl     = 25;         // SCLを接続しているピン番号
        cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス

        _bus_instance.config(cfg);    // 設定値をバスに反映します。
        _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
      }
      { // 表示パネル制御の設定を行います。
        // 以下の設定値はパネル毎に一般的な初期値が設定されていますので、不明な項目はコメントアウトして試してみてください。
        auto cfg = _panel_instance.config();  // 表示パネル設定用の構造体を取得します。
        cfg.memory_width  = 128;      // ドライバICがサポートしている最大の幅
        cfg.memory_height =  64;      // ドライバICがサポートしている最大の高さ
        // cfg.panel_width      =   240;  // 実際に表示可能な幅
        // cfg.panel_height     =   320;  // 実際に表示可能な高さ
        // cfg.offset_x         =     0;  // パネルのX方向オフセット量
        // cfg.offset_y         =     0;  // パネルのY方向オフセット量
        // cfg.offset_rotation  =     0;  // 回転方向の値のオフセット 0~7 (4~7は上下反転)
        // cfg.dummy_read_pixel =     8;  // ピクセル読出し前のダミーリードのビット数
        // cfg.dummy_read_bits  =     1;  // ピクセル以外のデータ読出し前のダミーリードのビット数
        // cfg.readable         =  true;  // データ読出しが可能な場合 trueに設定
        // cfg.invert           =  true;  // パネルの明暗が反転してしまう場合 trueに設定
        // cfg.rgb_order        = false;  // パネルの赤と青が入れ替わってしまう場合 trueに設定
        // cfg.dlen_16bit       = false;  // データ長を16bit単位で送信するパネルの場合 trueに設定
        // cfg.bus_shared       =  true;  // SDカードとバスを共有している場合 trueに設定(drawJpgFile等でバス制御を行います)

        _panel_instance.config(cfg);  // 設定をパネルに反映
      }
      setPanel(&_panel_instance);     // 使用するパネルをセットします。
    }
};

最後に、作成したクラスを使用して、表示を直接出力する「lcd」と仮想画面で「スプライト」するための「canvas」をインスタンスとして作成します。

static LGFX_SSD1306 lcd; // LGFX_SSD1306のインスタンス(クラスLGFX_SSD1306を使ってlcdでいろいろできるようにする)を作成
static LGFX_Sprite canvas(&lcd);  // スプライトを使うためのLGFX_Spriteのインスタンスを作成

対応OLED表示器一覧

対応しているOLED表示器の一覧は以下のようになります。

上コードの5行目で接続するOLED表示器にあったインスタンスを準備しましたが「SSD1306」以外の表示器を使用する場合は、下の一覧からコメントを解除して置き換えてください。

//lgfx::Panel_GC9A01      _panel_instance;
//lgfx::Panel_GDEW0154M09 _panel_instance;
//lgfx::Panel_HX8357B     _panel_instance;
//lgfx::Panel_HX8357D     _panel_instance;
//lgfx::Panel_ILI9163     _panel_instance;
//lgfx::Panel_ILI9341     _panel_instance;
//lgfx::Panel_ILI9342     _panel_instance;
//lgfx::Panel_ILI9481     _panel_instance;
//lgfx::Panel_ILI9486     _panel_instance;
//lgfx::Panel_ILI9488     _panel_instance;
//lgfx::Panel_IT8951      _panel_instance;
//lgfx::Panel_SH110x      _panel_instance; // SH1106, SH1107
  lgfx::Panel_SSD1306     _panel_instance;
//lgfx::Panel_SSD1327     _panel_instance;
//lgfx::Panel_SSD1331     _panel_instance;
//lgfx::Panel_SSD1351     _panel_instance; // SSD1351, SSD1357
//lgfx::Panel_SSD1963     _panel_instance;
//lgfx::Panel_ST7735      _panel_instance;
//lgfx::Panel_ST7735S     _panel_instance;
//lgfx::Panel_ST7789      _panel_instance;
//lgfx::Panel_ST7796      _panel_instance;

5.初期設定について

以下に初期設定の部分だけ抜粋して紹介します。

基本的な設定は「M5Stack」標準のM5Diplayクラスと同じで、「M5.Lcd」の部分を「lcd」に置き換えて設定するだけです。「スプライト」を行う仮想画面は「canvas」で設定します。

// 初期設定 ------------------------------------------------------
void setup() {
  M5.begin(true, true, true); // 本体初期化(UART, I2C, LED)
  //LCD初期設定
  lcd.init();                                     // 表示器初期化
  canvas.setTextWrap(false);                      // 右端到達時のカーソル折り返しを禁止(true)で許可
  canvas.createSprite(lcd.width(), lcd.height()); // スプライト用の仮想画面を画面幅を取得して準備
}
M5.begin」は「ATOM LITE」本体の初期化関数です。使用するボードによって異なるため、他のボードを使用する場合は使用するボードに合わせて変更してください。

6.基本的な文字、図形表示方法

基本的な文字(フォント、日本語、サイズ、倍率)や図形の表示方法を紹介します。

以下プログラム例の表示出力は「スプライト」を想定して「canvas」で指定していますが、直接出力して確認する場合は「lcd」で指定してください。

・フォントの指定

文字の表示はフォントを「setFont」で指定し、文字色と背景色を「setTextColor」で以下のように指定します。

今回使用した「SSD1306」はモノクロなので色は白「TFT_WHITE(0xFFFF)」と黒「TFT_BLACK(0x0000)」だけです。
// setFont でフォントを指定
canvas.setFont(&fonts::lgfxJapanMinchoP_16);

// setTextColor で文字色と背景を指定
canvas.setTextColor(TFT_WHITE, TFT_BLACK);  //(文字色, 背景色)
canvas.println("文字白、背景黒");

// 背景は省略できますが更新時に前の文字と重なるため背景指定推奨
canvas.setTextColor(TFT_WHITE);             //(文字色)
canvas.println("文字白、背景色指定なし");

色の指定は登録色か16進数(16bit)で指定します。
登録色は「TFT_」付で以下のものがあります。(GiuHubより抜粋)

//登録色          16bit指定
TFT_BLACK       = 0x0000;      /*   0,   0,   0 */
TFT_NAVY        = 0x000F;      /*   0,   0, 128 */
TFT_DARKGREEN   = 0x03E0;      /*   0, 128,   0 */
TFT_DARKCYAN    = 0x03EF;      /*   0, 128, 128 */
TFT_MAROON      = 0x7800;      /* 128,   0,   0 */
TFT_PURPLE      = 0x780F;      /* 128,   0, 128 */
TFT_OLIVE       = 0x7BE0;      /* 128, 128,   0 */
TFT_LIGHTGREY   = 0xD69A;      /* 211, 211, 211 */
TFT_LIGHTGRAY   = 0xD69A;      /* 211, 211, 211 */
TFT_DARKGREY    = 0x7BEF;      /* 128, 128, 128 */
TFT_DARKGRAY    = 0x7BEF;      /* 128, 128, 128 */
TFT_BLUE        = 0x001F;      /*   0,   0, 255 */
TFT_GREEN       = 0x07E0;      /*   0, 255,   0 */
TFT_CYAN        = 0x07FF;      /*   0, 255, 255 */
TFT_RED         = 0xF800;      /* 255,   0,   0 */
TFT_MAGENTA     = 0xF81F;      /* 255,   0, 255 */
TFT_YELLOW      = 0xFFE0;      /* 255, 255,   0 */
TFT_WHITE       = 0xFFFF;      /* 255, 255, 255 */
TFT_ORANGE      = 0xFDA0;      /* 255, 180,   0 */
TFT_GREENYELLOW = 0xB7E0;      /* 180, 255,   0 */
TFT_PINK        = 0xFE19;      /* 255, 192, 203 */ //Lighter pink, was 0xFC9F
TFT_BROWN       = 0x9A60;      /* 150,  75,   0 */
TFT_GOLD        = 0xFEA0;      /* 255, 215,   0 */
TFT_SILVER      = 0xC618;      /* 192, 192, 192 */
TFT_SKYBLUE     = 0x867D;      /* 135, 206, 235 */
TFT_VIOLET      = 0x915C;      /* 180,  46, 226 */
TFT_TRANSPARENT = 0x0120;

ASCII文字、数字のフォント

ASCII文字と数字のフォントは以下のようになります。

Font0:  8px ASCII文字
Font2:16px ASCII文字
Font4:26px ASCII文字
Font6:36(48)px 数字と時計用文字のみ(1234567890apm.:-)
Font7:48px 7セグ風数字と記号のみ(1234567890.:-)
Font8:75px 数字と記号のみ(1234567890.:-)

Font6」は36pxですが「p」の表示がベースラインから12px下へはみ出すため実質48px(縦)使用されます

「Font」ごとに「SSD1306」に表示すると下画像のようになります。

lovyanGFX液晶表示OLED SSD1306

Font0 8px ASCII

lovyanGFX液晶表示OLED SSD1306

Font2 16px ASCII

lovyanGFX液晶表示OLED SSD1306

Font4 26px ASCII


lovyanGFX液晶表示OLED SSD1306

Font6 36(48)px
数字と時計用 apm . : –

lovyanGFX液晶表示OLED SSD1306

Font7 48px
7セグ風数字と . : –

lovyanGFX液晶表示OLED SSD1306

Font8 75px
数字と . : –


日本語のフォント

日本語フォントには以下の物が指定できます。

IPAフォントをコンバートした日本語フォントが4種類x9サイズ = 36通りプリセットされています。
末尾の数字がサイズを表しており、8, 12, 16, 20, 24, 28, 32, 36, 40 が用意されています。

&fonts::lgfxJapanMincho_12   // 明朝体 サイズ12 固定幅フォント
&fonts::lgfxJapanMinchoP_16  // 明朝体 サイズ16 プロポーショナルフォント
&fonts::lgfxJapanGothic_20   // ゴシック体 サイズ20 固定幅フォント
&fonts::lgfxJapanGothicP_24  // ゴシック体 サイズ24 プロポーショナルフォント

「明朝体」をサイズごとに表示すると下画像のようになります。

lovyanGFX液晶表示OLED SSD1306 日本語
lovyanGFX液晶表示OLED SSD1306 日本語
lovyanGFX液晶表示OLED SSD1306 日本語

「ゴシック体」をサイズごとに表示すると下画像のようになります。

lovyanGFX液晶表示OLED SSD1306 日本語
lovyanGFX液晶表示OLED SSD1306 日本語
lovyanGFX液晶表示OLED SSD1306 日本語
他にもefontをコンバートした日本語・韓国語・中国語(簡体字・繁体字)フォントが
各4種類x5サイズ = 20通りプリセットされていますがメモリ消費が多いため、あまりおすすめしません。

他のフォントやefontの消費メモリ等は以下のリンクで詳しく紹介しています。

lovyanGFXの使い方 M5Stackシリーズ編 基本的な表示(日本語、図形)方法
lovyanGFXで簡単日本語表示、データ更新やグラフ表示で「チラツキ」を抑えるための「スプライト」について、コピペ用サンプルプログラムでCORE2,M5Stick Plus,GRAYで表示して詳しく紹介します。

・文字の表示

・draw系(文字列、整数、浮動小数点数)

draw系関数では「文字、数字、浮動小数点数」をそれぞれ、表示座標と一緒に設定します。
フォントは事前に設定したものが使用されますが、第4引数にフォントを追加することでそこだけ個別に指定することもできます。

canvas.setFont(&fonts::lgfxJapanMincho_12); // フォント指定
// 文字の表示
canvas.drawString("文字表示", 0, 0);         // (文字列, x座標, y座標)
canvas.drawString("文字表示", 64, 0, &fonts::lgfxJapanGothic_16);  // (文字列, x座標, y座標, フォント)

// 整数の表示
canvas.drawNumber(123, 0, 20);              // (数値, x座標, y座標)
canvas.drawNumber(123, 64, 20, &Font2);     // (数値, x座標, y座標, フォント)

// 浮動小数点数の表示
canvas.drawFloat(3.14, 2, 0, 40);           // (浮動小数点数, 小数点以下の桁数, x座標, y座標)
canvas.drawFloat(3.14, 2, 64, 40, &Font4);  // (浮動小数点数, 小数点以下の桁数, x座標, y座標, フォント)

・print系(C言語標準出力)

C言語の標準出力関数の「print」「println」「printf」も以下のように使用できます。

canvas.setFont(&fonts::lgfxJapanGothic_12); // フォント指定
// print 関数では、setCursor関数で指定した座標 (またはprint関数で最後に描画した文字の続き)に描画
canvas.setCursor(0, 10);
canvas.print("改行なし ");

// println関数では、文字列を描画後に改行できます。print("\n");と同じ効果
canvas.println("改行あり");

// printf関数では、第2引数以降の内容を描画(複数指定可、C言語のprintfと同じように表示)
int value = 123;
canvas.printf("valueの値は%dです。", value);  // %dの部分にvalueの整数が表示される

printf」に使用されている%dは「変換指定子」で、扱うデータの「型」によって使い分けます。
「変換指定子」はたくさんありますが、主なものは下表のようになります。

変換指定子対応する型出力される内容
%cchar1文字だけ
%schar(配列)文字列
%dint10進数
%uunsigned int10進数(符号なし)
%ldlong10進数(倍精度)
%x,%Xunsigned int16進数
%fdouble(float型以上)浮動小数点数(実数)

「型」については以下リンクの「C言語」の変数についてで詳しく紹介しています。

動かして学ぶC言語「変数」について、正しく学ぶならC言語が一番
「変数」とはプログラム内のデータを保存しておくために使用します。 データを入れておく箱のようなもので、一時的にデータを入れておき、必要な時に取り出して使用したり、取り出して加工(演算等)してから元に戻して、また必要な時に使用したりします。

printf」で表示桁数の指定や0埋め、左揃え等を行う場合は以下のように指定します。

float value = 3.14;                 // float型の変数「value」に3.14を格納

canvas.setFont(&fonts::Font0);      // フォント指定
canvas.printf("|%f|\n", value);     // |3.140000| そのまま表示
canvas.printf("|%.2f|\n", value);   // |3.14|     小数点2桁まで表示
canvas.printf("|%6.2f|\n", value);  // |  3.14|   6文字分のスペースで表示(右揃え)
canvas.printf("|%06.2f|\n", value); // |003.14|   6文字分のスペースで0埋め表示
canvas.printf("|%-6.2f|\n", value); // |3.14  |   6文字分のスペースで表示(左揃え)

・文字サイズ(倍率)の指定

フォントとは別に「setTextSize」で文字サイズを倍率で指定することができます。

canvas.setFont(&fonts::lgfxJapanGothic_12); // フォント指定
// setTextSize で文字の拡大率を指定
canvas.setTextSize(1.5, 3);                 //(横方向倍率, 縦方向倍率)
canvas.println("文字 横2.5倍、 縦3倍");

// 第2引数を省略した場合は、第1引数の倍率が縦と横の両方に反映されます。
canvas.setTextSize(2);                      //(横縦方向倍率)
canvas.println("文字 縦横2.5倍");
ベースとなる文字を拡大縮小するため文字の表示が粗くなったり、つぶれたりするので見た目を確認しながら使用しましょう。

・図形の表示

主な図形の表示方法は以下のようになります。

canvas.drawPixel     (x, y, TFT_WHITE);  // 点

canvas.drawLine      (x0, y0, x1, y1, TFT_WHITE);  // 2点間の直線
canvas.drawFastVLine (x, y, h       , TFT_WHITE);  // 垂直線
canvas.drawFastHLine (x, y, w       , TFT_WHITE);  // 水平線

canvas.drawRect      (x, y, w, h   , TFT_WHITE);  // 矩形の外周
canvas.fillRect      (x, y, w, h   , TFT_WHITE);  // 矩形の塗り
canvas.drawRoundRect (x, y, w, h, r, TFT_WHITE);  // 角丸の矩形の外周
canvas.fillRoundRect (x, y, w, h, r, TFT_WHITE);  // 角丸の矩形の塗り

canvas.drawCircle    (x, y, r      , TFT_WHITE);  // 円の外周
canvas.fillCircle    (x, y, r      , TFT_WHITE);  // 円の塗り
canvas.drawEllipse   (x, y, rx, ry , TFT_WHITE);  // 楕円の外周
canvas.fillEllipse   (x, y, rx, ry , TFT_WHITE);  // 楕円の塗り

canvas.drawTriangle  (x0, y0, x1, y1, x2, y2, TFT_WHITE);         // 3点間の三角形の外周
canvas.fillTriangle  (x0, y0, x1, y1, x2, y2, TFT_WHITE);         // 3点間の三角形の塗り
canvas.drawBezier    (x0, y0, x1, y1, x2, y2, TFT_WHITE);         // 3点間のベジエ曲線(0:起点、1:近接点、2:終点)
canvas.drawBezier    (x0, y0, x1, y1, x2, y2, x3, y3, TFT_WHITE); // 4点間のベジエ曲線(0:起点、1:近接点1、2:近接点2、3:終点)

canvas.drawArc       ( x, y, r0, r1, angle0, angle1, TFT_WHITE);  // 円弧の外周
canvas.fillArc       ( x, y, r0, r1, angle0, angle1, TFT_WHITE);  // 円弧の塗り
// 円弧の設定詳細 r0 = 外円半径、r1 = 内円半径、angle0 = 開始角度、angle1 = 終了角度 ※角度0度は右

7.同一通信アドレス、2画面表示方法

表示画面の設定はシリアルポートごとに個別に行うことが出来るため、2系統のシリアル通信のあるボードなら通信アドレスが同じものでも違う内容で2画面表示することができます。

各種設定はクラスで管理されており、個別のクラス名にすることでそれぞれの通信ポートや使用端子の割り付け、通信アドレスを設定できます。

今回はクラス「LGFX_SSD1306_0LGFX_SSD1306_1」を作成して、直接表示「lcd_0lcd_1」のインスタンスと、スプライト(仮想画面)表示「canvas_0canvas_1」のインスタンスを個別に作成して、それぞれの画面表示に使用します。


実際に「ATOM LITE」に「SSD1306」を2個使用して2画面表示したものが下画像になります。

lovyanGFX液晶表示OLED SSD1306 2画面
画面0は「Grove」コネクタの「G26 , G32」端子を「I2C通信ポート番号0」で「SDA , SCL」に設定。
画面1は「G21 , G25」端子を「I2C通信ポート番号1」で「SDA , SCL」に設定。

8.2画面サンプルプログラム(コピペ)

2画面表示するサンプルプログラムは以下のようになります。「コピペ」して動作確認してみましょう。

※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#include <M5Atom.h>       // Atomのヘッダファイル(Arduino.h /Wire.h /FastLED.h含む)
#define LGFX_USE_V1       // v1.0.0 を有効にします(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)
#include <LovyanGFX.hpp>  // lovyanGFXのヘッダを準備

// 独自の設定を行うクラスを、LGFX_Deviceから派生して2画面分作成します。
// *********************************************************************
// 「画面0」のクラスをLGFX_SSD1306_0として準備。(コンストラクタ名も同じ名前にする)
class LGFX_SSD1306_0 : public lgfx::LGFX_Device {
  // 接続するOLED表示器にあったインスタンスを準備します。
  lgfx::Panel_SSD1306   _panel_instance;  // SSD1306を使用する場合
  lgfx::Bus_I2C   _bus_instance;          // I2Cバスのインスタンス (ESP32のみ)

  // 「画面0」用のコンストラクタを作成し、各種設定を行います。
  public:
    LGFX_SSD1306_0() {  // コンストラクタ名はクラス名に合わせてLGFX_SSD1306_0として準備(クラス名と同じにする)
      { // 「画面0」のバス制御の設定を行います。
        auto cfg = _bus_instance.config();  // I2Cバス設定用の構造体を取得します。
        cfg.i2c_port    = 0;          // 使用するI2Cポートを選択
        cfg.freq_write  = 400000;     // 送信時のクロック
        cfg.freq_read   = 400000;     // 受信時のクロック
        cfg.pin_sda     = 26;         // SDAを接続しているピン番号
        cfg.pin_scl     = 32;         // SCLを接続しているピン番号
        cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス

        _bus_instance.config(cfg);    // 設定値をバスに反映します。
        _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
      }
      { // 「画面0」の制御設定を行います。
        auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。
        cfg.memory_width  = 128;      // ドライバICがサポートしている最大の幅
        cfg.memory_height =  64;      // ドライバICがサポートしている最大の高さ

        _panel_instance.config(cfg);  // 設定をパネルに反映
      }
      setPanel(&_panel_instance);     // 使用するパネルをセットします。
    }
};
static LGFX_SSD1306_0 lcd_0; // LGFX_SSD1306_0のインスタンス(クラスLGFX_SSD1306_0を使ってlcd_0でいろいろできるようにする)を作成
static LGFX_Sprite canvas_0(&lcd_0);  // スプライトを使うためのLGFX_Spriteのインスタンスを作成

// *********************************************************************
// 「画面1」のクラスをLGFX_SSD1306_1として準備。(コンストラクタ名も同じ名前にする)
class LGFX_SSD1306_1 : public lgfx::LGFX_Device {
  // 接続するOLED表示器にあったインスタンスを準備します。
  lgfx::Panel_SSD1306   _panel_instance;  // SSD1306を使用する場合
  lgfx::Bus_I2C   _bus_instance;          // I2Cバスのインスタンス (ESP32のみ)

  // 「画面1」用のコンストラクタを作成し、各種設定を行います。
  public:
    LGFX_SSD1306_1() {  // コンストラクタ名はクラス名に合わせてLGFX_SSD1306_1として準備(クラス名と同じにする)
      { // 「画面1」のバス制御の設定を行います。
        auto cfg = _bus_instance.config();  // I2Cバス設定用の構造体を取得します。
        cfg.i2c_port    = 1;          // 使用するI2Cポートを選択
        cfg.freq_write  = 400000;     // 送信時のクロック
        cfg.freq_read   = 400000;     // 受信時のクロック
        cfg.pin_sda     = 21;         // SDAを接続しているピン番号
        cfg.pin_scl     = 25;         // SCLを接続しているピン番号
        cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス

        _bus_instance.config(cfg);    // 設定値をバスに反映します。
        _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
      }
      { // 「画面1」の制御設定を行います。
        auto cfg = _panel_instance.config();    // 表示パネル設定用の構造体を取得します。
        cfg.memory_width  = 128;      // ドライバICがサポートしている最大の幅
        cfg.memory_height =  64;      // ドライバICがサポートしている最大の高さ

        _panel_instance.config(cfg);  // 設定をパネルに反映
      }
      setPanel(&_panel_instance);     // 使用するパネルをセットします。
    }
};
static LGFX_SSD1306_1 lcd_1; // LGFX_SSD1306_1のインスタンス(クラスLGFX_SSD1306_1を使ってlcd_1でいろいろできるようにする)を作成
static LGFX_Sprite canvas_1(&lcd_1);  // スプライトを使うためのLGFX_Spriteのインスタンスを作成

// 初期設定 -------------------------------------------------------------------------
void setup() {
  M5.begin(true, true, true);   // 本体初期化(UART, I2C, LED)
  // LCD初期設定
  // 「画面0」***********************************
  lcd_0.init();                 // 「画面0」初期化
  canvas_0.setTextWrap(true);   // 右端到達時のカーソル折り返しを禁止
  canvas_0.createSprite(lcd_0.width(), lcd_0.height()); // スプライト用の仮想画面を画面幅を取得して準備
  // 「画面1」***********************************
  lcd_1.init();                 // 「画面1」初期化
  canvas_1.setTextWrap(true);   // 右端到達時のカーソル折り返しを禁止
  canvas_1.createSprite(lcd_1.width(), lcd_1.height()); // スプライト用の仮想画面を画面幅を取得して準備
}
// メイン ---------------------------------------------------------------------------
void loop() {
 // 「画面0」表示処理(メモリ描画領域canvas_0に描画)********************
  canvas_0.fillScreen(TFT_BLACK);    // 背景塗り潰し
  canvas_0.setTextColor(TFT_WHITE);  // 文字色と背景を指定(文字色, 背景)
  // 日本語表示
  canvas_0.setCursor(0, 0);                     // 座標を指定(x, y)
  canvas_0.setFont(&fonts::lgfxJapanGothic_28); // ゴシック体(8,12,16,20,24,28,32,36,40)
  canvas_0.println("画面0");                    // 表示内容をcanvas_0に準備
  canvas_0.println("SSD1306");                  // 表示内容をcanvas_0に準備
  
  canvas_0.pushSprite(0, 0);    // メモリ内に描画したcanvas_0を座標を指定して表示する

 // 「画面1」表示処理(メモリ描画領域canvas_1に描画)********************
  canvas_1.fillScreen(TFT_BLACK);    // 背景塗り潰し
  canvas_1.setTextColor(TFT_WHITE);  // 文字色と背景を指定(文字色, 背景)
  // 日本語表示1
  canvas_1.setCursor(0, 0);                     // 座標を指定(x, y)
  canvas_1.setFont(&fonts::lgfxJapanMincho_28); // 明朝体P(8,12,16,20,24,28,32,36,40)
  canvas_1.println("画面1");                    // 表示内容をcanvas_1に準備
  canvas_1.println("2画面表示");                 // 表示内容をcanvas_1に準備
  
  canvas_1.pushSprite(0, 0);    // メモリ内に描画したcanvas_1を座標を指定して表示する

  delay(100);
}

9.まとめ

「lovyanGFX」を使用して有機ELディスプレイ(OLED)「SSD1306」で日本語表示や図形、同一アドレス2画面表示を行う方法を紹介しました。

日本語表示は「ゴシック体(P)」と「明朝体(P)」があり、文字サイズも豊富(9種類)で、倍率で微調整もできます。小さいOLED液晶では漢字等の表示には限界がありますが簡単に表示できるため自由度は広がると思います。

メモリ内に仮想画面を準備して、仮想画面上で合成した画面を一括で出力できる「スプライト」もできるため、データ更新やグラフの描画等で画面のチラツキを抑えた表示を行うこともできます。

2画面について需要があるかは微妙ですが・・・液晶表示器付きの「CORE2」等のサブ画面やシリアル出力用モニタとしても活用できそうです。

前回の「M5Stackシリーズ」に続き、今回「OLED」での基本的な使用方法を紹介しました。
「lovyanGFX」では画像の描画にもたくさんの機能があるようなので、また紹介していきたいと思います。

lovyanGFXの使い方 M5Stackシリーズ編 基本的な表示(日本語、図形)方法
lovyanGFXで簡単日本語表示、データ更新やグラフ表示で「チラツキ」を抑えるための「スプライト」について、コピペ用サンプルプログラムでCORE2,M5Stick Plus,GRAYで表示して詳しく紹介します。

コメント

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