ESP32 デュアルコア ( マルチタスク )で、4つの News 記事を取得する電光掲示板を作ってみた

ESP32 ( ESP-WROOM-32 )

こんばんは。

今回は、ESP32 ( ESP-WROOM-32 )のDual Core ( Multi Task ) を更に応用して、4種類の Web ニュース記事を取得して、電光掲示板スクロールしてみました。
有機EL ( OLED )ディスプレイは、SPI通信の フルカラー SSD1331 モジュールで、SSD1351 よりも速度は遅いのですが、4つの記事を十分な速度でスクロールさせることができました。

この記事および自作ソースコードの公開について、Yahoo! Japan さんにお問い合わせして、趣味や研究範囲と判断でき、問題無いとの回答を得ております。
(2017/8/11)

まずは以下の動画をご覧ください。

いかがでしょうか。
東スポWeb 記事が少々カクカクしてますが、4つの記事を別々にスクロールさせていることが分かると思います。

EPP8266の時は、4つの記事をこれだけのスピードでスクロールさせることはとても無理だったのですが、かなり高速でスクロールしてくれますね。
それに加えて、裏の CPU でスクロールを止めずに記事を GET できているのがスバラシイ!!
しかも、今回選んだニュース記事は、以前までの記事で使っていた Yahoo! Japan RSS ニューストピックストップ記事よりも格段に多い文字列を取得しています。
取得した記事は以下の通りです。

●EDN Japan
●日刊スポーツ
●東スポWeb
●日経トレンディネット

日経トレンディネットが最も多い文字数で、全角で 1000文字弱ありました。
SRAM メモリをかなり消費してしまいますが、ESP32 ( ESP-WROOM-32 )は問題無く動作しますね。
素晴らしい!!

では、これの方法を説明します。
前回、前々回の記事と重複しているところがあるので、すっ飛ばして説明させていただきます。

スポンサーリンク

使っているもの

使用している主なデバイスは以下の通りです。

ESPr Developer 32 または、ESP32-DevKitC

ESPr Developer 32
スイッチサイエンス(Switch Science)

ESPr Developer 32 参考記事

フルカラーOLED SSD1331 SPI モジュール

その他の細かい物品については、前回の記事を参照してください。

事前に、Arduino core for ESP32設定、ライブラリインストール、フォント、ルート証明書を保存しておく

Arduino IDE は ver 1.8.3 を使用し、Arduino core for ESP32 は最新版をダウンロードしてインストールしてください。

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

また、ライブラリ等は以下の記事を参照して、私の自作ライブラリのインストールしておき、micro SDカードにフォントや Yahoo! Japan RSS ルート証明書を保存しておいてください。

Yahoo ニュース、天気予報、NTP時計ガジェットを ESP32 マルチタスク ( デュアルコア )で動かしてみた

ESP32 マルチタスク(デュアルコア)で、電光掲示板スクロールを止めずに、別のCPUで Web GET できました

Arduino – ESP32 WiFiClientSecure ライブラリで、安定して https ( SSL )記事をGETする方法

【外部使用ライブラリ】

ESP32_SD_SSD1331_Gadgets  ( beta ver 1.1 )
ESP32_SD_ShinonomeFNT  ( beta ver 1.21 )
ESP32_SD_UTF8toSJIS  ( beta ver 1.21 )
ESP32_SSD1331 ( beta ver 1.3 )
ESP32_WebGet ( beta ver 1.1 )
Time ライブラリ ( Arduino 標準ライブラリ ver 1.5 )

【micro SD カードへ保存するファイル】

Utf8Sjis.tbl  (UTF-8 → Shift_JIS 変換テーブル)
shnmk16.bdf (全角東雲フォント)
shnm8x16.bdf (半角東雲フォント)
yahoo.cer ( Yahoo! Japan RSS ルート証明書 )

スケッチの入力

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

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

