lovyanGFXの使い方 M5Stackシリーズ編 基本的な表示(日本語、図形)方法

lovyanGFXでM5Stackの液晶表示

M5Stackシリーズで日本語表示や「チラツキ」なく文字や数字、グラフを描画したいと思い、らびやんさん作の「lovyanGFX」を使用させていただくことにしました。

「lovyanGFX」にはたくさんの機能があるようですが、簡単に日本語表示ができることと、メモリ内で処理した画像を一気に出力(スプライト)して画面の「チラツキ」を抑えることができるため、これだけでも非常にありがたいです。

たくさん機能があり以下リンクの「Git Hub」で詳しく紹介されてますが、基本的な表示だけで十分便利なので、まずは日本語表示や線、図形等の基本的な表示方法を紹介したいと思います。

GitHub - lovyan03/LovyanGFX: SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51)
SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51) - GitHub - lovyan03/LovyanGFX: SPI LCD graphi...

今回は「M5Stackシリーズ」の「COR2」「GRAY」「M5StickC Plus」で実際にいろいろ表示させてみました。
ボードの自動認識機能があるので「M5Paper」や「CoreInk」でも同様に表示できると思います。


「lovyanGFX」で「SSD1306」等の有機ELディスプレイ(OLED)の表示を行う方法は以下のリンクで詳しく紹介しています。

SSD1306 OLEDで日本語表示 lovyanGFXの使い方
SSD1306でlovyanGFXを使用した日本語表示方法を紹介。ATOM LITEを使ってますがArduinoでも基本は同じで、他のOLEDでも初期設定を変えるだけです。

「M5Stack」標準ライブラリを使用した液晶表示器の基本的な使い方や「M5GFX」ライブラリの使い方は以下のリンクでまとめて詳しく紹介しています。

M5Stack 液晶表示の使い方まとめ - 完全版 -(Arduinoコマンド)
M5Stackの液晶の使い方を初期設定から文字表示(print,draw関数)中央揃えや右揃え,フォント,線,図形,M5GFXのスプライト等わかりやすくまとめました。
スポンサーリンク

1.サンプル画面の紹介

機種ごとにサンプル画面を下画像のように表示させました。

下画像上の小さいオレンジの物が「M5StickC Plus」で、左が「CORE2」右が「GRAY」です。

「CORE2」と「GRAY」は「M5StickC Plus」と画面幅(px数)を同じにするために画面を回転させて横向きで表示させてます。
lovyanGFXでM5Stackの液晶表示

サンプル画面には上から「日本語表示」「ボタンAのON/OFF状態表示(BTN)」「ボタンAを押した回数カウント表示(CNT)」「横線2本」「縦線1本」「円、三角、四角」「登録色19色(TFT_付は除く)を塗り潰し四角で並べて表示」してます。

「CORE2」と「GRAY」では画面下半分で「赤→緑→青→赤のグラデーション表示」を「スプライト」有り(上)「スプライト」無し(下)で表示させてます。

※「スプライト」についてはこの後「3.メモリ描画領域(スプライト)について」で紹介します。

写真ではわかりませんが「スプライト」無し(下)のグラデーションは点滅するような「チラツキ」が発生してます。

lovyanGFXでM5Stack CORE2の液晶表示

上画像は「CORE2」で「GRAY」も同じ表示です。「スプライト」を使用する時のカラーモードを16bit以上にすると表示されなかったため、8bitにして表示させてます。
このためグラデーションの上側は8bitで色数が少ないグラデーションとなってます。下側は「スプライト」無し(「チラツキ」発生)の直接表示で16bitの表示です。

lovyanGFXでM5StickC Plusの液晶表示

上画像は「M5StickC Plus」の表示です。
ボードの自動認識機能があるので、ヘッダファイルと画面の向きだけ設定すれば「COR2」のプログラムを簡単に流用できます。

こちらは「スプライト」有りの表示でカラーモード24bitでも問題なく表示されました。


「M5StickC Plus」を使用して、カラーモード8bit、16bit、24bitの場合でグラデーションの色の違いを確認しました。

下画像は左からカラーモード8bit、16bit、24bitで、画面の上半分の「スプライト」有り表示のbit数を変えています。下半分は「スプライト」無し(「チラツキ」発生)の直接表示で24bit固定です。

lovyanGFXでM5StickC Plusの液晶表示

画面上が8bit、下が24bitで解像度の違いがはっきり確認できます。

lovyanGFXでM5StickC Plusの液晶表示

画面上が16bit、下が24bitですが同じように見えます。

