有機ELディスプレイ(OLED)「SSD1306」で日本語表示を行う方法を紹介します。
以前、以下のリンクで「SSD1306」についてと使用方法を紹介しました。
この時は「Adafruit社」から提供されているライブラリを使用しましたが、日本語の表示については ひと手間必要で詳しく紹介できず紹介のみとなってしまいました。
今回は簡単に日本語表示ができる、らびやんさん作の「lovyanGFX」を使用させていただきました。
OLEDは「SSD1306」を使用しましたが「lovyanGFX」はたくさんの表示器に対応しており、他のOLEDでも初期設定を変えるだけで表示できてとても便利です。
また、シリアルポートごとに個別に設定を行うことが出来るため、2系統のシリアル通信のあるボードならOLEDの通信アドレスが同じものでも違う内容で2画面表示できるので、こちらも紹介したいと思います。
1.サンプル画面の紹介
2.サンプルプログラム(コピペ)
・サンプル画面プログラム
・日本語表示部のみ抜粋
3.メモリ描画領域(スプライト)について
4.ヘッダーとOLEDの通信設定について
5.初期設定について
6.基本的な文字、図形表示方法
・フォントの指定
・文字の表示
・文字サイズ(倍率)の指定
・図形の表示
7.同一通信アドレス、2画面表示方法
8.2画面サンプルプログラム(コピペ)
9.まとめ
1.サンプル画面の紹介
「SSD1306」はM5Stackシリーズの「ATOM LITE」と接続して動作確認を行いました。
「ATOM LITE」については以下のリンクで詳しく詳しく紹介しています。
サンプル画面には上から「日本語表示」「本体ボタンのON/OFF状態表示(BTN)」「本体ボタンを押した回数カウント表示(CNT)」「横線2本」「縦線1本」「円、三角、四角」を並べて表示しています。
「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表示
}
本体ボタンの使い方、ボタン操作関数一覧については以下のリンクで詳しく紹介しています。
書き込んで実行すると「BTN= 」の部分の表示だけが点滅していると思います。
この表示部は「ON」と「OFF」の表示文字数が違うため「OFF」のあとに「ON」を指定すると「OFF」の上に「ON」が表示されるため、重なって「ONF」となってしまいます。
こうならないように事前に「” “」スペースで全文消去を行っており、消去と表示が繰り返し表示されることになります。
「canvas」で指定した仮想画面内で画像を処理してから表示させることで画面の「チラツキ」を抑えることができます。
以前紹介した以下リンクのストップウオッチを作るプログラムでは、タイマー割込みを使用して0.01秒の表示を高速で行いたいため「lcd」を採用しています。(lovyanGFXではなくM5GFXライブラリ使用)
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で詳しく紹介されています。
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()); // スプライト用の仮想画面を画面幅を取得して準備
}
6.基本的な文字、図形表示方法
基本的な文字(フォント、日本語、サイズ、倍率)や図形の表示方法を紹介します。
・フォントの指定
文字の表示はフォントを「setFont」で指定し、文字色と背景色を「setTextColor」で以下のように指定します。
// 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.:-)
「Font」ごとに「SSD1306」に表示すると下画像のようになります。
Font0 8px ASCII
Font2 16px ASCII
Font4 26px ASCII
Font6 36(48)px
数字と時計用 apm . : –
Font7 48px
7セグ風数字と . : –
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 プロポーショナルフォント
「明朝体」をサイズごとに表示すると下画像のようになります。
「ゴシック体」をサイズごとに表示すると下画像のようになります。
他のフォントやefontの消費メモリ等は以下のリンクで詳しく紹介しています。
・文字の表示
・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は「変換指定子」で、扱うデータの「型」によって使い分けます。
「変換指定子」はたくさんありますが、主なものは下表のようになります。
変換指定子 | 対応する型 | 出力される内容 |
%c | char | 1文字だけ |
%s | char(配列) | 文字列 |
%d | int | 10進数 |
%u | unsigned int | 10進数(符号なし) |
%ld | long | 10進数(倍精度) |
%x,%X | unsigned int | 16進数 |
%f | double(float型以上) | 浮動小数点数(実数) |
「型」については以下リンクの「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_0 と LGFX_SSD1306_1」を作成して、直接表示「lcd_0と lcd_1」のインスタンスと、スプライト(仮想画面)表示「canvas_0 と canvas_1」のインスタンスを個別に作成して、それぞれの画面表示に使用します。
実際に「ATOM LITE」に「SSD1306」を2個使用して2画面表示したものが下画像になります。
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」では画像の描画にもたくさんの機能があるようなので、また紹介していきたいと思います。
コメント