ESP-WROOM-02 で Wi-Fi リアルタイム制御できる日本語電光掲示板(4連LEDマトリックス版)

ESP8266 ( ESP-WROOM-02 )

こんばんは。

前回に引き続き、今回も ESP-WROOM-02 ( ESP8266 ) を使った、スマホのブラウザとWi-Fi リアルタイム制御 ( WebSocket通信 ) できる自作の日本語電光掲示板作成です。

ただし、今回は 8×8 LED マトリックスを4つ連結して、ちゃんと読める電光掲示板にしてみたいと思います。

4連にすることで、プログラムスケッチが長くなり、記事中に掲載できなくなってきたので、美咲フォント読み込みやAdafruit製LEDのI2C制御部分を独自にライブラリ化してみました。
おかげで、何とかこの記事中にスケッチを掲載できるようになりました。

本当はタイマー機能や時計機能を追加したかったのですが、スケッチが長くなり過ぎるので今回は文字のスクロール機能だけとしました。

動作の様子はこちらの動画をご覧ください。

どうでしょうか?
前回記事のLEDマトリックス1個に比べて格段に読みやすくなりましたね。
スマホ側のリアルタイムコントロールは、スピードコントロールや明るさコントロールの他に文字の回転やスクロール方向を変えられます。
しかも、今回から白黒反転文字もできるようになりました!!!
これがイイですね~・・・。


JIS13区の記号や半角カタカナもちゃんとスクロールしていますね。
上下方向や右方向ほスクロールは半角カタカナの扱いが難しいので、これで勘弁してください。
でも、縦型看板もできますので、画期的だと思います。
縦型にした場合の動画はこちらです。

やっぱり日本語は縦型がイイですね。

ちなみに、このフォントは8×8ドットの美咲フォントを使用しています。
8×8ドットといっても、読みやすくするために7×7ドットに収めて隙間を設けています。
複雑な文字は読みにくいのは仕方ありませんが、離れて見れば意外と読めると思います。
複雑な文字を使う場合は平仮名やカタカナに変えると良いです。
それにしてもこのフォントはスバラシイと個人的に思います。電子工作に重宝しています。

前回と同様、スマホから一度に送信できる文字数は全角で40文字、半角で120文字ですが、メッセージを伝えるには十分な実用レベルだと思います。
何といっても、使用する部品点数が極端に少ないというところが最高ですね。

では、これの作り方について説明していきます。

スポンサーリンク

1.準備するもの

●ESP-WROOM-02開発ボード ( スイッチサイエンス製 )

当ブログで何度も紹介しておりますが、電波の技適認証済みESP-WROOM-02 を簡単にArduino化できて、シリアル通信が簡単な超おすすめボードです。

ESP-WROOM-02開発ボード
スイッチサイエンス(Switch Science)

自分でUSBシリアル変換や5V-3.3V変換レギュレータを買ってつくっても結局同じくらいの値段になりますので、このボードを買った方が簡単だと思います。

●I2C 8×8 mini LED matrix (Adafruit製)

これも何度も紹介しておりますが、今回はこれが4個必要です。
この記事ではブルーで作っておりますが、ブルーは高価です。
赤色とか緑ならばもう少し安価です。
ブルーを4つ揃えると 8,000円 くらいかかってしまいますね。
因みに、1.2インチのものとミニのものと間違えないでください必ずミニを使ってください。
Amazonさんではスイッチサイエンスさん販売かマルツさん販売が良いと思います。

Adafruit ミニLEDマトリックス基板(青色) 【959】
エイダフルート(Adafruit)
¥2,612(2024/03/19 11:20時点)

黄色は手ごろな値段ですね。
Adafruit ミニLEDマトリックス基板(黄色) 【871】
エイダフルート(Adafruit)
¥2,128(2024/03/19 14:10時点)

●ブレットボード、ジャンパーワイヤー、最新スマホ、ブラウザ、パソコン等

スマホは最新の高速CPUのものを使ってください。
WebSocketについてはAndroidが推奨です。
ブラウザは最新バージョンの Google Chrome が推奨です。

2.Arduino IDE やESP-WROOM-02を設定する

ESPr Developer ( ESP-WROOM-02 開発ボード )の組み立てや使い方はこちらの記事を参照してください。

そして、前回の記事の 3~9までの設定を予め済ませておいてください。

3.新たに2つの独自ライブラリを追加

新たに私が独自に作ったライブラリを2つ追加します。