#include "ESP32_SD_SSD1331_Gadgets.h"

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

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 char* MyFont_file = "/font/MyFont.fnt"; //自作フォントファイル名を定義
const char* Yahoo_rootca_file = "/root_ca/yahoo.cer"; //Yahoo! Japan RSS ルート証明書ファイル

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_SD_SSD1331_Gadgets ESSG;
ESP32_SD_UTF8toSJIS u8ts;
ESP32_SSD1331 _ssd1331(SCLK_OLED, MISO_OLED, MOSI_OLED, CS_OLED, DC_OLED, RST_OLED); //HSPI 接続
ESP32_SD_ShinonomeFNT _SFR(CS_SD, 24000000); //SPI 24MHz
ESP32_WebGet _EWG;

//Yahoo! Japan RSS トピックス以外のニュースは2048バイト以上の配列確保必要
uint8_t sj_txt[4][2048] = {}; //Shift_JIS コード文字列を格納
uint16_t sj_length[4] = {}; //Shift_JIS コード文字列長

int32_t NewsGetLastTime = 0; //起動時にすぐGETするようにマイナスにしている
bool WebGet[4] ={false, false, false, false}; //記事をGETした場合はtrue

//***************** Arduino Setup **********************************
void setup() {
  Serial.begin(115200);
  _EWG.EWG_AP_Connect(ssid, password); //Wi-Fi ルーターと接続
  delay(1000);
  _ssd1331.SSD1331_Init(); //OLED SSD1331 初期化
  //UTF-8→S_JIS変換テーブル、東雲フォント全角、半角ファイル、合計3つのファイルを同時に開く
  if(!_SFR.SD_Shinonome_Init3F(UTF8SJIS_file, Shino_Half_Font_file, Shino_Zen_Font_file)){
    return;
  }

  //EDN Japan 初回GET
  WebGet[0] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/it_edn/all.xml", Yahoo_rootca_file, sj_txt[0], &sj_length[0]);
  //日刊スポーツ 初回GET
  WebGet[1] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/nksports/all.xml", Yahoo_rootca_file, sj_txt[1], &sj_length[1]);
  //東スポWeb 初回GET
  WebGet[2] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/tospoweb/all.xml",  Yahoo_rootca_file, sj_txt[2], &sj_length[2]);
  //日経クロストレンド 初回GET
  WebGet[3] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/nkctrend/all.xml", Yahoo_rootca_file, sj_txt[3], &sj_length[3]);
  NewsGetLastTime = millis();

  TaskHandle_t th; //ESP32 マルチタスク ハンドル定義
  xTaskCreatePinnedToCore(Task1, "Task1", 4096, NULL, 5, &th, 0); //マルチタスク core 0 実行
}
//***************** メインループ **********************************
void loop() {
  if((millis() - NewsGetLastTime) > 180000){ //180秒毎に記事更新
    //EDN Japan
    WebGet[0] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/it_edn/all.xml", Yahoo_rootca_file, sj_txt[0], &sj_length[0]);
    //日刊スポーツ
    WebGet[1] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/nksports/all.xml", Yahoo_rootca_file, sj_txt[1], &sj_length[1]);
    //東スポWeb
    WebGet[2] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/tospoweb/all.xml", Yahoo_rootca_file, sj_txt[2], &sj_length[2]);
    //日経クロストレンド
    WebGet[3] = Yahoo_RSS_GET("news.yahoo.co.jp", "/rss/media/nkctrend/all.xml", Yahoo_rootca_file, sj_txt[3], &sj_length[3]);
    NewsGetLastTime = millis();
  }
}

//************* マルチタスク ****************************************
void Task1(void *pvParameters){
  while(1){ //red(0-7), green(0-7), blue(0-3)
    ESSG.Scroll_1_line(0, 0, 0, 7, 0, 1, sj_txt[0], sj_length[0], &WebGet[0]);
    ESSG.Scroll_1_line(16, 1, 1, 1, 3, 4, sj_txt[1], sj_length[1], &WebGet[1]);
    ESSG.Scroll_1_line(32, 2, 7, 0, 1, 7, sj_txt[2], sj_length[2], &WebGet[2]);
    ESSG.Scroll_1_line(48, 3, 7, 7, 3, 11, sj_txt[3], sj_length[3], &WebGet[3]);
  }
}
//************* Yahoo! Japan RSS GET ********************************
bool Yahoo_RSS_GET(const char * Host, String t_ip, const char *Rootca_File, uint8_t sj[], uint16_t *sj_len){
  char root_ca[2048];
  ESSG.Root_CA_SDcard_Read(Rootca_File, root_ca);
  String news_str = _EWG.EWG_https_Web_Get(root_ca, Host, t_ip, '\n', "</rss>", "<title>", "</title>", "◆ ");
  *sj_len = u8ts.UTF8_to_SJIS(news_str, sj);
  Serial.println(news_str);
  Serial.flush();
  return true;  
}