lovyanGFXでM5StickC Plusの液晶表示

画面上下両方24bitです。
写真写りが少し違いますが・・・16bitの時と目視では見分けがつきません。

「M5StickC Plus」はカラーモード24bitで指定しても18bitの処理になると思われます。
カラーモードの設定は「setColorDepth(16)」で16bit設定となりますが、書かなければ初期値の16bitのため、「M5StickC Plus」では書かなくても十分きれいな表示ができると思います。
「CORE2」「GRAY」の場合は16bitで「スプライト」が表示されなかったので「スプライト」用画面は「setColorDepth(8)」で8bitに設定しました。

「CORE2」と「M5StickC Plus」については以下のリンクで詳しく紹介しています。

M5Stack CORE2について、デモ画面、基本仕様、端子配列(機能)等を詳しく紹介
CORE2について工場出荷時デモ画面の動作確認方法や外観紹介から基本仕様、端子配列(一覧表にまとめました)、端子機能等を詳しく紹介します。
M5StickC Plusの使い方、初期設定、サンプルプログラム、M5StickCとの違い等を詳しく紹介
M5StickC PlusをArduino IDEやPlatformIOで使うための初期設定やサンプルプログラムでの動作確認の方法です。ビジュアルプログラミングのUiFlowの初期設定についても紹介します。
スポンサーリンク

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

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

「CORE2」のサンプルプログラムは以下のようになります。「コピペ」で確認してみましょう。
「GRAY」はヘッダを変えるだけで「M5StickC Plus」はヘッダと画面の向きと必要に応じて「setColorDepth」の設定を変えるだけで使用できます。

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

#include <M5Core2.h>    // CORE2使用の場合有効
// #include <M5Stack.h>       // M5Stack GRAY使用の場合有効
// #include <M5StickCPlus.h>  // M5StickC Plus使用の場合有効

#define LGFX_AUTODETECT // 自動認識(D-duino-32 XS, PyBadgeはパネルID読取れないため自動認識の対象から外れているそうです)
#define LGFX_USE_V1     // v1.0.0を有効に(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)
#include <LovyanGFX.hpp>          // lovyanGFXのヘッダを準備
#include <LGFX_AUTODETECT.hpp>    // クラス"LGFX"を準備
static LGFX lcd;                  // LGFXのインスタンスを作成(クラスLGFXを使ってlcdコマンドでいろいろできるようにする)
static LGFX_Sprite canvas(&lcd);  // スプライトを使う場合はLGFX_Spriteのインスタンスを作成