①I2C_Adafruit_8x8_LEDmatrix_library のダウンロード

GitHub の こちらのページ からI2C通信のAdafruit社製 8×8 LEDマトリックスライブラリをダウンロードしてください。
ページを開くと下図のようになります。


ZIPファイルを解凍し、Arduino IDE のlibraries フォルダにフォルダごとコピーしておきます。
I2C_Adafruit_8x8_LEDmatrix_library-master
という親フォルダの中に同じ名前の子フォルダがあると思います。
その子フォルダをArduino IDE の librariesフォルダにコピーします。
親フォルダをコピーしてもインクルードされませんので注意してください。

②MisakiFNT_read_for_ESP8266 ライブラリのダウンロード

同じように、GitHubの こちらのページ から美咲フォントを読み込むためのESP8266専用ライブラリをダウンロードします。
ページを開くと下図のようになります。

ZIPファイルを解凍すると同じように
MisakiFNT_read_for_ESP8266-master
という親フォルダの中に同じ名前の子フォルダがあると思います。
その子フォルダをArduino IDE の librariesフォルダにコピーします。
親フォルダをコピーしてもインクルードされませんので注意してください。

コピーし終わったら、Arduino IDEを再起動します。

ライブラリがインストールされると下図のように追加されていると思います。

これをクリックすると
#include <MisakiFNT_read.h>
#include <I2C_Adafruit_8x8_LED_matrix.h>
と表示されればインストールOKです。
もし、何も表示されなければ、親フォルダをコピーしてしまっているかもしれませんので、子フォルダをコピーし直してIDEを再起動してください。

4.LED マトリックスを組み立て、I2Cアドレスを設定する

Adafruit I2C 8×8 ミニLEDマトリックス基板の組み立て方法はこちらの記事を参照してください。

ピンヘッダまでハンダ付けできたら、下図のようにA0 と A1 をハンダを盛ってハンダショートしてください。
そうすると LED ドライバの HT16K33 のI2C通信アドレスが設定できます。

アドレスは0x70~0x73 の4種類しか設定できません。
HT16K33 に詳しい方はこの使い方はもったいないと思うでしょうね。

そもそもHT16K33 はLEDマトリックスを2つ制御できるのに、この基板は贅沢に1つしか使っていません。
でも、この基板を使うととても簡単なので私はこれを使いました。

5.接続する

4つのドットマトリックスをI2C通信接続するとこんな感じになります。


ドットマトリックスのI2Cアドレスの並び順は図のようになります。
4つ使ってもかなりシンプルですね。

I2C通信の場合はSCL, SDAラインには適切なプルアップ抵抗を付けなければいけませんが、マトリックス基板にそれぞれ10kΩのプルアップ抵抗が既に接続されています。
それが全て並列接続ですから、抵抗値が結構小さくなりますね。
でも、動作には問題ありませんでした。

また、電圧は3.3Vですが、問題なく動作しています。
LEDドライバのHT16K33は5V推奨ですが、大丈夫だと思います。

写真で見るとこんな感じです。

6.スケッチを入力

では、Arduino IDE にスケッチを入力します。

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

/* WebSocketリアルタイムコントロール 8x8LEDドットマトリックス4連 電光掲示板サンプルスケッチ
 * ESP-WROOM-02(ESP8266) および Adafruit I2C 8x8 mini LED matrix専用
 * The MIT License (MIT)
 * Copyright (c) 2016 MGO-tec 
 * License reference URL --> https://opensource.org/licenses/mit-license.php
 */
#include <EasyWebSocket.h>
#include <ESP8266WiFi.h>
#include <Hash.h>
#include <Wire.h>
#include <UTF8toSJIS.h>
#include <MisakiFNT_read.h>
#include <I2C_Adafruit_8x8_LED_matrix.h>

#define LDaddrs1 (0x70)  //LEDドライバーHT16K33 アドレス
#define LDaddrs2 (0x71)  //LEDドライバーHT16K33 アドレス
#define LDaddrs3 (0x72)  //LEDドライバーHT16K33 アドレス
#define LDaddrs4 (0x73)  //LEDドライバーHT16K33 アドレス

const char* ssid = "xxxx"; //ご自分のルーターのSSIDに書き換えてください
const char* password = "xxxx"; //ご自分のルーターのパスワードに書き換えてください