【解説】

●1行目:
自作ライブラリのインクルードです。
UTF-8 → Shift_JISライブラリや、東雲フォントライブラリをインクルードしなくても、ESP32_SD_SSD1331_Gadgetsライブラリ内でインクルードされています。

●3-4行目:
ご自分のルーターの SSID とパスワードに書き換えてください。

●6-10行目:
micro SD カードに保存してあるフォントファイルや、Yahoo! Japan RSS ルート証明書のファイル名を定義しています。

●21-25行:
私の自作ライブラリのクラス名を定義しています。

●28行:
Yahoo! Japan RSS ニュース記事を取得した後、Shift_JISコードに変換しますが、その変換された Shift_JISコード文字列を格納しておく配列です。
「日経トレンディネット」記事の場合は、1000文字近くなるので、Shift_JISコードに変換すると2倍になります。
その直近の最大数ということで、2048としました。

●32行:
46行目などの、Yahoo_RSS_GET関数などでWeb記事をGETしたら、trueを返します。それを格納しておきます。

●41行:
ここで、UTF-8→Shift_JIS変換テーブルファイルや、フォントファイルを同時に3つ開きます。
ESP32 では、1タスク中に同時に開けるファイル数の最大値は4つまでです。

●46-52行:
Yahoo! Japan RSS ニュースサイトから、記事タイトルだけを取得します。
83-91行で関数化しています。
今回取得しているのは、以下の記事です。

EDN Japan
日刊スポーツ
東スポWeb
日経トレンディネット

これらの記事取得後は、sj_txtという変数にShift_JISコードが返ってきます。
これは、前回記事のような 1024バイトでは足りません。
2048バイト以上無ければ取得できませんので要注意です。
と言っても、多いのは日経トレンディネットですが・・・。

●55行:
以前の記事でも述べましたが、ESP32 の FreeRTOS マルチタスク用の TaskHandle_t 型の定義です。
th にはタスクハンドルが格納されます。

●56行:
ここで、ESP32 デュアルコアの core 0 で、74-81行のタスクが実行されます。
つまり、有機EL ( OLED )ディスプレイの文字スクロールを、while無限ループで実行させます。

●59-71行:
Arduino 関数のメインループです。
ESP32 のマルチタスクでは、core 1 で実行されます。
前回記事でも述べましたが、WifiClientSecure などの WiFi系ライブラリは、core 1 のメインループ関数内で実行させる方がトラブルが少ないです。

180秒毎に Yahoo! Japan RSS 記事を取得しています。

●74-81行:
マルチタスク、core 0 で実行する関数です。
Scroll_1_line は自作ライブラリの関数で、OLED SSD1331 ディスプレイの1行をスクロールさせる関数です。

●83-91行:
Yahoo! Japan RSS サイトからニュース記事のタイトルをGET する関数です。
85行で micro SD カードに保存してあるルート証明書を読み込んで、それを86行の関数へ代入して、SSL ハンドシェイクを実行しています。
記事は String型の UTF-8 コードで返って来るので、87行目で Shift_JISコードに変換しています。

コンパイル書き込み実行

では、上記のスケッチをコンパイル書き込み実行させてみてください。

最初に紹介した動画のように表示されればOKです。

また、シリアルモニターではこんな感じに表示されます。

まとめ

以上、うまく動きましたでしょうか?

ESP8266 ではなかなか実現できなかった4つ異なる記事の同時スクロールが、問題無くできるようになって、改めて ESP32 ( ESP-WROOM-32 )のポテンシャルの高さに驚かされます。
しかもデュアルコア(マルチタスク)で、文字スクロールが停止しないというのがスゴイですよね。
それに、結構高速でスクロールしてくれています。

これは、OLED SSD1331 のグラフィックアクセラレーションコマンドのおかげなのですが、それでもスゴイです。
電子工作の幅が本当に広がりますね。