// 変数設定
int cnt;        // 本体ボタンON回数格納用
int x = 0;      // x軸座標格納用
uint16_t color; // 登録色格納用
// 初期設定 -----------------------------------------
void setup() {
  M5.begin();   // 本体初期化
  // LCD初期設定
  lcd.init();                 // LCD初期化
  lcd.setRotation(2);         // 画面向き設定(0~3で設定、4~7は反転) ※CORE2、GRAYの場合
  //lcd.setRotation(1);         // 画面向き設定(0~3で設定、4~7は反転) ※M5StickC Plusの場合
  canvas.setColorDepth(8);    // カラーモード設定(書かなければ初期値16bit。24bit(パネル性能によっては18bit)は対応していれば選択可)
                              // CORE2 GRAY のスプライトは16bit以上で表示されないため8bitに設定
  canvas.setTextWrap(false);  // 改行をしない(画面をはみ出す時自動改行する場合はtrue)
  canvas.setTextSize(1);      // 文字サイズ(倍率)
  canvas.createSprite(lcd.width(), lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)
}
// メイン -----------------------------------------
void loop() {
  M5.update();                      // 本体ボタン状態更新
  // LCD表示処理(canvas.で指定してメモリ内の仮想画面に描画していく)
  canvas.fillScreen(BLACK);         // 背景塗り潰し
  canvas.setTextColor(WHITE);       // 文字色と背景を指定(文字色, 背景(省略可))
  // 日本語表示
  canvas.setCursor(0, 0);                         // 座標を指定(x, y)
  canvas.setFont(&fonts::lgfxJapanGothic_24);     // ゴシック体(8,12,16,20,24,28,32,36,40)
  canvas.println("液晶表示 ゴシック体");            // 表示内容をcanvasに準備
  canvas.setCursor(0, 25);                        // 座標を指定(x, y)
  canvas.setFont(&fonts::lgfxJapanMincho_24);     // 明朝体(8,12,16,20,24,28,32,36,40)
  canvas.println("液晶表示 明朝体");               // 表示内容をcanvasに準備
  // 本体ボタンON/OFF状態表示
  if (M5.BtnA.isPressed()) {                      // ボタンを押していれば
    canvas.setTextColor(CYAN);                    // 文字色指定
    canvas.drawString("BTN=ON", 5, 56, &Font4);   // 本体ボタンON表示
  } else {                                        // ボタンを押してなければ
    canvas.setTextColor(WHITE);                   // 文字色指定
    canvas.drawString("BTN=OFF", 5, 56, &Font4);  // 本体ボタンOFF表示
  }
  // 本体ボタンON回数カウント表示
  if (M5.BtnA.wasPressed()) {         // ボタンが押されていたら
    cnt++;                            // カウント+1
  }
  canvas.setTextColor(WHITE);         // 文字色指定
  canvas.setCursor(125, 56, &Font4);  // 座標とフォントを指定(x, y, フォント)
  canvas.print("CNT=");               //「CNT=」表示
  canvas.setTextSize(0.5);            // 文字倍率変更
  canvas.setCursor(190, 53, &Font7);  // 座標とフォントを指定(x, y, フォント)
  canvas.printf("%03d", cnt);         // カウント数表示
  canvas.setTextSize(1);              // 文字倍率を戻す
  // 線(色は3種類の方法で指定)
  canvas.drawLine(0, 50, 240, 50, lcd.color332(255, 255, 255)); // 線(始点x,始点y,終点x,終点y,色)
  canvas.drawFastVLine(120, 50, 30, (uint8_t)0xFF);             // 線(始点x,始点y,始点からの垂線長さ,色)
  canvas.drawFastHLine(0, 80, 240, WHITE);                      // 線(始点x,始点y,始点からの平行線長さ,色)
  // 円
  canvas.drawCircle(20, 98, 13, WHITE); // 円(始点x,始点y,半径,色)
  canvas.fillCircle(51, 98, 13, WHITE); // 塗り潰し円(始点x,始点y,半径,色)
  // 三角
  canvas.drawTriangle(69, 110, 85, 86, 101, 110, WHITE);    // 三角(x0, y0, x1, y1, x2, y2, 色)
  canvas.fillTriangle(105, 110, 121, 86, 137, 110, WHITE);  // 塗り潰し三角(x0, y0, x1, y1, x2, y2, 色)
  // 四角
  canvas.drawRect(145, 85, 26, 26, WHITE);  // 四角(始点x,始点y,縦長さ,横長さ)
  canvas.fillRect(175, 85, 26, 26, WHITE);  // 塗り潰し四角(始点x,始点y,縦長さ,横長さ,色)
  // 色名登録色表示(TFT_付きは除く)
  x = 0;                          // x座標リセット
  for (int i = 0 ; i < 19; i++) { // 全19色(TFT_付は除く)分表示繰り返し
    switch (i) {
      case 0:   color = BLACK      ;  break;  //   0,   0,   0
      case 1:   color = NAVY       ;  break;  //   0,   0, 128
      case 2:   color = DARKGREEN  ;  break;  //   0, 128,   0
      case 3:   color = DARKCYAN   ;  break;  //   0, 128, 128
      case 4:   color = MAROON     ;  break;  // 128,   0,   0
      case 5:   color = PURPLE     ;  break;  // 128,   0, 128
      case 6:   color = OLIVE      ;  break;  // 128, 128,   0
      case 7:   color = LIGHTGREY  ;  break;  // 192, 192, 192
      case 8:   color = DARKGREY   ;  break;  // 128, 128, 128
      case 9:   color = BLUE       ;  break;  //   0,   0, 255
      case 10:  color = GREEN      ;  break;  //   0, 255,   0
      case 11:  color = CYAN       ;  break;  //   0, 255, 255
      case 12:  color = RED        ;  break;  // 255,   0,   0
      case 13:  color = MAGENTA    ;  break;  // 255,   0, 255
      case 14:  color = YELLOW     ;  break;  // 255, 255,   0
      case 15:  color = WHITE      ;  break;  // 255, 255, 255
      case 16:  color = ORANGE     ;  break;  // 255, 165,   0
      case 17:  color = GREENYELLOW;  break;  // 173, 255,  47
      case 18:  color = PINK       ;  break;  // 255, 0  , 255
    }
    canvas.fillRect(x , 115, 12, 20, color);  // 塗り潰し四角でcolorを表示
    x = x + 12;                               // x座標を+12
  }
  // グラデーション表示(スプライト有り、仮想画面に描画)
  for (int i = 0; i < 80; i++) {
    canvas.drawGradientLine( 0, 150 + i, 79, 150 + i, RED, GREEN);    // 赤から緑へのグラデーション直線
    canvas.drawGradientLine( 80, 150 + i, 159, 150 + i, GREEN, BLUE); // 緑から青へのグラデーション直線
    canvas.drawGradientLine( 160, 150 + i, 240, 150 + i, BLUE, RED);  // 青から赤へのグラデーション直線
  }
  canvas.pushSprite(0, 0);  // メモリ内に描画したcanvasを座標を指定して表示する

  // グラデーション表示(スプライト無し、直接表示)
  for (int i = 0; i < 80; i++) {
    lcd.drawGradientLine( 0, 240 + i, 79, 240 + i, RED, GREEN);     // 赤から緑へのグラデーション直線
    lcd.drawGradientLine( 80, 240 + i, 159, 240 + i, GREEN, BLUE);  // 緑から青へのグラデーション直線
    lcd.drawGradientLine( 160, 240 + i, 240, 240 + i, BLUE, RED);   // 青から赤へのグラデーション直線
  }
  delay(100); // 遅延時間(ms)
}