const char* UTF8SJIS_file = "/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく
const char* Zen_Font_file = "/MSKG13KU.FNT"; //全角フォントファイル名を定義
const char* Half_Font_file = "/4X8.FNT"; //半角フォントファイル名を定義

uint8_t LedDot0[8] = {0,0,0,0,0,0,0,0};

EasyWebSocket ews;

UTF8toSJIS u8ts;

MisakiFNT_read MFR;

I2C_Adafruit_8x8_LED_matrix adaLED;

String html_str1;
String html_str2;
String html_str3;
String html_str4;
String html_str5;
String html_str6;
String html_str7;

String ret_str="";
String scl_txt="";

uint8_t scl_cnt = 0;
uint8_t fnt_cnt = 0;
bool FntReadOK = true;

uint8_t LedDotOut[4][8] = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
uint8_t Next_buf[4][8] = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
uint8_t tmp_buf[8] = {0,0,0,0,0,0,0,0};
uint8_t tmp_buf_cnv[8] = {0,0,0,0,0,0,0,0};
uint8_t tmp_buf_cnv2[8] = {0,0,0,0,0,0,0,0};
uint8_t AdaMini_cnv[8] = {0,0,0,0,0,0,0,0};
uint8_t LedDot_mini_cnv[8] = {0,0,0,0,0,0,0,0};
uint8_t sj_txt[127];
uint8_t sj_cnt = 0;
uint16_t sj_length;

uint16_t PingSendTime = 30000;

uint32_t SclTime;

uint16_t SclSpeed = 100;
bool Scl_Stop = false;
uint8_t Direction = 0;
uint8_t brightness = 0;
int16_t Angle = 0;

boolean sjis_txt_in = false;
boolean BW_reverse = false;

