フルカラー有機EL ( OLED ) に倍角日本語フォントを縦横でスクロールさせてみた ( ESP32 , SSD1331 使用)

記事公開日:2018年1月3日
最終修正日:2018年1月9日

スポンサーリンク

ESP32_SSD1331ライブラリをv1.7 にアップデートしました。
横長文字の縦スクロールができるようになり、白黒反転文字スクロールができるようになりました。
詳細はこの記事の最後の方を参照してください。

縦方向スクロールの場合、全角のみ対応です。
どうしても半角を表示させたい場合、半角1文字の場合は半角スペースを挿入して半角2文字にするなどしてみてください。
(2018/1/9)

新年
明けまして、おめでとうございます。
本年もどうぞ、よろしくお願いいたします。

ついに、新年を迎えてしまいました。

ところで、Twitter で新年ツイートをしたら、その画像に思いのほか多くの「リツイート」や「いいね」を頂戴しました。
それはこんな画像です。

ESP32_Spiffs_SSD1331_SizeUp01

これは、8×8 pixel の美咲フォントと、16×16 pixelの東雲フォントで表示させたものです。
「賀正」を2倍角に表示させました。

大したことはやっていないのに、こんなに多く「いいね」を頂けるとは思っていなかったので、なんか嬉しくなっちゃいますね。
みなさん、ありがとうございました。
m(_ _)m

さて、本題に戻りまして、新年一発面の記事は、16×16 pixel のフリーの日本語フォント、東雲フォントを2~4倍角でフルカラー有機EL ( OLED )に表示させて、スクロールさせてみました。

前回の記事では、I2C OLED SSD1306 で表示させてみましたが、モノクロ表示ということと、スクロールスピードは遅く、文字表示の自由度はイマイチでした。

そこで、OLED SSD1331 でプログラムを組んでみたら、かなり自由度が高いことに気付いたんです。
いろいろ試行錯誤しているうちに、縦長文字や横長文字も比較的簡単にできて、縦方向スクロールも比較的簡単でした。
そして、今回は高速のSPI通信で、しかもフルカラーです。

ということで、早速、以下の動画をご覧ください。

そして、2018/1/4 に ESP32_SSD1331ライブラリを beta ver 1.7 にアップデートし、以下の動画のように横長文字の縦スクロールができるようになり、白黒反転文字スクロールができるようになりました。
この動画のソースコードはこの記事の最後の方に追加しました。
(2018/1/4)

いかがでしょうか?

使い方によっては、フリーマーケットやコミケ、展示会などのデスクに置いておけば、値札表示に使えるし、意外とインパクトあるかもしれませんね。

スクロール速度はかなり落としています。
前回の記事くらいに速度を落とすとスムースに見えます。
疑似的にキャッシュっぽいことをやっていますが、それでもまだスクロールがぎこちないです。
SPIFFSファイルシステムだと、読み取り速度が遅いので、なかなか難しいです。
今の自分の頭ではここまでが限界です。
microSDカードにすればもっとスムースになりますので、いつか作ってみようと思っています。

OLED SSD1331 はハードウェアのグラフィックアクセラレーションコマンドが充実しているので、動画にあるような、文字の縦長表示や縦方向スクロールが比較的簡単に構築できます。
そして、SSD1306と違って pixel毎に位置を決められるので、文字配置や表示範囲の自由度が高く、ディスプレイとしてはとても良いデバイスですね。

ということで、これの作り方を説明します。

なお、以下のソースコードやライブラリは素人の自作ですので、動作保証はしません。

準備するもの

OLED SSD1331 SPI モジュール

SPI通信の物を使用してください。
Amazon.co.jp では以下の販売店にあります。
中国販売店ですので、到着に10~2週間くらいかかります。

あとは、ちょっと割高になりますが、Pmod というモジュールで秋月電子通商さんで手に入ります。

Pmod OLEDrgb Pmod96×64有機ELディスプレイ

ESP-WROOM-32 ( ESP32 )開発ボード

今回はスイッチサイエンスさんの ESPr Developer 32 を使用しました。
ESP-WROOM-32 ( ESP32 )の電源周りの保護機能が充実していて、USBシリアルデバイスは FTDI製を使用している、おすすめボードです。
以前は Amazon で販売していましたが、今はスイッチサイエンスウェブショップだけの販売のようです。
Amazon.co.jp で販売再開したようです。

ピンヘッダは別売りでハンダ付けが必要なのでご注意ください。

もちろん、スイッチサイエンスウェブショップでも販売しています。

ESPr® Developer 32

その他、Espressif System純正の ESP32-DevKitC でもOKです。
Amazon では現在は販売されていないようなので、秋月電子通商さんか、マルツパーツさんで入手できます。

その他、ピンヘッダ、ブレッドボード、ジャンパーワイヤー等

ESPr Developer 32、SSD1331ボードの組み立て

スイッチサイエンスさんの ESPr Developer 32 を使う場合は、以下の記事を参照してピンヘッダなどをハンダ付けして組み立ててください。

ESPr Developer 32 ( スイッチサイエンス製 ) を使ってみました

そして、ESPr Developer 32 に SSD1331 モジュールをマウントする工作方法は以下の記事を参照してください。