・初期設定と日本語表示のみ抜粋

サンプル画面にはいろいろ表示させてわかりにくいかもしれませんので、シンプルに日本語を1文だけ表示するプログラムを以下に抜粋しました。「コピペ」で確認してみましょう。

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

#include <M5Core2.h>    // CORE2使用の場合有効
// #include <M5Stack.h>       // M5Stack GRAY使用の場合有効
// #include <M5StickCPlus.h>  // M5StickC Plus使用の場合有効

#define LGFX_AUTODETECT // 自動認識(D-duino-32 XS, PyBadgeはパネルID読取れないため自動認識の対象から外れているそうです)
#define LGFX_USE_V1     // v1.0.0を有効に(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)

#include <LovyanGFX.hpp>          // lovyanGFXのヘッダを準備
#include <LGFX_AUTODETECT.hpp>    // クラス"LGFX"を準備

static LGFX lcd;                  // LGFXのインスタンスを作成(クラスLGFXを使ってlcdコマンドでいろいろできるようにする)
static LGFX_Sprite canvas(&lcd);  // スプライトを使う場合はLGFX_Spriteのインスタンスを作成

// 初期設定 -----------------------------------------
void setup() {
  M5.begin();   // 本体初期化

  // LCD初期設定
  lcd.init();                 // LCD初期化
  lcd.setRotation(1);         // 画面向き設定(0~3で設定、4~7は反転)
  canvas.setColorDepth(8);    // カラーモード設定(書かなければ初期値16bit。24bit(パネル性能によっては18bit)は対応していれば選択可)
                              // CORE2 GRAY、のスプライトは16bit以上で表示されないため8bitに設定
  canvas.setTextWrap(false);  // 改行をしない(画面をはみ出す時自動改行する場合はtrue)
  canvas.setTextSize(1);      // 文字サイズ(倍率)
  canvas.createSprite(lcd.width(), lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)
}
// メイン -----------------------------------------
void loop() {
  // LCD表示処理(canvas.で指定してメモリ内の仮想画面に描画していく)
  canvas.fillScreen(BLACK);   // 背景塗り潰し
  canvas.setTextColor(WHITE); // 文字色と背景を指定(文字色, 背景(省略可))

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

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

  delay(100); // 遅延時間(ms)
}
スポンサーリンク

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

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

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

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

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

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

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


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

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

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

if (M5.BtnA.isPressed()) {                   // ボタンを押していれば
  lcd.setTextColor(CYAN);                    // 文字色指定
  lcd.drawString("BTN=ON", 5, 56, &Font4);   // 本体ボタンON表示
} else {                                     // ボタンを押してなければ
  lcd.setTextColor(WHITE);                   // 文字色指定
  lcd.drawString("BTN=OFF", 5, 56, &Font4);  // 本体ボタンOFF表示
}

書き込んで実行すると「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.ヘッダーファイルの準備

以下にヘッダー部分だけ抜粋して紹介します。

下コードの1行目では使用するマイコンボードごとのヘッダファイル「M5Stack.h」「M5Core2.h」「M5StickCPlus.h」等を設定してください。

3~7行目は「lovyanGFX」を使用するために必要な設定なので、そのまま書きます。

#include < 機種ごとのヘッダファイル >

