ESP32 で 日本語漢字フォント をカラー OLED に表示させ、4行同時スクロール ( SSD1331 使用)

ESP32 ( ESP-WROOM-32 )

電光掲示板風スクロール方法

次に、文字列1行を右から左へスクロールするスケッチです。

ブラウザからスケッチをコピーしたら、必ず一旦保存してください。そうしないと正しく表示されませんので要注意!!

【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

#include "ESP32_SD_ShinonomeFNT.h"
#include "ESP32_SD_UTF8toSJIS.h"
#include "ESP32_SSD1331.h"

const char* UTF8SJIS_file = "/font/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく
const char* Shino_Zen_Font_file = "/font/shnmk16.bdf"; //全角フォントファイル名を定義
const char* Shino_Half_Font_file = "/font/shnm8x16.bdf"; //半角フォントファイル名を定義

const uint8_t CS_SD = 5; //SD card CS ( Chip Select )

const uint8_t SCLK_OLED =  14; //SCLK
const uint8_t MOSI_OLED =  13; //MOSI (Master Output Slave Input)
const uint8_t MISO_OLED =  12; //これは実際は使っていない。MISO (Master Input Slave Output)
const uint8_t CS_OLED = 15;
const uint8_t DC_OLED =  16; //OLED DC(Data/Command)
const uint8_t RST_OLED =  4; //OLED Reset

ESP32_SSD1331 ssd1331(SCLK_OLED, MISO_OLED, MOSI_OLED, CS_OLED, DC_OLED, RST_OLED);

ESP32_SD_ShinonomeFNT SFR(CS_SD, 24000000);
ESP32_SD_UTF8toSJIS u8ts;

const uint16_t MaxTxt = 100; //Shift_JISコードの最大数

uint8_t sj_txt[MaxTxt]; //Shift_JISコード格納
uint16_t Scrolle_speed = 10; //文字列スクロールインターバル時間
uint32_t scl_LastTime = 0;
uint8_t Fnt_buf[2][16]; //フォント格納
uint16_t sj_length = 0; //Shift_JISコードの長さ
uint8_t scl_cnt = 0; //フォントのスクロールカウント数(ドット単位)
uint16_t SJ_cnt = 0; //Shift_JISコードカウント
bool fnt_read_flag = true; //フォントを読み込むか否かのフラグ
uint8_t ZorH = 0; //全角ならば 2 , 半角ならば 1 を格納
uint8_t dummy_cnt = 0; //全角ならば次のフォントを読み込むかどうかのカウント

void setup() {
  Serial.begin(115200);
  ssd1331.SSD1331_Init(); //OLED SSD1331 初期化
  
  SFR.SD_Shinonome_Init2F(Shino_Half_Font_file, Shino_Zen_Font_file); //ライブラリ初期化。2ファイル同時に開く
  u8ts.ESP32_SD_UTF8toSJIS_Init(UTF8SJIS_file); //ライブラリ初期化

  String str1 = "やっとESP32で日本語フォント表示ができたよ~ん!!!";
  
  sj_length = u8ts.UTF8_to_SJIS(str1, sj_txt); //String 文字列をSift_JISコードに変換

  scl_LastTime = millis();
}

void loop() {
  if(millis() - scl_LastTime > Scrolle_speed){
    if(fnt_read_flag == true){
      //フォントを読み込んだら、SJ_cnt を1つ進める
      ZorH = SFR.Sjis_inc_FntRead(sj_txt, sj_length, &SJ_cnt, Fnt_buf);
    }
    //半角の場合、scl_cntが 8 になったら次のフォントを読み込む。全角の場合は16までスクロールする
    fnt_read_flag = ssd1331.Scroller_8x16_RtoL(0, ZorH, Fnt_buf[dummy_cnt], &scl_cnt, &dummy_cnt, 7, 7, 3);
    scl_LastTime = millis();
  }
}

【解説】

●1-20行:
ここまでは前のスケッチと同じです。

●21行目:
ESP32_SD_ShinonomeFNT.h 内で ESP32_SD_UTF8toSJIS.h をインクルードしていますが、ここでは、UTF8コードから Shift_JISコードへ独立して変換する必要があるため、ここでクラス宣言します。

●23行:
Shift_JIS コード配列の最大数を決めます。
とりあえず、半角100文字分としておきます。