今、高校野球の時季ですが、その結果もこの電光掲示板スクロールで絶えず表示できそうです。

と、いうことで、今回はここまでです。

ではまた・・・。

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

スイッチサイエンス ESPr Developer 32 Type-C SSCI-063647
スイッチサイエンス
¥2,420(2024/03/29 13:47時点)
ZEROPLUS ロジックアナライザ LAP-C(16032)
ZEROPLUS
¥22,504(2024/03/28 20:55時点)
Excelでわかるディープラーニング超入門
技術評論社
¥1,700(2024/03/29 10:12時点)

コメント

  1. Y.Mita より:

    いつも有益で楽しい記事、ありがとうございます。
    実は昨日もコメント書いたのですが、何故か送信後に消えてしまった?
    もしかするとURLを書いたので受け付けられなかったのかも、と思って再度書かせていただきます。
    OLEDを使って本記事をそのままコピーさせていただいた後に、私がよく使用している、ILI9341を使った2.8インチLCD(320×240)で5行+日付・時刻・天気予報をESP32で実装してみました。
    https://youtu.be/1hnR1zUxFmE
    ドット数が多くて色々表示できるし、1,600円程度でSPI接続で結構遊べるのでお勧めです。
    私の汚いコードで良ければどこかにアップしますが、興味ありますか?

    お目汚し、コメント欄汚し、失礼しました。

    • mgo-tec mgo-tec より:

      Y.Mitaさん

      コメント投稿ありがとうございます。

      やはり、URLのせいでスパムとして弾かれていました。
      失礼しました。
      Youtube動画リンクは正常に修正しておきました。

      動画拝見しました。
      私のサンプルプログラムを見事に拡張されていて、スバラシイです!!
      ここまで応用していただけると、私もやる気が出ますね。
      ILI9341は私も随分前に購入していて、いつか試そうと思いつつ放置していました。
      今は Google Home の課題が山積していて、いつ手を付けられることやらッて感じです。

      もし、よろしければコードをアップしていただければ、リンクを貼らせて頂きたいと思います。
      この記事を読んだ方々も恐らく見たいと思いますので・・・。

      とても嬉しいコメント感謝いたします。
      m(_ _)m

  2. Y.Mita より:

    mgo-tecさん、
    コメント返答、ありがとうございます。
    公開できる様に準備を進めていますが、皆様に迷惑を掛けそうで、本当に公開してよいか、迷っています。(って、現状見えてしまっていますが)
    https://github.com/YMita2017/Yahoo5NewsViewWithWeather
    もし、ご迷惑をお掛けしそうならば、直ちに非公開に修正しますので、遠慮なく申し付けください。
    よろしくお願いします。

    • mgo-tec mgo-tec より:

      Y.Mita さん

      わざわざご連絡ありがとうございます。
      迷惑どころか、私のコードをここまで発展させて頂いて、逆に感謝しています。
      ありがとうございました。
      m(_ _)m
      ということで、正式なリンクに修正させて頂きました。
      みなさんの参考になってくれると良いですね。

      これからもいろいろとスゴイものを作ってください。

  3. Y.Mita より:

    mgo-tecさん、こんばんは。
    リンク公開、ありがとうございます。
    これから私のつたない製作に対して質問等が来て、ご迷惑をお掛けするかも、と心配していました。
    そこで、今回、以前に開設して2年ほど放置していた私のblogにも記事を投稿しました。
    http://ymita.blog9.fc2.com/blog-entry-1470.html
    かなり古いラジコン関連記事ばかりですが、お時間あれば覗いてみてください。
    これからもよろしくお願いします。

    • mgo-tec mgo-tec より:

      Y.Mitaさん

      いえいえ、大丈夫ですよ~。

      私も何かと忙しく、Y.Mitaさんのコードを解読する時間が無く、質問されてもサッパリわからないと思います。
      もし、質問があったら、Y.Mitaさんのブログで質問投稿してください、と振らせて頂きます。

      ラジコン飛行機はやっぱいいですね。
      青空の中で工作をやっているっていう感じで、羨ましいです。
      私もいつか時間に余裕ができたらやってみたいです。

      ということで、これからもドンドン面白いものを作っていってください。
      こちらこそ、これからもよろしくお願いします。

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