//***********セットアップ***************************************************
void setup() 
{
  Wire.begin(); // initialise the connection
  Wire.setClock(400000L); //HT16K33のクロックはMax 400kHz
  adaLED.LED_Driver_Initialize(LDaddrs1);
  adaLED.LED_Driver_Initialize(LDaddrs2);
  adaLED.LED_Driver_Initialize(LDaddrs3);
  adaLED.LED_Driver_Initialize(LDaddrs4);

  delay(300);

  html_str1 = "<body style='background:#000; color:#fff;'>\r\n";
  html_str1 += ews.EWS_TextBox_Send("txt1", "Hello World ! こんばんは!","送信");
  html_str1 += "<br>\r\n";
  html_str1 += ews.EWS_TextBox_Send("txt2", "全角40文字まで。半角120文字まで","送信");
  html_str1 += "<br>\r\n";
  html_str1 += ews.EWS_TextBox_Send("txt3", "半角カタカナもOK! メッセージボード電光掲示板","送信");
  html_str1 += "<br>\r\n";
  html_str1 += ews.EWS_TextBox_Send("txt4", "←●▲■℡〒℃Ω㎜Ⅶ①②③⑩★㎡♪","送信");
  html_str1 += "<br>\r\n";
  
  html_str2 = ews.EWS_On_Momentary_Button("Left", "←", 60,25,15,"#FFFFFF","#0055ff");
  html_str2 += ews.EWS_On_Momentary_Button("Right", "→", 60,25,15,"#FFFFFF","#0055ff");
  html_str2 += ews.EWS_On_Momentary_Button("Up", "↑", 60,25,15,"#FFFFFF","#0055ff");
  html_str2 += ews.EWS_On_Momentary_Button("Down", "↓", 60,25,15,"#FFFFFF","#0055ff");
  html_str3 = "<br><br>\r\n";
  html_str3 += ews.EWS_Canvas_Slider_T("Speed",200,40,"#777777","#ff00ff");
  html_str3 += "<br><br>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("_SclStop", "Scrole Stop", 100,25,15,"#000000","#777777");
  html_str3 += "<br><br>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("0", "0°", 60,25,15,"#ffffff","#ff0000");
  html_str3 += "<span>  </span>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("90", "90°", 60,25,15,"#ffffff","#ff0000");
  html_str3 += "<span>  </span>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("-90", "-90°", 60,25,15,"#ffffff","#ff0000");
  html_str3 += "<span>  </span>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("180", "180°", 60,25,15,"#ffffff","#ff0000");
  html_str3 += "<br><br>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("#rev", "Normal", 70,25,15,"#000000","#ffffff");
  html_str3 += "<span>  </span>\r\n";
  html_str3 += ews.EWS_On_Momentary_Button("~rev", "Reverse", 70,25,15,"#ffffff","#0000ff");

  html_str3 += "<br><br>\r\n";
  
  html_str4 = ews.EWS_Canvas_Slider_T("bright",200,40,"#777777","#ffff00");
  html_str4 += "<br><br>\r\n";
  
  html_str5 = ews.EWS_Status_Text(20,"RED");
  html_str5 += "<br>\r\n";
  html_str5 += "<br><br>\r\n";  
  html_str5 += ews.EWS_Close_Button("WS CLOSE",150,40,17);
  html_str5 += ews.EWS_Window_ReLoad_Button("ReLoad",150,40,17);
  html_str5 += "</body></html>\r\n";

  html_str6 = "";
  html_str7 = "";
  
  ews.AP_Connect(ssid, password);
  
  SclTime = millis();

}
//**************メインループ*************************************************
void loop() {
  //WebSocket ハンドシェイク関数
  ews.EWS_HandShake(html_str1, html_str2, html_str3, html_str4, html_str5, html_str6, html_str7);
  
  uint8_t sjis[2];
  uint8_t utf8_1, utf8_2, utf8_3;

  uint32_t sp_addres=0x9DCC; //スペース(対応文字がない場合にスペースとして初期化しておく)

  uint16_t fnt_adrs_half;
  uint8_t tmp_buf2[8];
  uint8_t br;

  ret_str = ews.EWS_ESP8266CharReceive(PingSendTime); //ブラウザからのWebSocketデータ受信

  if(ret_str != "_close"){   
    if(ret_str != "\0"){
      if(ret_str != "Ping"){
        if(ret_str[0] != 't'){
          switch(ret_str[4]){
            case 'S':
              SclSpeed = (ret_str[0]-0x30)*100 + (ret_str[1]-0x30)*10 + (ret_str[2]-0x30);
              SclSpeed = 200-SclSpeed;
              Scl_Stop = false;
              break;
            case 'L':
              Direction = 0;
              break;
            case 'R':
              Direction = 1;
              break;
            case 'U':
              Direction = 2;
              break;
            case 'D':
              Direction = 3;
              break;
            case '_':
              Scl_Stop = true;
              break;
            case 'b':
              br = (ret_str[0]-0x30)*100 + (ret_str[1]-0x30)*10 + (ret_str[2]-0x30);
              //LEDドライバHT16K33の明るさは0~16
              adaLED.LED_Driver_Brightness(LDaddrs1, floor(br/12));
              adaLED.LED_Driver_Brightness(LDaddrs2, floor(br/12));
              adaLED.LED_Driver_Brightness(LDaddrs3, floor(br/12));
              adaLED.LED_Driver_Brightness(LDaddrs4, floor(br/12));
              break;
            case '0':
              Angle = 0;
              break;
            case '9':
              Angle = 90;
              break;
            case '1':
              Angle = 180;
              break;
            case '-':
              Angle = -90;
              break;
            case '#':
              BW_reverse = false;
              break;
            case '~':
              BW_reverse = true;
              break;
          }
        }else if(ret_str[0] == 't'){
          scl_txt = ret_str.substring(ret_str.indexOf('|')+1, ret_str.length()-1);
          scl_txt += String(" ") + String("\0");
          
          u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, scl_txt, sj_txt, &sj_length);

          fnt_cnt = 0;
          scl_cnt = 0;
          sj_cnt = 0;
          FntReadOK = true;
          sjis_txt_in = true;
        }
        ret_str = "\0";
      }else{
        ret_str = "\0";
      }
    }
    
    if(sjis_txt_in == true){
      if(millis() - SclTime > SclSpeed){
        if(sj_cnt == sj_length){
          sj_cnt = 0;
        }
        if(FntReadOK==true){
          uint8_t cp = MFR.Sjis_To_MisakiFNT_DotRead(Zen_Font_file, Half_Font_file, Direction, Angle, sj_txt[sj_cnt], sj_txt[sj_cnt+1], tmp_buf_cnv);
          FntReadOK = false;
          sj_cnt = sj_cnt + cp;

          adaLED.LED_Black_White_Reversal(BW_reverse, tmp_buf_cnv, tmp_buf_cnv);
          adaLED.LED_Dot_Rotation(Angle, tmp_buf_cnv, tmp_buf_cnv2);
        }

        if(Scl_Stop == false){

          adaLED.LED_8x8mini_Disp_Out(LDaddrs1, LedDotOut[0]);
          adaLED.LED_8x8mini_Disp_Out(LDaddrs2, LedDotOut[1]);
          adaLED.LED_8x8mini_Disp_Out(LDaddrs3, LedDotOut[2]);
          adaLED.LED_8x8mini_Disp_Out(LDaddrs4, LedDotOut[3]);
          
          switch(Direction){
            case 1:
              Scroller_Dot_Replace( Direction, Next_buf[3], LedDotOut[3], tmp_buf_cnv2);
              Scroller_Dot_Replace( Direction, Next_buf[2], LedDotOut[2], Next_buf[3]);
              Scroller_Dot_Replace( Direction, Next_buf[1], LedDotOut[1], Next_buf[2]);
              Scroller_Dot_Replace( Direction, Next_buf[0], LedDotOut[0], Next_buf[1]);
              break;
            default:
              Scroller_Dot_Replace( Direction, Next_buf[0], LedDotOut[0], tmp_buf_cnv2);
              Scroller_Dot_Replace( Direction, Next_buf[1], LedDotOut[1], Next_buf[0]);
              Scroller_Dot_Replace( Direction, Next_buf[2], LedDotOut[2], Next_buf[1]);
              Scroller_Dot_Replace( Direction, Next_buf[3], LedDotOut[3], Next_buf[2]);
              break;
          }
          scl_cnt++;
        }
        
        if(scl_cnt == 8){
          scl_cnt = 0;
          FntReadOK = true;
        }
        SclTime = millis();
      }
    }
  }else if(ret_str == "_close"){
    ret_str = "\0";
    scl_txt = "";
  }
}