●25-34行:
ここでは、文字列を電光掲示板のようにスクロールさせる変数を初期化しています。
scl_cnt はスクロールカウントを1ドットずつカウントします。
カウントが7まで進んだら半角分進みます。
SJ_cnt は Shift_JISコードの sj_txt 配列のカウントです。
要するに、半角の場合、scl_cnt が7まで進んだら SJ_cnt を1つ進めてフォントを読み込むという感じにします。
読み込む場合は fnt_read_flag が true になります。
ZorH は読み込んだフォントが全角ならば 2 半角ならば 1 になります。
半角ならば、フォントのdummy_cnt がゼロのままで、全角ならば半角分スクロールしたら 1 になります。
これらの変数は毎回繰り返してもメモリに保持しておかなければならないので、グローバル変数領域で宣言する必要があります。

●40行:
ここでは、2ファイルだけ開くので、この関数を使います。

●41行:
ESP32_SD_UTF8toSJIS ライブラリを初期化します。
ここで3つ目のファイルとして、UTF8toSjis.tbl ファイルを開きます。

●45行:
今回新たに登場した関数で、String 文字列から一気に Shift_JIS コードへ変換して、コード長を返します。

●51行:
ここで文字列のスクロール速度を調整します。

●52-58行:
54行目では、SJ_cnt カウントに値する Shift_JIS コードを読み取り、フォントに変換します。
全角ならば ZorH に2を返し、半角ならば1を返します。
57行の Scroller_8x16_RtoL 関数が呼び出される度に、scl_cnt が1つずつ進み、フォントが1ドットずつ移動します。
これは以前の記事でも紹介した、グラフィックアクセラレーションコマンドを使ってスクロールしています。
全角ならば dummy_cnt を0~1まで進めて全角文字を表示させます。
全角の場合、16ドット移動したら、fnt_read_flag にtrue を返し、次のフォントを読み込みます。

以上です。
いかがでしょうか。
ESP8266 のときよりか、格段にスクロール関数が簡単になったと思いませんか?
私的にもとても面倒だったので、これで作業がはかどります。

では、これをコンパイル実行させてみてください。
下図の動画のように表示されればOKです。

ブラウザからスケッチをコピーしたら、必ず一旦保存してください。そうしないと正しく表示されませんので要注意!!

 4行同時にスクロールしてみる

では、上記のものを応用して、今まで出来なかった、4行同時スクロールしてみたいと思います。
以下のスケッチを入力してみてください。

ブラウザからスケッチをコピーしたら、必ず一旦保存してください。そうしないと正しく表示されませんので要注意!!

【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

#include "ESP32_SD_ShinonomeFNT.h"
#include "ESP32_SD_UTF8toSJIS.h"
#include "ESP32_SSD1331.h"

const char* UTF8SJIS_file = "/font/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく
const char* Shino_Zen_Font_file = "/font/shnmk16.bdf"; //全角フォントファイル名を定義
const char* Shino_Half_Font_file = "/font/shnm8x16.bdf"; //半角フォントファイル名を定義

const uint8_t CS_SD = 5; //SD card CS ( Chip Select )

const uint8_t SCLK_OLED =  14; //SCLK
const uint8_t MOSI_OLED =  13; //MOSI (Master Output Slave Input)
const uint8_t MISO_OLED =  12; //これは実際は使っていない。MISO (Master Input Slave Output)
const uint8_t CS_OLED = 15;
const uint8_t DC_OLED =  16; //OLED DC(Data/Command)
const uint8_t RST_OLED =  4; //OLED Reset

ESP32_SSD1331 ssd1331(SCLK_OLED, MISO_OLED, MOSI_OLED, CS_OLED, DC_OLED, RST_OLED);

ESP32_SD_ShinonomeFNT SFR(CS_SD, 24000000);
ESP32_SD_UTF8toSJIS u8ts;

const uint16_t MaxTxt = 100; //Shift_JISコードの最大数