#define LGFX_AUTODETECT // 自動認識(D-duino-32 XS, PyBadgeはパネルID読取れないため自動認識の対象から外れているそうです)
#define LGFX_USE_V1     // v1.0.0を有効に(v0からの移行期間の特別措置とのこと。書かない場合は旧v0系で動作)

#include <LovyanGFX.hpp>          // lovyanGFXのヘッダを準備
#include <LGFX_AUTODETECT.hpp>    // クラス"LGFX"を準備

static LGFX lcd;                  // LGFXのインスタンスを作成(クラスLGFXを使ってlcdコマンドでいろいろできるようにする)
static LGFX_Sprite canvas(&lcd);  // スプライトを使う場合はLGFX_Spriteのインスタンスを作成

9行目では直接表示を行うコマンドを「lcd」として準備しています。
名前は何でも良いので「display」等も使われます。

10行目では「スプライト」を使用するためのコマンドを「canvas」として準備しています。
ここも名前は何でもいいので「sprite」としてもわかりやすいです。
仮想画面に文字や図形を「描画」するので「canvas」という名前が良く使われています。

5.初期設定について

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

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

// 初期設定 -----------------------------------------
void setup() {
  M5.begin();   // 本体初期化
  // LCD初期設定
  lcd.init();                 // LCD初期化
  lcd.setRotation(2);         // 画面向き設定(0~3で設定、4~7は反転) ※CORE2、GRAYの場合
  //lcd.setRotation(1);         // 画面向き設定(0~3で設定、4~7は反転) ※M5StickC Plusの場合
  canvas.setColorDepth(8);    // カラーモード設定(書かなければ初期値16bit。24bit(パネル性能によっては18bit)は対応していれば選択可)
                              // CORE2 GRAY のスプライトは16bit以上で表示されないため8bitに設定
  canvas.setTextWrap(false);  // 改行をしない(画面をはみ出す時自動改行する場合はtrue)
  canvas.setTextSize(1);      // 文字サイズ(倍率)
  canvas.createSprite(lcd.width(), lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)
}
カラーモード(setColorDepth)について、書かない場合は初期値の16bitとなりますが「CORE2」「GRAY」で「スプライト」を使う場合は8bitに設定しないと表示されなかったため「canvas.setColorDepth(8)」と設定してます。
「M5StickC Plus」では「setColorDepth(24)」でも表示されましたが「setColorDepth(16)」と色の違いは感じられなかったので書かずに省略してもよいと思います。

6.色の指定方法いろいろ

色を指定する方法はたくさんあるので紹介します。

まずは以下のように画面(「スプライト」用の仮想画面も同じ)のカラーモードを設定します。
設定しない場合は初期値の16bitになります。

// カラーモードの設定(仮想画面は「lcd」の部分を「canvas」にして設定)
lcd.setColorDepth(8);   // RGB332の8ビットに設定する場合
lcd.setColorDepth(16);  // RGB565の16ビットに設定する場合
lcd.setColorDepth(24);  // RGB888の24ビットに設定する場合
                        // 表示される色数はパネル性能によりRGB666の18ビットになります。
「CORE2」と「GRAY」で「スプライト」を使用する場合、16bit以上では表示されなかったため「canvas」の設定は8bitとしてください。

次に文字や図形の色の指定方法を紹介します。

一番簡単なのは登録済の色を「RED」や「WHITE」等アルファベットの大文字で指定する方法です。
色数は19色(TFT_付を除く)登録されているのでこれだけでも文字や図形であれば問題ないと思います。

登録されている色名一覧は以下のようになります。
※R,G,B値はライブラリファイルのコメントより抜粋

// 登録色一覧          //   R,   G,   B
BLACK       = 0x0000; //   0,   0,   0
NAVY        = 0x000F; //   0,   0, 128
DARKGREEN   = 0x03E0; //   0, 128,   0
DARKCYAN    = 0x03EF; //   0, 128, 128
MAROON      = 0x7800; // 128,   0,   0
PURPLE      = 0x780F; // 128,   0, 128
OLIVE       = 0x7BE0; // 128, 128,   0
LIGHTGREY   = 0xC618; // 192, 192, 192
DARKGREY    = 0x7BEF; // 128, 128, 128
BLUE        = 0x001F; //   0,   0, 255
GREEN       = 0x07E0; //   0, 255,   0
CYAN        = 0x07FF; //   0, 255, 255
RED         = 0xF800; // 255,   0,   0
MAGENTA     = 0xF81F; // 255,   0, 255
YELLOW      = 0xFFE0; // 255, 255,   0
WHITE       = 0xFFFF; // 255, 255, 255
ORANGE      = 0xFD20; // 255, 165,   0
GREENYELLOW = 0xAFE5; // 173, 255,  47
PINK        = 0xF81F; // 255,   0, 255