//*************************文字スクロール、ドット変換**************************************
void Scroller_Dot_Replace(uint8_t drection, uint8_t* next_buff, uint8_t* scl_buff_1, uint8_t* Orign_buff)
{//位置が見た目と同じく、右が1番、左が2番なので注意。
  uint8_t i;

  switch( drection ){
    case 0:        //(←)右から左へスクロール----------------------------
      for(i=0 ; i<8 ; i++){
        bitWrite( next_buff[i],7, bitRead( scl_buff_1[i],7)); //7番目のビットの取り置き
        scl_buff_1[i] = scl_buff_1[i]<<1;
        bitWrite( scl_buff_1[i],0, bitRead( Orign_buff[i],7));
        Orign_buff[i] = Orign_buff[i]<<1;
      }
      break;
    case 1:        //(→)左から右へスクロール----------------------------
      for(i=0 ; i<8 ; i++){
        bitWrite( next_buff[i],0, bitRead( scl_buff_1[i],0)); //7番目のビットの取り置き
        scl_buff_1[i] = scl_buff_1[i]>>1;
        bitWrite( scl_buff_1[i],7, bitRead( Orign_buff[i],0));
        Orign_buff[i] = Orign_buff[i]>>1;
      }
      break;
    case 2:      //(↑)下から上へスクロール----------------------------
      next_buff[0] = scl_buff_1[0];
      for(i=0 ; i<7 ; i++){
        scl_buff_1[i] = scl_buff_1[i+1];
      }
      scl_buff_1[7] = Orign_buff[0];
      for(i=0 ; i<7 ; i++){
        Orign_buff[i] = Orign_buff[i+1];
      }
      break;
    case 3:        //(↓)上から下へスクロール----------------------------
      next_buff[7] = scl_buff_1[7];
      for(i=7 ; i>0 ; i--){
        scl_buff_1[i] = scl_buff_1[i-1];
      }
      scl_buff_1[0] = Orign_buff[7];
      for(i=7 ; i>0 ; i--){
        Orign_buff[i] = Orign_buff[i-1];
      }
      break;
  }
}

プログラムの解説をする前に、20、21行の “xxxx” のところをご自分のルーターのSSIDとパスワードに変更しておいてください。

では、解説していきます。(WebSocketに関することは大幅に省略)

●1-6行:ライセンス表記
何度も当ブログで言っておりますが、インターネットでグローバルにソースコードを使っていただくためにはライセンス表記しなければいけないようです。無表記は逆に自由に使えないらしいです。
ですから、配布、改変、商用等、全て自由に仕様可能のMITライセンスとしました。
ただ、無保証です。ライセンス表記はしておいてくださいというものです。

●7行:
自作のEasyWebSocketライブラリのインクルード

●8-9行:
ESP8266 core for Arduino ライブラリのインクルード