uint8_t sj_txt[4][MaxTxt]; //Shift_JISコード格納
uint16_t Scrolle_speed[4] = {0, 2, 4, 6}; //文字列スクロールインターバル時間
uint32_t scl_LastTime[4] = {0, 0, 0, 0};
uint8_t Fnt_buf[4][2][16]; //フォント格納
uint16_t sj_length[4] = {0, 0, 0, 0}; //Shift_JISコードの長さ
uint8_t scl_cnt[4] = {0, 0, 0, 0}; //フォントのスクロールカウント数(ドット単位)
uint16_t SJ_cnt[4] = {0, 0, 0, 0}; //Shift_JISコードカウント
bool fnt_read_ok[4] = {true, true, true, true}; //フォントを読み込むか否かのフラグ
uint8_t ZorH[4] = {0, 0, 0, 0}; //全角ならば 2 , 半角ならば 1 を格納
uint8_t dummy_cnt[4] = {0, 0, 0, 0}; //全角ならば次のフォントを読み込むかどうかのカウント

void setup() {
  Serial.begin(115200);
  ssd1331.SSD1331_Init(); //OLED SSD1331 初期化

  //※この関数を使う場合はStrDirect_ShinoFNT_readALL関数を使う場合限定。
  //3つのファイルを同時に開くため、後でクローズすることが必要。
  SFR.SD_Shinonome_Init3F(UTF8SJIS_file, Shino_Half_Font_file, Shino_Zen_Font_file);

  uint8_t font_buf[12][16];
  SFR.StrDirect_ShinoFNT_readALL("16x16 日本語", font_buf); //String 文字列から一気にフォント変換
  ssd1331.SSD1331_8x16_Font_DisplayOut(12, 0, 16, 7, 7, 3, font_buf); //OLED SSD1331 へ出力
  SFR.SD_Shinonome_Close3F(); //StrDirect_ShinoFNT_readALL関数を使う場合、必ず閉じておく
  delay(2000);
  
  SFR.SD_Shinonome_Init2F(Shino_Half_Font_file, Shino_Zen_Font_file); //ライブラリ初期化。2ファイル同時に開く
  u8ts.ESP32_SD_UTF8toSJIS_Init(UTF8SJIS_file); //ライブラリ初期化

  String str1 = "やっとESP32で日本語フォント表示ができたよ~ん!!!123456789";
  String str2 = "●■▲×→⇔↑⇒↓←※ぁぃぅぇぉゃゅょャュョァィゥェォ";
  String str3 = "アカサタナハマヤラワンァィゥェォャュョabcdefghijklmnアイウエオカキクケコ";
  String str4 = "JIS第2水準-弌鯖鰺鰯鰤齋堯槇遙凜熙¥abcdefgxyz ";
  
  sj_length[0] = u8ts.UTF8_to_SJIS(str1, sj_txt[0]); //String 文字列をSift_JISコードに変換
  sj_length[1] = u8ts.UTF8_to_SJIS(str2, sj_txt[1]);
  sj_length[2] = u8ts.UTF8_to_SJIS(str3, sj_txt[2]);
  sj_length[3] = u8ts.UTF8_to_SJIS(str4, sj_txt[3]);

  delay(10);
  
  for(int i=0; i<4; i++){
    scl_LastTime[i] = millis();
  }
}

void loop() {
  font_scroll(0, 0, 7, 7, 3);
  font_scroll(1, 16, 0, 0, 3);
  font_scroll(2, 32, 0, 7, 0);
  font_scroll(3, 48, 7, 0, 0);
}

void font_scroll(uint8_t num, uint8_t y0, uint8_t red, uint8_t green, uint8_t blue){
  if(millis() - scl_LastTime[num] > Scrolle_speed[num]){
    if(fnt_read_ok[num] == true){
      //フォントを読み込んだら、SJ_cnt を1つ進める
      ZorH[num] = SFR.Sjis_inc_FntRead(sj_txt[num], sj_length[num], &SJ_cnt[num], Fnt_buf[num]);
    }
    //半角の場合、scl_cntが 8 になったら次のフォントを読み込む。全角の場合は16までスクロールする
    fnt_read_ok[num] = ssd1331.Scroller_8x16_RtoL(y0, ZorH[num], Fnt_buf[num][dummy_cnt[num]], &scl_cnt[num], &dummy_cnt[num], red, green, blue);
    scl_LastTime[num] = millis();
  }
}

変数をすべて配列にして、4行同時スクロールに挑戦です。
では、これをコンパイル書き込み実行してみてください。

ブラウザからスケッチをコピーしたら、必ず一旦保存してください。そうしないと正しく表示されませんので要注意!!