オリジナルの色を設定したい場合はビット数に応じて以下表のように設定します。

lovyanGFX色の指定方法

8bitの色指定例

// 登録色で指定
lcd.drawFastHLine(0, 100, 240, WHITE);  //「白」で平行線を引く

// int8_t型、uint8_t型で8ビットの変数として設定
uint8_t color = 0x6d;    // 0110|1101(RRRG|GGBB)※R:3bit、G:3bit、B:2bit
lcd.drawFastHLine(0, 110, 240, color);  //「color(灰色)」で平行線を引く

// 8bitでR赤,G緑,B青を指定
lcd.drawFastHLine(0, 120, 240, (uint8_t)0xFF);  //「白」で平行線を引く
                                                // ※uint8_t無しだと16bit扱い(0x00FF)でほぼ青色になる
lcd.drawFastHLine(0, 130, 240, lcd.color332(127, 127, 127));  // 「灰色」で平行線を引く(R,G,B)を0~255で設定

16bitの色指定例

// 登録色で指定
lcd.setTextColor(YELLOW);   // 文字色を「黄色」に設定

// int16_t型、uint16_t型で16ビットの変数として設定
uint16_t color = 0xFFE0;    // 1111|1111|1110|0000(RRRR|RGGG|GGGB|BBBB)※R:5bit、G:6bit、B:5bit
lcd.setTextColor(color);    // 文字色を「color(黄色)」に設定

// 16bitでR赤,G緑,B青を指定
lcd.setTextColor(0xFFE0);  // 文字色を「黄色」に設定
lcd.setTextColor(lcd.color565(255, 255,  0));  // 文字色を「黄色」に設定、(R,G,B)を0~255で設定

24bitの色指定例

// 登録色で指定
lcd.setColor(ORANGE);       // 描画色を「オレンジ」に設定

// uint32_t型で32ビットの変数として24ビットを設定
uint32_t color = 0xFF00FF;  // ----|----|1111|1111|0000|0000|1111|1111
                            //(----|----|RRRR|RRRR|GGGG|GGGG|BBBB|BBBB)※R:8bit、G:8bit、B:8bit
lcd.setColor(color);        // 描画色を「color(ピンク)」に設定

// 24bitでR赤,G緑,B青を指定
lcd.setColor((uint32_t)0xFFFFFF);  // 描画色を「白」に設定(32bitにキャスト)
lcd.setColor(0x00FF00U);           // 描画色を「緑」に設定(32bitにキャスト)
lcd.setColor(lcd.color888(0, 0, 255));  // 描画色を「青」に設定、(R,G,B)を0~255で設定

図形を描画する時の色の指定例

描画関数の最終引数の色は省略できるので、同じ色で繰り返し描画する場合は、省略した方がわずかに速く動作するようです。
省略した場合は「setColor」で設定した色、または最後に使用した色を描画色として使用します。

lcd.setColor(RED);                              // 描画色に赤色を指定
lcd.fillCircle(51, 98, 13);                     // 塗り潰し円(始点x,始点y,半径)
lcd.fillTriangle(105, 110, 121, 86, 137, 110);  // 塗り潰し三角(x0, y0, x1, y1, x2, y2)
lcd.fillRect(175, 85, 26, 26);                  // 塗り潰し四角(始点x,始点y,縦長さ,横長さ)

// グラデーションの線を描画する drawGradientLine は色の指定を省略できません。
lcd.drawGradientLine( 0, 130, 240, 130, 0xFF0000U, 0x0000FFU); // 赤から青へのグラデーション直線

7.文字の表示方法

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

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

// 文字の表示
lcd.drawString("文字表示", 10, 0);          // (文字列, x座標, y座標)
lcd.drawString("文字表示", 10, 0, &fonts::lgfxJapanGothic_12);  // (文字列, x座標, y座標, フォント)

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

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

表示座標について、初期値は左上が基準ですが、右揃えや中央揃えで描画したい場合は、「setTextDatum」で基準位置を指定します。
縦方向が top、middle、baseline、bottomの4通り、横方向が left、center、rightの3通りで以下の12通りが指定できます。