ESP-WROOM-32 ( ESP32 )の SPIFFS を使って、日本語漢字 美咲フォント を読み込む

モジュールをマウントしなくても、以下に紹介するようにブレッドボード上で接続してもOKです。

接続する

ESPr Developer 32 とブレッドボード上でジャンパーワイヤーで接続する場合はこんな感じです。

ESP32_Spiffs_SSD1331_SizeUp02

Pmod OLEDrgb と接続する場合はこんな感じになります。

ESP32_Spiffs_SSD1331_SizeUp03

ESP32-DevKitC の場合もピン番号は以下の様な感じです。

ESP32_Spiffs_SSD1331_SizeUp04

Arduino core for ESP32、SPIFFSファイルアップローダー、SPIFFS領域拡大、フォントダウンロードを予め済ませておく

事前に以下の記事を参照して、設定を済ませておいてください。

●Arduino core for the ESP32 の設定
Arduino core for the ESP32 のインストール方法

●ESP-WROOM-32 ( ESP32 ) SPIFFSアップローダープラグインのインストール
ESP-WROOM-32 ( ESP32 ) SPIFFS アップローダープラグインの使い方

●ESP-WROOM-32 の SPIFFSメモリサイズ拡大
ESP-WROOM-32 ( ESP32 ) SPIFFS メモリサイズを大きくする方法

●全角東雲フォント、半角東雲フォント、 UTFtoSJISテーブルファイルのダウンロード
Arduino – ESP32 で、3つの SPI 通信 OLED ディスプレイ に Twitter Trend データを 表示させてみた

自作ライブラリのダウンロード

私の自作したライブラリを Arduino IDE にインストールしておいてください。
因みに、素人コードなので、無保証です。

バージョンアップしたものもあるので、古いライブラリはフォルダごと削除してからインストールしてください

GitHub からZIPファイルをダウンロードして、Arduino IDE にインストールしてください。
インストール方法は以下の記事を参照してください。

GitHubにある ZIP形式ライブラリ のインストール方法

ESP32_SSD1331 Beta ver 1.7

新年になって新たにBeta ver 1.6 にバージョンアップしました。
更に 1.7 にバージョンアップしました。(2018/1/4)
16×16 pixel フォントをサイズアップして表示する関数を追加しています。
横長文字の縦スクロールができるようになりました。
そして、白黒反転文字スクロールができるようになりました。

リンクは以下です。

https://github.com/mgo-tec/ESP32_SSD1331

ESP32_SPIFFS_ShinonomeFNT Beta ver 1.2

新年になって新たに Beta ver 1.2 にバージョンアップしました。
文字列を6列まで表示できるように最大サイズを変更しました。
リンクは以下です。

https://github.com/mgo-tec/ESP32_SPIFFS_ShinonomeFNT

ESP32_SPIFFS_UTF8toSJIS Beta ver 1.1

Beta ver 1.1 を使用してください。
リンクは以下です。

https://github.com/mgo-tec/ESP32_SPIFFS_UTF8toSJIS

スケッチの入力

では、以下のサンプルスケッチを入力してみてください。

縦方向スクロールの場合、全角のみ対応です。
どうしても半角を表示させたい場合、半角1文字の場合は半角スペースを挿入して半角2文字にするなどしてみてください。

#include "ESP32_SSD1331.h" //Beta ver 1.6
#include "ESP32_SPIFFS_ShinonomeFNT.h" //Beta ver 1.2
#include "ESP32_SPIFFS_UTF8toSJIS.h" //Beta ver 1.1

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

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 DC_OLED =  21; //OLED DC(Data/Command)
const uint8_t RST_OLED =  4; //OLED Reset
const uint8_t CS1_OLED = 15; //CS (Chip Select ピン)

ESP32_SSD1331 ssd1331(SCLK_OLED, MISO_OLED, MOSI_OLED, CS1_OLED, DC_OLED, RST_OLED);
ESP32_SPIFFS_ShinonomeFNT SFR;

//※文字列の最大数は6
enum { Display_Max_num = 6, MaxTxtByte = 100 ,cash = 2};

uint8_t sj_txt[Display_Max_num][MaxTxtByte] = {0}; //Shift_JISコード格納
uint16_t sj_length[Display_Max_num] = {0}; //Shift_JISコードの長さ
uint16_t sj_cnt[Display_Max_num] = {0}; //Shift_JISコード半角文字数カウント
uint8_t disp_buf[Display_Max_num][16][16] = {0}; //ディスプレイに表示させるフォントバッファ
boolean fnt_read_ok[Display_Max_num] = {true, true, true, true};
boolean FontReakOK[Display_Max_num] = {false, false, false, false};
uint8_t Zen_or_Han[cash][Display_Max_num] = {0}; //全角半角判断数値

//疑似キャッシュフォント定義-------------------------------------
uint8_t cash_font_cnt[Display_Max_num] = {0}; //キャッシュフォント数カウント
uint8_t cash_font_read_cnt[Display_Max_num] = {0}; //キャッスフォント読み込みカウント
uint8_t CashFont[cash][Display_Max_num][2][16] = {0}; //キャッシュに格納するフォント
//-------------------------------------------------------------