ESP8266 の時には、2行以上スクロールさせると遅くて使い物にならなかったのですが、ESP32 と SSD1331 のグラフィックアクセラレーションコマンドのおかげで、4行同時でも文句ない速さでスクロールしてくれました。
以下の動画をご覧ください。

いかがでしょうか。
今までのESP8266 のプログラムでは4行同時スクロールなどは、とても無理だったのですが、ここまで速くスクロールしてくれました。
OLED SSD1331 の SPI クロックは 150ns と遅い方なのに、これだけ速いというのは驚きです。
ESP32 の計算速度が速いということもありますが、一番影響が大きいのは、SSD1331 のグラフィックアクセラレーションコマンドだと思います。

これが出来て何がスゴイのかというと、WEBから取得した記事のテキストを4行同時スクロールできるということです。
つまり、この小さいディスプレイで、4つの記事を同時に読むことができるのです。
これは画期的ですね。
ツイートを表示させることも可能かと思います。

では、4つ同じ速度だと見た目的に面白くないので、ちょっと時間差をつけてみます。
26行目を以下のように変えてみて下さい。

uint16_t Scrolle_speed[4] = {0, 2, 4, 6};

そしてコンパイル実行してみると、こんな感じになります。

いかがでしょうか。
見た目にオモシロイですね。
ただ、一番上の行は速度がアップして、速すぎて読めないですが・・・。

まとめ

以上、ESP32 – DevKitC ( ESP-WROOM-32 開発ボード ) と OLED ( 有機EL ) SSD1331 を使った、日本語漢字フォントの表示についてでした。

東雲フォントというのは、アマチュア電子工作家の私にとって、とても素晴らしいフォントだと思います。
開発された古川泰之さんや /efont/ の皆さまには敬意を表したいです。
ありがとうございました。
m(_ _)m

そして、ESP8266 ( ESP-WROOM-02 )のときには出来なかった4行同時スクロールが問題なく出来るようになって、改めて ESP32 のポテンシャルの凄さや、安いながらもSSD1331 の素晴らしさを実感しています。

では、次回は今までやってきた、NTP時計や WEB 天気予報、Yahoo ニュースをひとまとめにして表示させてみたいと思います。

ではまた・・・。