lcd.setTextDatum( top_left        );  // 上左(初期値)
lcd.setTextDatum( top_center      );  // 上中央
lcd.setTextDatum( top_right       );  // 上右
lcd.setTextDatum( middle_left     );  // 中左
lcd.setTextDatum( middle_center   );  // 真ん中
lcd.setTextDatum( middle_right    );  // 中右
lcd.setTextDatum( baseline_left   );  // ベースライン左 ※ベースラインは文字の基準ライン(gやjは下にはみ出る)
lcd.setTextDatum( baseline_center );  // ベースライン中央 
lcd.setTextDatum( baseline_right  );  // ベースライン右
lcd.setTextDatum( bottom_left     );  // 下左
lcd.setTextDatum( bottom_center   );  // 下中央
lcd.setTextDatum( bottom_right    );  // 下右
setTextDatum」はprint系関数では縦方向の指定のみ有効で、横方向の指定は無効です。

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

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

// print 関数では、setCursor関数で指定した座標 (またはprint関数で最後に描画した文字の続き)に描画
lcd.setCursor(10, 20);
lcd.print("改行なしで文字表示");

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

// printf関数では、第2引数以降の内容を描画(複数指定可、C言語のprintfと同じように表示)
int value = 123;
lcd.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を格納

lcd.printf("|%f|\n", value);     // |3.140000| そのまま表示
lcd.printf("|%.2f|\n", value);   // |3.14|     小数点2桁まで表示
lcd.printf("|%6.2f|\n", value);  // |  3.14|   6文字分のスペースで表示(右揃え)
lcd.printf("|%06.2f|\n", value); // |003.14|   6文字分のスペースで0埋め表示
lcd.printf("|%-6.2f|\n", value); // |3.14  |   6文字分のスペースで表示(左揃え)

・文字の表示

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

// setFont でフォントを指定
lcd.setFont(&fonts::lgfxJapanMinchoP_16);

// setTextColor で文字色と背景を指定
lcd.setTextColor(WHITE, RED);  //(文字色, 背景色)
lcd.println("文字白色、背景赤色");

// 背景は省略できますが更新時に前の文字と重なるため背景指定推奨
lcd.setTextColor(WHITE);         //(文字色)
lcd.println("文字白色、背景塗り潰しなし");
TFT_eSPIとの互換性のために「setTextFont」関数による番号でのフォント指定にも対応してますが、他の番号のフォントも強制的にバイナリに含まれサイズが膨らむため、非推奨のようです。
lcd.setTextFont(2);          // 非推奨
lcd.setFont(&fonts::Font2) // 推奨

基本的なフォントは以下のようになります。

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

「CORE2」を使用して各Fontを表示すると以下のようになります。

lovyanGFXで液晶表示ASCII文字 CORE2

「Font0,2,6」でASCII文字の一覧を表示させたものが上画像になります。
「Font0」はすごく小さいですが、表示はきれいで十分読み取れます。
「Font2」も小さいですが、こちらもきれいで読み取りやすいです。
「Font4」はちょうどいいサイズでこれがメインになりそうです。


lovyanGFXで液晶表示 CORE2

「Font6,7」を表示させたものが上画像になります。
「Font6」は下にスペースが開くのでちょっとクセがあります。
「Font7」は拡大縮小して使用すればデータ表示用として活躍できそうです。

lovyanGFXで液晶表示 CORE2

「Font8」を表示させたものが上画像になります。
ちょっと大きいので用途は限られそうですがきれいな表示です。

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

・日本語フォント

日本語フォントには以下の物が指定できます。
「efont」では中国語、韓国語のフォントも指定できます。


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 プロポーショナルフォント

efontをコンバートした日本語・韓国語・中国語(簡体字・繁体字)フォントが
各4種類x5サイズ = 20通りプリセットされています。
末尾の数字がサイズを表しており、10, 12, 14, 16, 24 が用意されています。
末尾の文字は b= ボールド(太字) / i= イタリック(斜体) を表しています。

&fonts::efontJA_10     // 日本語 サイズ10
&fonts::efontCN_12_b   // 簡体字 サイズ12 ボールド
&fonts::efontTW_14_bi  // 繁体字 サイズ14 ボールドイタリック
&fonts::efontKR_16_i   // 韓国語 サイズ16 イタリック
補完(エメット)機能のあるエディタの場合「&fonts::」まで入力すると、使用可能なフォントが一覧で表示されます。

「CORE2」を使用して日本語フォントを幾つか表示してみました。
16pxでも小さな文字ですが問題なく読めます。8pxはさらにこの半分なので読むのは大変かもしれません。