uint32_t SclTime1 = 0;
uint8_t H_Size, V_Size; //水平サイズ:H_Size(1,2,4)  垂直サイズ:V_Size(1,2,4)
uint8_t X0, X1, Y0, Y1; //ディスプレイ表示座標位置
uint8_t red, green, blue; //256color, Max red=7, green=7, blue=3

void setup() {
  Serial.begin(115200);
  ssd1331.SSD1331_Init();
  ssd1331.Display_Clear(0, 0, 95, 63);
  //3つのSPIFFSファイルを同時オープン
  SFR.SPIFFS_Shinonome_Init3F(UTF8SJIS_file, Shino_Half_Font_file, Shino_Zen_Font_file); //ライブラリ初期化。2ファイル同時に開く
  Serial.println();

  String test_str[4];
  uint8_t test_buf[4][16][16] = {0};
  uint16_t test_sj_length[4];

  //16x16 東雲フォント 等倍表示
  test_str[0] = "2018年";
  X0 = 24; Y0 = 24; red = 7; green = 7; blue = 3;
  test_sj_length[0] = SFR.StrDirect_ShinoFNT_readALL(test_str[0], test_buf[0]);
  ssd1331.SSD1331_8x16_Font_DisplayOut(test_sj_length[0], X0, Y0, red, green, blue, test_buf[0]);
  delay(1500);
  ssd1331.Display_Clear(0, 0, 95, 63);

  //16x16 東雲フォント 縦長2倍角表示
  test_str[1] = "平成30年";
  H_Size = 1; V_Size = 2; X0 = 14; Y0 = 16; red = 7; green = 7; blue = 3;
  test_sj_length[1] = SFR.StrDirect_ShinoFNT_readALL(test_str[1], test_buf[1]);
  ssd1331.HVsizeUp_8x16_Font_DisplayOut(H_Size, V_Size, test_sj_length[1], X0, Y0, red, green, blue, test_buf[1]);
  delay(1500);
  ssd1331.Display_Clear(0, 0, 95, 63);

  //16x16 東雲フォント 縦長4倍角表示
  test_str[2] = "あけまして!";
  H_Size = 1; V_Size = 4; X0 = 0; Y0 = 0; red = 0; green = 7; blue = 0;
  test_sj_length[2] = SFR.StrDirect_ShinoFNT_readALL(test_str[2], test_buf[2]);
  ssd1331.HVsizeUp_8x16_Font_DisplayOut(H_Size, V_Size, test_sj_length[2], X0, Y0, red, green, blue, test_buf[2]);

  delay(1500);
  ssd1331.Display_Clear(0, 0, 95, 63);

  test_str[3] = "おめでとう!";
  H_Size = 1; V_Size = 4; X0 = 0; Y0 = 0; red = 7; green = 0; blue = 0;
  test_sj_length[3] = SFR.StrDirect_ShinoFNT_readALL(test_str[3], test_buf[3]);
  ssd1331.HVsizeUp_8x16_Font_DisplayOut(H_Size, V_Size, test_sj_length[3], X0, Y0, red, green, blue, test_buf[3]);

  delay(2000);
  ssd1331.Display_Clear(0, 0, 95, 63);

  //キャッシュバイトを使う場合、文字の最後に全角スペース適当に入れておけば、文字スクロール終了を検出する時に全てをスクロールし切ることができる
  //4倍角ならスペース5つ入力
  sj_length[0] = SFR.UTF8toSJIS_convert("★★★★★★A Happy New Year!  ", sj_txt[0]);
  sj_length[1] = SFR.UTF8toSJIS_convert("★謹賀新年", sj_txt[1]);
  sj_length[2] = SFR.UTF8toSJIS_convert("★★★★★★平成30年", sj_txt[2]);
  sj_length[3] = SFR.UTF8toSJIS_convert("★★★★★★2018年", sj_txt[3]);
  sj_length[4] = SFR.UTF8toSJIS_convert("★★★★★★皆さまにとって良い年でありますように!", sj_txt[4]);
  sj_length[5] = SFR.UTF8toSJIS_convert("スクロールがぎこちないですが、ご容赦ください!     ", sj_txt[5]);

  //マルチタスクでスムースにスクロールするための、キャッシュバイト2バイト事前読み込み
  for(int j=0; j<cash; j++){
    for(int str_number=0; str_number<Display_Max_num; str_number++){
      //Zen_or_Han[j][str_number] = SFR.Sjis_inc_FntRead_Rot(&sj_cnt[str_number], -90, 0, str_number, sj_txt[str_number], sj_length[str_number], CashFont[j][str_number]);
      Zen_or_Han[j][str_number] = SFR.Sjis_inc_FntRead(&sj_cnt[str_number], str_number, sj_txt[str_number], sj_length[str_number], CashFont[j][str_number]);
    }
  }

  TaskHandle_t th; //ESP32 マルチタスク ハンドル定義
  xTaskCreatePinnedToCore(Task1, "Task1", 4096, NULL, 5, &th, 0); //マルチタスク core 0 実行

  SclTime1 = millis();
}
//************** メインループ *******************
void loop() {
  int str_number;
  //1文字スクロールしたらフォントを読み込む
  for(str_number=0; str_number<Display_Max_num; str_number++){
    if(FontReakOK[str_number] == true) {
      Zen_or_Han[ cash_font_read_cnt[str_number] ][str_number] = SFR.Sjis_inc_FntRead(&sj_cnt[str_number], str_number, sj_txt[str_number], sj_length[str_number], CashFont[ cash_font_read_cnt[str_number] ][str_number]);
      cash_font_read_cnt[str_number]++;
      if(cash_font_read_cnt[str_number] >= cash) cash_font_read_cnt[str_number] = 0;
      FontReakOK[str_number] = false;
    }
  }
}
//************* マルチタスク **********************
void Task1(void *pvParameters){
  int str_number;
  while(1){
    if(millis() - SclTime1 > 10){ //スクロールインターバル 10ms
      if( sj_cnt[5] < (sj_length[5] - 2) ){ //スクロール終了検出はsj_lengthから全角2バイト分引く
        str_number=5;
        H_Size = 4; Y0 = 0; red = 7; green = 7; blue = 3;
        if(ssd1331.SizeUp_Scroller_8x16_RtoL(H_Size, Y0, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }
      }else{
        str_number=0;
        H_Size = 1; V_Size = 1; X0 = 0; X1 = 95; Y0 = 0; red = 7; green = 2; blue = 3;
        if(ssd1331.HVsizeUp_Scroller_8x16_RtoL(H_Size, V_Size, X0, X1, Y0, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }

        str_number=1;
        H_Size = 2; V_Size = 2; X0 = 16; X1 = 79; Y0 = 16; red = 7; green = 7; blue = 0;
        if(ssd1331.HVsizeUp_Scroller_8x16_RtoL(H_Size, V_Size, X0, X1, Y0, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }

        str_number=2;
        uint8_t Direction = 0; //縦方向スクロール 0:↑ 1:↓
        H_Size = 1; V_Size = 3; X0 = 0; Y0 = 16; Y1 = 63; red = 7; green = 0; blue = 0;
        if(ssd1331.HVsizeUp_Vscroller_16x16(H_Size, V_Size, Direction, X0, Y0, Y1, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }

        str_number=3;
        Direction = 1; //縦方向スクロール 0:↑ 1:↓
        H_Size = 1; V_Size = 3; X0 = 80; Y0 = 16; Y1 = 63; red = 0; green = 7; blue = 0;
        if(ssd1331.HVsizeUp_Vscroller_16x16(H_Size, V_Size, Direction, X0, Y0, Y1, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }

        str_number=4;
        H_Size = 1; V_Size = 1; X0 = 16; X1 = 79; Y0 = 48; red = 0; green = 7; blue = 3;
        if(ssd1331.HVsizeUp_Scroller_8x16_RtoL(H_Size, V_Size, X0, X1, Y0, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }
      }
      SclTime1 = millis();
    }
    delay(1);//マルチタスクのwhileループでは必ず必要
  }
}

【解説】

●1-3行目:
私の自作ライブラリのインストールです。
3行目の ESP32_SPIFFS_UTF8toSJIS はESP32_SPIFFS_ShinonomeFNTライブラリ内でインクルードされていますが、ここではライブラリのインストールを忘れない為に明示的にインクルードさせています。

●5-7行目:
SPIFFSファイルシステムでアップロードさせたフォントファイルとUTF8toSJIS変換テーブルファイルを定義しています。

●9-14行:
OLED SSD1331 と SPIインターフェースで接続する GPIOピン番号の定義です。

●16-17行:
自作ライブラリのクラス名定義です。

●20行:
ディスプレイに表示させる文字列は最大6列です。
それ以上にするとエラーになります。
MaxTxtByte はメモリの許す限り大きくできます。
cash 数は大きくしても意味ありません。

●31-33行:
疑似的にキャッシュっぽいことをやるための配列定義です。
各文字列毎に全角1文字分(半角2文字分)をSRAMの配列に格納しておき、半角1文字スクロールしている間に次の1文字をSPIFFSから読み込むためのものです。

●39行:
OLED SSD1331 では、今回は256色カラーにしています。
赤色は0~7、緑色は0~7、青色は0~3で設定します。
RGBを混ぜて色を作ります。

●46行:
ここで、SPIFFSファイルシステムで、3つのファイルを同時に開いておきます。

●54-84行:
ここでは、テスト用として、固定文字列を表示させています。
文字サイズの数値は、水平方向、垂直方向とも 0 , 2 , 4 のうちのいずれかを代入します。
横方向 0~96 pixel
縦方向 0~63 pixel
なので、サイズを大きくした場合に、その数値からはみ出ないように文字数やサイズを設定してください。
これを超えると、恐らくまともに動きません。

●88-93行:
ここで、String型UTF-8文字列を Shift_JISコードに変換します。
最大6列まで定義できます。
最後の文字列は、スクロール終了を検知の時に文字列を全部スクロールし切るために、文字列の最後の方に4倍角用のスペース5つを入力しています。

●96-101行:
ここで、各文字列の全角1文字を予めキャッシュ配列に読み込んでおきます。

●103-104行:
ESP32 のデュアルコアCPUを使うマルチタスク関数です。
メインループが Core 1 で、122行目以降のタスクが Core 0 です。
ESP32 のマルチタスクについては以下の記事を参照してください。

Arduino – ESP32 のマルチタスク ( Dual Core ) を試す

●112-119行:
CPU Core 1 のメインループです。
半角1文字スクロールしている間にフォントを読み込んでいます。
114行目の関数で、フォントを読み込んだ後、文字カウントを自動的に1増加させます。

●122-181行:
CPU Core 0 のマルチタスクループです。
125行目でスクロールスピードを設定していて、10ms インターバルを置いています。
この数値を少なくするほどスクロールは速くなりますが、SPIFFS のフォント読み込みが間に合わなくなりますので、あまり速くしない方が良いでしょう。

●126-133行:
フォントを縦横4倍角にして、文字をスクロールさせ、スクロールが全て完了し切ったら次の処理に移ります。
キャッシュフォントを設定しているため、126行では半角2文字分を引いて設定しないと、文字スクロール終了を検知しないので注意です。
先にも述べたように、すべての文字をスクロールし切ることを検知するためには、文字列の最後に全角スペースを5つ入力しておくことが必要です。(4倍角の場合)

●135-141行:
等倍フォントの水平スクロールです。

●143-149行:
縦横2倍角の水平スクロールです。

●151-158行:
横方向1倍、縦方向3倍角文字の垂直スクロールです。
Direction を0 にすると下から上へスクロールします。
垂直スクロールの場合、必ず全角文字にしてください。

●169-175行:
等倍文字の水平スクロールですが、表示させる範囲を狭くしています。

横長、縦長サイズアップフォントの縦横スクロール

2018/1/4 に自作ライブラリ、ESP32_SSD1331 を beta ver 1.7 にアップデートして、横長文字の縦スクロールができるようになりました。
そして、白黒反転文字スクロールもできるようになりました。
そのサンプルスケッチは以下の通りです。
縦方向スクロールの場合、全角のみ対応です。
どうしても半角を表示させたい場合、半角1文字の場合は半角スペースを挿入して半角2文字にするなどしてみてください。

#include "ESP32_SSD1331.h" //Beta ver 1.7
#include "ESP32_SPIFFS_ShinonomeFNT.h" //Beta ver 1.2
#include "ESP32_SPIFFS_UTF8toSJIS.h" //Beta ver 1.1

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

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 DC_OLED =  21; //OLED DC(Data/Command)
const uint8_t RST_OLED =  4; //OLED Reset
const uint8_t CS1_OLED = 15; //CS (Chip Select ピン)

ESP32_SSD1331 ssd1331(SCLK_OLED, MISO_OLED, MOSI_OLED, CS1_OLED, DC_OLED, RST_OLED);
ESP32_SPIFFS_ShinonomeFNT SFR;

//※文字列の最大数は6
enum { Display_Max_num = 4, MaxTxtByte = 100 ,cash = 2};

uint8_t sj_txt[Display_Max_num][MaxTxtByte] = {0}; //Shift_JISコード格納
uint16_t sj_length[Display_Max_num] = {0}; //Shift_JISコードの長さ
uint16_t sj_cnt[Display_Max_num] = {0}; //Shift_JISコード半角文字数カウント
uint8_t disp_buf[Display_Max_num][16][16] = {0}; //ディスプレイに表示させるフォントバッファ
boolean fnt_read_ok[Display_Max_num] = {true, true, true, true};
boolean FontReakOK[Display_Max_num] = {false, false, false, false};
uint8_t Zen_or_Han[cash][Display_Max_num] = {0}; //全角半角判断数値

//疑似キャッシュフォント定義-------------------------------------------------
uint8_t cash_font_cnt[Display_Max_num] = {0}; //キャッシュフォント数カウント
uint8_t cash_font_read_cnt[Display_Max_num] = {0}; //キャッスフォント読み込みカウント
uint8_t CashFont[cash][Display_Max_num][2][16] = {0}; //キャッシュに格納するフォント
//-------------------------------------------------------------

uint32_t SclTime1 = 0;

void setup() {
  Serial.begin(115200);
  ssd1331.SSD1331_Init();
  ssd1331.Display_Clear(0, 0, 95, 63);
  //3つのSPIFFSファイルを同時オープン
  SFR.SPIFFS_Shinonome_Init3F(UTF8SJIS_file, Shino_Half_Font_file, Shino_Zen_Font_file); //ライブラリ初期化。2ファイル同時に開く
  Serial.println();

  //キャッシュバイトを使う場合、文字の最後に全角スペース適当に入れておけば、文字スクロール終了を検出する時に全てをスクロールし切ることができる
  //4倍角ならスペース5つ入力
  sj_length[0] = SFR.UTF8toSJIS_convert("こんなのもできますよ~ん 縦長4倍角    ", sj_txt[0]);
  sj_length[1] = SFR.UTF8toSJIS_convert("すかさず横長6倍角ですよ★    ", sj_txt[1]);
  sj_length[2] = SFR.UTF8toSJIS_convert("こんなのもできますよ~ん!白黒反転    ", sj_txt[2]);
  sj_length[3] = SFR.UTF8toSJIS_convert("そしてすかさず横長6倍角 白黒反転★       ", sj_txt[3]);

  //マルチタスクでスムースにスクロールするための、キャッシュバイト2バイト事前読み込み
  for(int j=0; j<cash; j++){
    for(int str_number=0; str_number<Display_Max_num; str_number++){
      //Zen_or_Han[j][str_number] = SFR.Sjis_inc_FntRead_Rot(&sj_cnt[str_number], -90, 0, str_number, sj_txt[str_number], sj_length[str_number], CashFont[j][str_number]);
      Zen_or_Han[j][str_number] = SFR.Sjis_inc_FntRead(&sj_cnt[str_number], str_number, sj_txt[str_number], sj_length[str_number], CashFont[j][str_number]);
    }
  }

  TaskHandle_t th; //ESP32 マルチタスク ハンドル定義
  xTaskCreatePinnedToCore(Task1, "Task1", 4096, NULL, 5, &th, 0); //マルチタスク core 0 実行

  SclTime1 = millis();
}
//************** メインループ *******************
void loop() {
  int str_number;
  //1文字スクロールしたらフォントを読み込む
  for(str_number=0; str_number<Display_Max_num; str_number++){
    if(FontReakOK[str_number] == true) {
      Zen_or_Han[ cash_font_read_cnt[str_number] ][str_number] = SFR.Sjis_inc_FntRead(&sj_cnt[str_number], str_number, sj_txt[str_number], sj_length[str_number], CashFont[ cash_font_read_cnt[str_number] ][str_number]);
      cash_font_read_cnt[str_number]++;
      if(cash_font_read_cnt[str_number] >= cash) cash_font_read_cnt[str_number] = 0;
      FontReakOK[str_number] = false;
    }
  }
}
//************* マルチタスク ****************************************
void Task1(void *pvParameters){
  uint8_t H_Size, V_Size; //水平サイズ:H_Size(1,2,4)  垂直サイズ:V_Size(1,2,4)
  uint8_t X0 = 0, X1 = 95, Y0 = 0, Y1 = 63; //ディスプレイ表示座標位置
  uint8_t red, green, blue; //256color, Max red=7, green=7, blue=3
  int str_number;
  int Direction;

  while(1){
    if(millis() - SclTime1 > 7){ //スクロールインターバル 7ms
      if( sj_cnt[0] < (sj_length[0] - 2) ){ //スクロール終了検出はsj_lengthから全角2バイト分引く
        str_number=0;
        H_Size = 1; V_Size = 4; red = 7; green = 7; blue = 3;
        if(ssd1331.HVsizeUp_Scroller_8x16_RtoL(false, H_Size, V_Size, X0, X1, Y0, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }
      }else if( sj_cnt[1] < (sj_length[1] - 2) ){
        str_number=1;
        H_Size = 6; V_Size = 1; Direction = 0; red = 7; green = 0; blue = 0;
        if(ssd1331.HVsizeUp_Vscroller_16x16(false, H_Size, V_Size, Direction, X0, Y0, Y1, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }
      }else if( sj_cnt[2] < (sj_length[2] - 2) ){
        str_number=2;
        H_Size = 2; V_Size = 4; red = 0; green = 7; blue = 0;
        if(ssd1331.HVsizeUp_Scroller_8x16_RtoL(true, H_Size, V_Size, X0, X1, Y0, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }
      }else if( sj_cnt[3] < (sj_length[3] - 2) ){
        str_number=3;
        H_Size = 6; V_Size = 2; Direction = 1; red = 7; green = 0; blue = 0;
        if(ssd1331.HVsizeUp_Vscroller_16x16(true, H_Size, V_Size, Direction, X0, Y0, Y1, str_number, Zen_or_Han[cash_font_cnt[str_number]][str_number], CashFont[cash_font_cnt[str_number]][str_number], red, green, blue)){
          cash_font_cnt[str_number]++;
          if(cash_font_cnt[str_number] >= cash) cash_font_cnt[str_number] = 0;
          FontReakOK[str_number] = true;
        }
      }else{
        sj_cnt[0] = 0;
        sj_cnt[1] = 0;
        sj_cnt[2] = 0;
        sj_cnt[3] = 0;
      }

      SclTime1 = millis();
    }
    delay(1);//マルチタスクのwhileループでは必ず必要
  }
}

これの解説は省略させていただきます。

コンパイル書き込み実行

では、Arduino IDE でコンパイル書き込み実行してみてください。
最初に紹介した動画のように表示されればOKです。

まとめ

いかがでしたでしょうか。
うまく動きましたでしょうか?

これをうまく使えばフリーマーケットやコミケ、そのほか卓上展示会などで値札や製品アピールにつかえそうですね。

まだキャッシュ機能がうまくいってなくて、スクロールがイマイチなのが次回の課題ですね。
それよりも、microSDカードを使えばスクロールもスムースになるので、それを使えば良いかもしれません。
でも、SPIFFSを使う手軽さはなかなか捨て難いものがありますので、これをなんとかうまく使いたいですね。

以上、今回はここまでです。

本年も私なりにアマチュア精神でいろいろ挑戦したいと思っております。
素人ソースコードですが、素人なりに自由な発想で作っていきたいと思います。
その分、うまく動作しないということもあるかと思います。
その場合、コメント投稿等でご連絡いただければ、できる範囲で改善していきたいと思っております。
ということで、今年の目標として、無駄なことをやることに引け目を感じず、何か有意義なものを創造することができればと思っております。

本年も何卒よろしくお願いいたします。
m(_ _)m

みなさまにとっても良い年でありますように・・・

mgo-tec電子工作 関連コンテンツ ( 広告含む )

スポンサーリンク

Amazon.co.jp 当ブログのおすすめ









投稿者:

mgo-tec

Arduino , ESP32 ( ESP-WROOM-32 ) , ESP8266 ( ESP-WROOM-02 )等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってますので、動作保証はしません。 電子回路やプログラミングの専門家ではありません。 畑違いの仕事をしていて、介護にドップリ浸かりそうな年配者です。 少しだけ電気の知識が必要な仕事なので、電気工事士や工事担任者等の資格は持っています。

「フルカラー有機EL ( OLED ) に倍角日本語フォントを縦横でスクロールさせてみた ( ESP32 , SSD1331 使用)」への12件のフィードバック

  1. はじめまして!&あけましておめでとうございます。
    おととしくらい(の頃)から、mgo-tecさんのページをいつも参考にさせてもらっています。

    KiCADを使ってオリジナルのESP32のマイコン基板を設計し、注文した回路基板が昨年の大晦日の日に届いたので、ESP32などの部品を付けて、動作確認のためにこのページのプログラムを動かしてみました。すんなりYouTubeの動画の通りに動いたので、ほっとしています。

    ちなみに、カラーOLEDはたぶん同じ仕様のものだと思いますがamazonで1050円で売っていたものを使いました。そのOLEDは現在売れ切れ中で、最初に買ったものは半田不良でちゃんと表示ができないものでしたが、今回は2回目に購入したものでちゃんと表示できてよかったです。

    と言うことで、今年もよろしくお願いいたします。

    1. あいむさん

      ブログをご覧頂き、ありがとうございます。
      ESP32とOLED SSD1331 基板ですか・・。
      それはイイですね!
      SSD1306とのボードはあっても、フルカラー小型OLEDとのボードはまだありませんからね。
      このSSD1331は自由度が高いホントに良いディスプレイですよね。

      もし、WEB公開されているのでしたら、このコメント投稿で、http://のhを外したアドレスを掲載していただければ、拝見させていただきたいです。
      無理にとは申しません。

      ということで、嬉しい投稿ありがとうございました。
      今後とも当ブログをよろしくお願い致します。
      m(_ _)m

  2. mgo-tec様

    あいむです。お返事ありがとうございます。

    >拝見させていただきたいです。
    と言うとでしたので、動作した証拠のビデオとったのでYouTubeにあげておきました。
    https://www.youtube.com/watch?v=pJUf4fPeySI
    (もう何年も自分のホームページを更新していないので、久々に更新して、このビデオも載せようと思っています。http://im-aim.com/)

    今回のこのボードは、ESP32の汎用のボードとして作りました。SPIのピンの順番は、このカラーOLEDとSDカードモジュールにして、I2Cは1色のOLED(http://akizukidenshi.com/catalog/g/gP-12031/)のピンの順番にしました。まだやってませんが、SSD1306も動くと思います。

    今後、専用のESP32のプリント基板を作ろうと思っているので、mgo-tecさんがハーフピッチ のESP32の半田付けに挑戦する気があるなら、mgo-tec用の基板もできますよ。今は、海外のプリント基板屋(https://fusionpcb.jp/login.html など)に注文したら1000円もしないでできる時代なったことだし。

    1. あいむさん

      ご無理とお手間をとらせしまって申し訳ございません。
      動画リンクを紹介していただき、誠にありがとうございます。
      会社の方だったのですね。
      アマチュアの私としては恐縮してしまいます。

      自分の作ったプログラムが他の方のボードで動作する動画は、なんか嬉しいですね。
      ちゃんと動いてくれるか心配なところもあったので・・・。

      SSD1306 に乗せ換えられる基板はスバラシイ!!
      あれだけの基板を設計できるのは羨ましいです。
      私は一旦挫折しました。
      設計する時間が無いのと、知識が乏しく、既製品ボード以上のことはとてもできないと悟ったためです。

      それと、私用の基板を作って頂くなんて、とてもとても恐れ多いです。
      そういうお声を頂戴しただけで、感謝感謝です。
      m(_ _)m
      でも、いつか、自分自身で基板設計に挑戦しようと思っておりますので、良い刺激をもらいました。
      いろいろありがとうございます。
      ESP32専用基板ができると面白そうなものになりそうですね。
      期待しております。
      がんばってください。

  3. あけましておめでとうございます。

    プログラムは全て動作しております。
    JJYの信号発生プログラムにこれを合体させ
    SHT21で温度を表示させるように改造しました。
    しかし全角半角混在では半角がうまく表示できません。
    美咲フォントバージョンを組み込んだ場合はうまく表示できました。
    MFR.StrDirect_MisakiFNT_readALL (“20″ + String(Year) + ” 年” + String(Month) + ” 月” + String(T_day) + ” 日” , font_buf);
    しかし字が小さく、この東雲バージョンで表示したく
    数値だけ変換テーブルでやったのですが、いまいちです。
    厚かましいお願いですがスマートに表示できるようなライブラリーをお願い申し上げます。

    1. マッキーさん

      以前コメント頂いた方とは違う方ですか?
      だとしたら、初めまして。
      そしてあけましておめでとうございます。
      当ブログをご覧いただき、ありがとうございます。

      今、2018/1/9 朝6:00に動かしたところ、ESP32_SSD1331ライブラリをver1.6→1.7 にバージョンアップしたのに、サンプルスケッチが誤動作していました。
      見直していますので
      、しばらくお待ちください。

    2. マッキーさん

      ESP32_SSD1331 の最新ライブラリはbeta ver 1.7 です。
      ブログ記事もそれ用のサンプルスケッチを1月7日に追記しています。

      ver1.7 では、縦方向の倍角文字スクロールが可能になりましたが、ver1.6時の解説でも記載しているとおり、縦方向スクロールは全角文字のみ対応です。
      半角文字混在は横方向スクロールのみです。
      縦方向の半角文字スクロールは、半角が2回連続で来る場合と、1回のみで終わる場合で表示が難しくなり、今は実装していません。
      全て全角に変換するか、または、半角1文字の場合は前に半角スペースを挿入して、半角文字をダブルにしてください。

      因みに、当方で以下のコードで実験してみました。
      (※抜粋です)

      uint8_t Year=18, Month=1, T_day=9;
      sj_length[0] = SFR.UTF8toSJIS_convert("20" + String(Year) + " 年" + String(Month) + " 月" + String(T_day) + " 日" + "     ", sj_txt[0]);
      -----以下省略-----
      

      こうすると、横方向スクロールは全く問題無く表示されますが、縦方向は対応していないのでうまくできません。
      そこで、半角1文字にスペースを挿入して、強制的に2文字にします。
      例えば、Arduino IDE の sprintf 関数を使います。
      これは、char型しか対応していませんので要注意です。

      uint8_t Year=18, Month=1, T_day=9;
        char Month_c[3], T_day_c[3];
        sprintf(Month_c, "%2d", Month);
        sprintf(T_day_c, "%2d", T_day);
        sj_length[0] = SFR.UTF8toSJIS_convert("20" + String(Year) + "年" + String(Month_c) + "月" + String(T_day_c) + "日" + "     ", sj_txt[0]);
      

      こうすれば、とりあえずは縦方向スクロールでもOKです。
      ただ、半角1文字は中央に配置したいと私は思っていますが、今後の課題です。

      以上、これで試してみて下さい。
      因みに、私は素人アマチュアで独学ですので、スマートなライブラリを作るには技術やスキルが足りません。
      今の私の頭ではこれが限界です。
      ご不便をおかけしますが、ご容赦くださいませ。
      m(_ _)m

    3. あと、このブログ記事では、キャッシュバイトを設定していて、マルチタスクで動作させていますが、シングルタスクで、メインループ内で動作させればかなりシンプルなスケッチになります。
      ただ、その場合、スクロールがかなりカクカクします。

  4. 早速のご返答ありがとうございました。
    コメント送信がすぐに反映されなかったので、うまく送信できなかったのかなと思い、何度もコメントしてすみませんでした。
    全て表示はできました。
    ありがとうございました。
    JJY+時刻と気温、湿度を表示させようと実験中です。
    BME280は手持ちがなかったので、代わりにSHT21を繋いでテストしましたが、コンパイルエラーは出ないのですがセンサー値を読み込むルーチンで停止します。
    やはりESP32用のライブラリーがいるようです。
    BME280は届き次第テストしてみます。
    今年もご活躍を期待しております。

    1. マッキーさん

      重複したと思われるコメントはこちらで削除させていただきましたので、何も問題ありません。
      コメント送信が直ぐ反映されず、逆にお手数おかけしました。
      このブログはちょっと動作が重く、申し訳ございません。

      SPIFFS の読み取りに関しては、私の方の課題がたくさんありますが、表示できて良かったです。
      今後改善していきたいと思っています。

      BME280 の私の自作ライブラリは殆どメンテナンスしてないので、不具合ありましたらまたコメントいただけると幸いです。
      こちらこそ、今後も当ブログをよろしくお願いいたします。
      m(_ _)m

  5. さっそくBME280のI2Cで動作させました。
    なにも問題ありません。SPIは未確認です。
    今のところ問題なく動作しています。
    SHT21のライブラリー作者のフォーラムをみるとやはりESP8266では動作するけどESP32は応答がないとか言ってます。
    この人はライセンス条項で「License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license)」とか洒落たこと言ってます。
    わたしもmgo-tecさんにビールぐらいで良かったらおごりたい気分です。

    1. マッキーさん

      動いてくれてホッとしました。
      何分、独学ですので、他の方の環境で動くかどうか自信が無いもので・・・。

      ビールライセンスは洒落てますね。
      そんな洒落たことを書ける余裕は今の私にはとてもありませんが・・・。

      私もおごられたい気分ですが、アマチュアコードですのでチョコチョコ不具合があると思います。
      今はブログをご覧いただけるだけで十分です。
      お気持ちだけ、有難く、ありがた~く頂戴いたします。
      m(_ _)m

コメントを残す

メールアドレスが公開されることはありません。

*画像の文字を入力してください。(スパム防止の為)