●10行:
I2C通信の標準ライブラリのインクルード

●11行:
自作のUTF8→Shift_JIS文字コード変換ライブラリのインクルード

●12行:
これが今回新たにインストールした美咲フォントファイルからフォントデータを読み込むライブラリのインクルードです。

●13行:
これも今回新たにインストールしたAdafruit製I2C通信8x8mini LED マトリックス用ライブラリのインクルードです。

●15-18行:
LEDマトリックス基板のI2Cアドレス定義

●23行:
SPIFFSファイルシステムでESP-WROOM-02へアップロードした、UTF8→Shift_JIS変換テーブルファイル名を定義

●24行:
SPIFFSファイルシステムでESP-WROOM-02へアップロードした、美咲フォントファイル名の定義

●25行:
SPIFFSファイルシステムでESP-WROOM-02へアップロードした、半角美咲フォントファイル名の定義

●29行:
EasyWebSocketライブラリのクラス名定義

●31行:
UTF8→Shift_JIS文字コード変換ライブラリのクラス名定義

●33行:
美咲フォントファイルのデータ読み込みライブラリのクラス名定義

●35行:
ドットマトリックスライブラリのクラス名定義

●81-84行:
自作ライブラリ関数でLEDドライバの初期化

●88-132行:
EasyWebSocketライブラリを使った、ブラウザに送信するHTMLタグの<body>要素内の文字列定義。

●134行:
EasyWebSocketライブラリで、ルーター(アクセスポイント)のコネクション確立

●142行:
WebSocketのハンドシェイク(コネクション確立)

●153行;
ブラウザから送られてくる文字列受信
PingSendTimeは30秒くらいが良いと思います。

●158-209行:
ブラウザから送られてくる文字列の最初の文字が ‘t’ でないならば、最初の3文字は数値で5番目の文字以降がブラウザのボタンIDとなります。つまり、
200|Speed;
という感じで送られてくるので、5番目の文字(配列の4番目)の1文字で制御方法を判別しています。
最初の文字が ‘t’ ならば、テキストボックスの文字列が送信されてきます。つまり、
txt2|全角40文字まで。半角120文字まで|
という感じで送られてきますので、それから文字列を抽出しています。

●183-186行:
新たに作ったLEDマトリックスライブラリです。
adaLED.LED_Driver_Brightness(I2Cアドレス, 明るさ);
明るさは0~16です。
この場合Canvas要素スライダーは長さが200なので12で割って小数点を切り捨てると17段階になります。

●211行:
WebSocket通信で送られてくる文字列は UTF-8 という仕様なので、この自作ライブラリでShift_JIS文字コードへ変換してやります。
u8ts.UTF8_to_SJIS_str_cnv(UTF8SJIS_file, “UTF8文字列”, “Shift_JIS文字列”, &文字列長さ);
文字列の長さのところに ‘&’ という文字を使う所がミソです。要するにポインタの住所です。

●225行~:
送られてきたUTF8文字列がShift_JIS文字列に変換できたら、美咲フォントを読み出し、LEDをスクロールしていきます。
277行のスクロール関数を8回繰り返したら、つまり8bitシフトしたら、次の文字を代入していってスクロールします。

●231行:
新たに作った美咲フォントを読み出すライブラリです。
返り値は半角の場合は1、全角の場合は2を返します。

MFR.Sjis_To_MisakiFNT_DotRead(“全角フォントファイル名”, “半角フォントファイル名”, スクロール方向, 文字角度, sj_txt[sj_cnt], sj_txt[sj_cnt+1], 美咲フォントビットマップ);

半角文字だった場合には4×8.FNTファイルでは右半分が空白になってしまいますので、それを詰める作業もこのライブラリでやってくれます。そして、文字列の配列カウントを1進めて、全角だった場合はカウントを2進めます。

●235行:
LEDドットマトリックスの白黒反転文字にするライブラリです。

adaLED.LED_Black_White_Reversal(BW_reverse, 変換前ビットマップ, 変換後ビットマップ);

BW_reverse は 実行する場合には true。 しない場合は false とすればOKです。

●241行:
ドットの回転や白黒反転、およびスクロール変換したドットを実際のLEDドライバへ送信するライブラリです。

adaLED.LED_8x8mini_Disp_Out(LDaddrs, ビットマップ);

●248-251行:
Direction はスクロール方向ですので、左から右へスクロールする場合、はビットマップ配列を逆に配置します。