「efont」が若干きれいに見えますが、この後で確認する消費メモリの大きさを考えると使用には注意が必要と思います。

lovyanGFXで日本語表示 CORE2

日本語フォント、サイズごとのメモリ使用量確認

日本語のフォントで文字サイズごとにFlashメモリの使用量を確認してみました。
確認は「PlatformIO」でコンパイル時のターミナルのメモリ使用量の表示で行いました。

使用量の単位は(KB = キロバイト)です。

文字サイズ明朝体明朝体Pゴシック体ゴシック体Pefont_JA
8px72656966226(10px)
16px167163159161
24px290258279277467
32px403397397398744
40px545538534536

今回使用した各ボードのFlashメモリ容量は以下のようになります。
・M5StickC Plus:1310KB
・GRAY  :1310KB
・CORE2:6553kB

「CORE2」はメモリ容量が多いので、あまり気にしなくてもよさそうですが「M5StickC Plus」等はメモリ容量が少ないため、フォントの容量を気にしておかないと肝心の処理系プログラムが書き込めず、後半にフォントの変更が必要になり、画面を作り直さなくてはいけなくなるかもしれませんので注意しましょう。

「efont」は「IPA」の明朝体やゴシック体に比べてメモリの消費量が多いです。
特にこだわりが無ければ「IPA」の方をおすすめします。

・その他のフォント

日本語表示以外では他に以下のフォントがあります。

//名前が"Free"で始まるフォントは 9pt 12pt 18pt 24ptの4種類があります。
&fonts::TomThumb
&fonts::FreeMono9pt7b
&fonts::FreeMonoBold9pt7b
&fonts::FreeMonoOblique9pt7b
&fonts::FreeMonoBoldOblique9pt7b
&fonts::FreeSans9pt7b
&fonts::FreeSansBold9pt7b
&fonts::FreeSansOblique9pt7b
&fonts::FreeSansBoldOblique9pt7b
&fonts::FreeSerif9pt7b
&fonts::FreeSerifBold9pt7b
&fonts::FreeSerifItalic9pt7b
&fonts::FreeSerifBoldItalic9pt7b
&fonts::Orbitron_Light_24
&fonts::Roboto_Thin_24
&fonts::Satisfy_24
&fonts::Yellowtail_32

・文字サイズ(倍率)設定

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

// setTextSize で文字の拡大率を指定
lcd.setTextSize(2.5, 3);     //(横方向倍率, 縦方向倍率)
lcd.println("文字 横2.5倍、 縦3倍");

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

・表示範囲の制限

setClipRect」で以下のように描画する範囲を限定でき、指定した範囲外には描画されなくなります。テキスト系だけでなく全ての表示に影響します。

// 描画したい範囲を四角い範囲で指定します。
lcd.setClipRect(10, 10, 100, 100);  //(x座標, y座標, 横幅, 縦長さ)

8.線、図形の表示方法

線や図形の表示は以下のように指定します。

lcd.drawPixel     (x, y, color);  // 点

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

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

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

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

lcd.drawArc       ( x, y, r0, r1, angle0, angle1, color);  // 円弧の外周
lcd.fillArc       ( x, y, r0, r1, angle0, angle1, color);  // 円弧の塗り
// 円弧の設定詳細 r0 = 外円半径、r1 = 内円半径、angle0 = 開始角度、angle1 = 終了角度 ※角度0度は右
「color」部の色の指定は省略可能で、同じ色で描画する場合は「setColor」で事前に設定した方がわずかに早く描画できるようです。

9.まとめ

「lovyanGFX」を使用して基本的な表示を行う方法を紹介しました。

日本語表示も「ゴシック体(P)」と「明朝体(P)」があり、文字サイズも豊富(9種類)で、倍率で微調整もできるためイメージ通りの表示画面が簡単に作れると思います。

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

ボードの自動認識機能があるため「M5Stack」シリーズであれば機種ごとのヘッダファイルさえ記述すれば、ほぼ同じ設定で使用可能です。

今回は日本語や図形等の基本的な使い方だけ紹介しましたが、外付けの有機ELディスプレイ(OLED SSD1306等複数対応)の表示も簡単にでき、画像の描画に関してもいろいろな機能があるようなので、また紹介していきたいと思います。

SSD1306 OLEDで日本語表示 lovyanGFXの使い方
SSD1306でlovyanGFXを使用した日本語表示方法を紹介。ATOM LITEを使ってますがArduinoでも基本は同じで、他のOLEDでも初期設定を変えるだけです。

コメント

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