コメント

  1. juchang より:

    mgo-tec 様

    「ESP32 で 日本語漢字フォント をカラー OLED に表示させ、4行同時スクロール」に挑戦していますが、「文字列表示サンプルスケッチ」のところでトラブっています。
    入力後、コンパイルをかけるとしばらくは動作するのですが、
    exit status-1
    ボード ESP32 Dev Module に対するコンパイル時にエラーが発生しました。
    とのメッセージとなってしまいます。
    「( ESP8266 )用 Arduino IDF ライブラリを作ってみました」、「関数1行で UTF-8 文字列を フリーの日本語漢字( 東雲 ) フォントに変換できるようにしてみました」ほか、色々調べてみましたが解決策が見出せません。
    SPIFFS メモリを大きくして、micro SDHC カードを使わない方法もあるとのことで、それにも挑戦してみたのですが、同様に、コンパイル時エラーとなってしまいます。
    何か解決のアドバイスをいただけると幸いです。

    • mgo-tec mgo-tec より:

      juchangさん

      毎度お試しいただき、ありがとうございます。

      まず、お伺いしたいのは、exit status 1 の前に何かエラーメッセージが出ていませんか?
      出ていなければ、Arduino IDEのファイルメニューの環境設定のコンパイラの警告表示を「全て」にして、コンパイルし直してみてください。

      エラーメッセージを解読しないと、私も全く分かりません。

      因みに、ネットでエラーメッセージを検索すると、解決策がでている場合が多いですよ。

  2. juchang より:

    mgo-tec 様

    大変お手数をお掛け致します。

    警告表示を「全て」にしてエラーメッセージを確認しました。
    「SPI.h」、「SD.h」、「FS.h」に対し複数のライブラリがあることが原因の一つと判明したので、ファイルを削除し改めてコンパイルし直したところ、その部分のエラーメッセージは消えました。
    残っているエラーメッセージは下記のとおりです。
    Archiving built core (caching) in: C:\Users\Sadao\AppData\Local\Temp\arduino_cache_202978\core\core_espressif_esp32_esp32_FlashMode_qio,FlashFreq_80,FlashSize_4M,UploadSpeed_921600,DebugLevel_none_d7731e9bf27ea9782339ebd79c5efa1f.a
    Traceback (most recent call last):

    File “gen_esp32part.py”, line 386, in

    File “gen_esp32part.py”, line 355, in main

    UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xef in position 0: ordinal not in range(128)

    Failed to execute script gen_esp32part

    解読を試みたのですが難しくてわかりません。
    ご助言の程お願いいたします。

    • mgo-tec mgo-tec より:

      juchangさん

      spi.h SD.h FS.h は大切なファイルです。
      削除してしまうと、ますます動かなくなってしまいます。
      それを削除する前のエラーメッセージを解読しなければなりません。
      それを教えて下さい。

  3. juchang より:

    mgo-tec 様

    削除前のエラーメッセージは、
    「SPI.h」に対して複数のライブラリが見つかりました
    使用済:C:\Users\Sadao\Documents\Arduino\libraries\SPI
    未使用:C:\Users\Sadao\Documents\Arduino\hardware\espressif\esp32\libraries\SPI
    となっていました。
    「SD.h」では、使用済と未使用が逆となっていたので、どちらも有効と思い、
    C:\Users\Sadao\Documents\Arduino\hardware\espressif\esp32\libraries\””
    を残し、片方を削除しました。
    その後、コンパイルし直したところこの部分のエラーメッセージが出なくなりました。
    取り急ぎ現状までの報告です。
    これから、mgo-tec さんのアドバイス通りネットで検索してみます。

    • mgo-tec mgo-tec より:

      複数のライブラリが見つかりましたというメッセージは実は直接関係ありません。
      他のエラーが原因です。
      例えば、必要なライブラリがインストールされていなかったとか、Timeライブラリが無いとかです。

      これより前のコンパイラメッセージは何かありませんでしたか?

  4. juchang より:

    mgo-tec 様

    エラーメッセージが解消しました!

    ネットで検索をしたところ、「str 型と unicode 型を混ぜるな」という記事があり、昨日、「SPIFFS メモリサイズを大きくする作業」をしたことを思い出しました。
    とりあえずこの作業は不要と思い、Arduino core for the ESP32 を再インストールし直したところ、エラーメッセージが消えました。
    その後、コンパイル実行をしたら画面に表示はされたのですが、画面左半分だけの表示となります。
    これからこの問題に取り組んでいきたいと思います。
    以上、これまでの経過を報告いたします。

    • mgo-tec mgo-tec より:

      そうなんですね。
      とりあえず、エラーが消えて良かったですね。
      基本的には、SPIFFSサイズを大きくしても、正しく手順を踏んでいれば問題なく動きます。
      ただ、esp8266の方はメモリサイズが2GBのものが流通していたりして、大きくすると問題が生じてしまいます。
      ESP32ならば、今のところ問題なく動いています。

      近々、ESP32用のトラブルシューティング記事を書こうと思っていますので、今回の件は私なりにも再検証したいとおもいます。
      いろいろ情報ありがとうございました。

  5. juchang より:

    mgo-tec 様

    本ページの画面表示に成功しました!

    画面半分表示の状態で、シリアルモニタを見たところ、
    UTF8toSjis file has not been up load to the flash in SD file system
    Shinonome file has not been up load to the flash in SD file system
    となっていました。
    SD カードスロット・ピッチ変換基板へのピンヘッダのはんだ付けがよくなっかたようで、はんだ付けをし直したところきれいに表示されました。
    休日にもかかわらず拙問にお付き合いをいただきありがとうございました。
    今後ともご指導の程よろしくお願い致します。

    • mgo-tec mgo-tec より:

      juchangさん

      それは良かった!!
      そういうことだったんですね。
      SDカードからファイルと読み取れない場合も、コンパイラ警告メッセージで、SPI.h や FS.h が重複しているという文が出ますね。
      私も最初は意味わかりませんでしたが、その前のメッセージが重要で、それを読み解くと大体解決できます。
      ですからライブラリ重複メッセージは、その前の段階のエラーが影響してそういうメッセージが出るという事です。
      ビギナーの方々には分かりづらいと思います。

      でも、良かったですね。
      私もホッとしました。

      私も何かと忙しく、すぐにお答えできない場合も多々ありますが、当ブログ記事による不具合にはできるだけ対応していきたいとは思っております。
      こちらこそ、今後ともよろしくお願いいたします。

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