●254-257行:
通常のスクロール方向(右→左)の場合です。

●277-319行:
スクロールするためのビット変換自作関数です。

7.コンパイル実行

コンパイルする前に、SPIFFSファイルシステムのspiffs_01.txtファイルのローカルIPアドレスをご自分のルーターで割り当てたアドレスに書き換えているか確認してください。

では、コンパイル実行してみましょう。
アクセスポイントとコネクション確立したら、ブラウザのURL入力欄にWROOMのローカルIPアドレスを入力してみてください。
最初にあった動画のようにコントロールできれば成功です。

どうでしょうか?
うまく動きましたでしょうか?

長いプログラムをライブラリ化することで、こんな複雑なことも400行以下に収めることができました。
次は、時計機能やタイマーメッセージ機能を追加していきたいと思います。
しかし、この記事を書くのも大変で、究極に疲れます・・・。
なんとかしたい・・・。

ではまた・・・。

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

スイッチサイエンス ESPr Developer 32 Type-C SSCI-063647
スイッチサイエンス
¥2,420(2024/03/19 08:55時点)
ZEROPLUS ロジックアナライザ LAP-C(16032)
ZEROPLUS
¥22,504(2024/03/18 15:19時点)
Excelでわかるディープラーニング超入門
技術評論社
¥2,068(2024/03/19 03:23時点)

コメント

  1. 元山 充(Sun Motoya) より:

    mgo-tec様 20170814 発 Sysplan.motoya
    LED8X8パターン文字(青、黄、赤)のスマホ40文字飛ばし(半角120文字)の実験は大変興味あり。正確に文書と写真/映像で解説頂き良くわかりました。参考に勉強させていただきます。実験的解説しては良くできていると感心し敬服します。実用までにはまだ乗り越えないといけないハード、ソフトの山がありそうですが、この記事解説を読んだ若者がネット部品購買や秋葉原の電子部品販売店(千石他)、日本橋(共立電子)などに出掛けることでしょう。海外でのLED電子文字/映像看板やビル建物外観のアクセサリ(イルミネ)も盛んで、おっつけ日本の街中でも4K, 8Kの100から200Inch大型LED液晶パネルによるディスプレーと並行して、屋外壁面のLED文字映像看板やパネルも増加することでしょう。既に海外では道路標識や交通案内にもLED文字表示パネルが多用され始めており、日本の国土交通省及び警察庁の道路標識や道路案内板の「規格省令、付則令」の改定により近年中に実現されるのでしょう。(国内では信号灯のLEDは普及)
     新しい産業「電子LED文字発光表示パネル、システム」は街中のGSやコンビニ、ファーストフーズ、レストラン、コスメティック、ファッションなどでの集客表示のニーズとして爆発的に高まることでしょう。本記事と私のコメントに感化されて「若者が、学校が」実験的な取組が増加することに期待し、産業界としても4K, 8K大型パネルとも合わせて熱い視線を送りたいと思います。

    • mgo-tec mgo-tec より:

      元山さん

      記事をご覧いただき、そしてとても嬉しいコメント、ありがとうございます!!!
      m(_ _)m

      ただ、私は独学でプログラミングをはじめて、この後の記事ではプロフェッショナルの方々からいろいろご指摘をいただき、度々修正せざるを得なくなったりと、まだまだ勉強中のアマチュア電子工作家です。
      この電光掲示板を作るにあたっても、ネット上のいろいろな方々の情報をかき集めて作ったので、その方々のおかげでもあります。
      今の時代はネットで殆どの情報が得られるので、一昔前までは考えられないくらい便利になりましたね。
      これからは、若者の方々もそれほど苦労せずにもの凄いものを簡単に作ってしまう時代になるでしょうね。

      電車の駅の電光掲示板などは、このプログラムより遙かに優れていて、いつもスゴイなぁと思っています。
      私の趣味程度のプログラムではまだまだで、やっぱり業務用を作っているプロの方々にはかないません。
      特に、絶対バグってはいけない信頼性という面では足元にも及びません・・・。
      この記事を書いた当初はまだまだプログラムが未熟で、穴があるかも知れません。
      不具合等あったらご連絡いただけると幸いです。

      ということで、苦痛だけのブログ記事アップも、元山さんのとても有難いコメントでとても励みになりました。
      感謝感激です。
      これからもいろいろ工作して、頑張って記事アップしていこうと思います。
      ありがとうございました。
      m(_ _)m

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