LED-Matrix-Panelの駆動(1)



 ESP-32でPxMatrixを使用してLED-Matrix-Panelを駆動しました。

P4 RGB LED Matrix Panel 64X32の駆動



 ESP32-WROOM-32DでドライバとしてPxMatrixを使用してLED-MATRIX-PANELを駆動しました。
PxMatrix LED MATRIX libraryの中にあるサンプルプログラム「pixetimes」を使用して、学習しました。
 使用しているArduino IDEはver1.8.19で、今現在(2023/10/20)はver2.2.1になっていますが、バージョンアップはしていません。



  完成動画


 先ずは、ドライバー「PxMatrix」のサンプル「pixeltime」を多少修正して駆動してみました。その完成動画です。
明るすぎてカメラが反応できなく見にくい画像になっています。
 最初に「Pixel Time」と表示した後、「Welcome to PxMatrix!」とスクロールして、ウエザーアイコンとカラーバーを 表示しています。その繰返しです。






  Arduino IDEの設定


1.PxMatrix LED MATRIX libraryのインストール
 このドライバPxMatrixの特徴として、パネルの入力コネクタ(PI)と出力コネクタ(PO)の間にジャンパ線を接続し、 すべてのシフトレジスタをチェーンして、1つの大きなシフトレジスタとしていることです。
 これには、マイクロコントローラに必要なGPIOピンの数を減らすことと、ハードウェアSPIインターフェイスを 使用して駆動できることの2つの利点があります。

(1) Arduino IDEの「スケッチ」⇒「ライブラリをインクルード」⇒「ライブラリの管理」から
「PxMatrix LED MATRIX library」を検索してインストールします。

(2)この「PxMatrix LED MATRIX library」は、「Adafruit GFX Library」を使用していますので、 上記と同様に「Adafruit GFX Library」を検索してインストールしておきます。

(3)上記2つをインストール後、「スケッチ」⇒「ライブラリをインクルード」で、「PxMatrix LED MATRIX library」 と「Adafruit GFX Library」が表示されているか確認してください。

2.ESP32-WROOM-32Dを使用するための設定
(1)「スケッチ」⇒「ボード」⇒「ボードマネージャ」より「esp32」を検索してインストールします。


(2)ESP32-WROOM-32DをUSBコードでPCに接続して、ボードを次のように設定します。
「ツール」⇒「ボード」⇒「ESP32 Aruduino」⇒「ESP32 Dev Module」を選択します。



(3)シリアルポートを「ツール」⇒「シリアルポート」で使用ポートを選択します。

これで、Arduino IDEの設定準備は、OKです。
なお、Arduino IDEでスケッチの書き込みに時間がかかるようでしたら、VSCODEの使用も考えてみてください。




  P4 RGB LED Matrix Panel 64X32について


 このパネルは、Aliexpressで1000円から2000円程で購入できます。ただ、物によっては入力ピンと 出力ピンのピンアサイン(ピン配置)が表示されていないものがあります。
 下図が、私が購入した LEDパネルの裏面ですが入力ピン・出力ピンのピン配置は表示されていませんでした。



1.パネルのピン配置
 ピン配置が表示されていなくても大部分がAdafruitのHUB75基準に従って作られたものだと思います。
 (心配の場合、購入先で確認してください)
 ピン配置が表記されている場合、表記されていない場合でも次のどれかになっていると思います。
  なお、入力ピンと出力ピンのピン配置は同じです。

(1)私のパネルは、図1のピン配置を使用しています。
  矢印は、パネル裏面に記載されているもので、方向を表しています。
 図1

図2

図3


(2)図1と図2の違いは、R、G、Bの添え字が違っているだけで内容は同じです。
  図1のR0=図2のR1、 図1のR1=図2のR2・・・・・・等です。

(3)パネルによっては、図3のように8ピン「E」を接続する必要があります。
  ピン表示が表記されていない場合、8ピンが「E」か「GND」かの確認は、マルチメーターを使用して、
 8ピンと16ピンの導通を調べ、導通していれば図2のように8ピンは「GND」になります。

(4)各ピンの機能は次の通りです。




  配線


 前述したように、使用するドライバPxMatrixは、パネルの入力コネクタ(PIn)と出力コネクタ(POut)の間に ジャンパ線を接続し、すべてのシフトレジスタをチェーンして、1つの大きなシフトレジスタとしていますので、 次のように配線します。

1.パネルの入力コネクタと出力コネクタ間の接続
 パネルの入力ピンと出力ピンを次のように接続します。
図5


2.パネルの入力コネクタとESP32のGPIO間の接続
図6

このようにR0だけに信号線を接続するだけで済みます。

3.配線図
 次図が実際の配線図です。実に簡単な配線になります。
図7


4.実際の配線写真


5.使用した電源は、右図のAliexpressで購入した5V、10A の物を使用しました。





  PxMatrixの概要


1.このドライバは、追加のコンポーネントなしで、中国製のRGB LEDマトリックスモジュールを制御します。
  次の通りこれらのパネルは、大規模なLEDディスプレイで一般的に使用され、さまざまなレイアウトと
 解像度で提供されます。
図8


 複数のパネルをチェーンして、より大きなパネルを構築することができます。 ドライバーはAdafruit GFXと互換性があり、 現在、ESP8266、ESP32、およびAtmelベースのArduinos(最大64x32のみ)で動作します。


2.表示する構造
 パネルは基本的に6つの大きなシフトレジスタで構成されています。 入力コネクタには、シフトレジスタへの 入力(Rx、Gx、Bxの各色に2つ)、2?5ビットのラッチアドレス入力(A、B、C、D、E)、ラッチイネーブル入力(LAT/STB)、 クロック入力(CLK)、出力イネーブル入力(OE)があります。

 いくつかの基本的な行スキャンレイアウトがあります。(1/4、1/8、1/16、および1/32行スキャン) プログラムで display.begin(n) を使用して、ディスプレイの正しいパターンを有効にすることができます。 (n={4,8,16,32} はパターンを定義します)。

 このようなLEDマトリックスは通常、大型ディスプレイのサブモジュールとして使用されるため、 デイジーチェーン接続用の出力コネクタを備えています。 出力コネクタには、A、B、C、LAT、CLKが 単にルーティングされ、(R、G、B)ピンがモジュールのシフトレジスタの出力である入力コネクタと同じ 信号があります。




  サンプルプログラム「pixetimes」


1.「PxMatrix LED MATRIX library」のサンプルプログラム「pixetimes」を使用しました。
 Arduino IDEから「ファイル」⇒「スケッチ例」⇒「PxMatrix LED MATRIX library」⇒「pixetimes」と選択し、 サンプルプログラム「pixetimes」を表示します。


2.私のパネルは、P4 RGB LED MATRIX Panel 64x32 を使っていますので、プログラム上で次の点を修正します。
(1)display.begin(n) (n=4,8,16,32)について
  私のパネルは、図8から、行スキャンパターンが(1/16)ですので、
   display.begin(16) とします。

(2)PxMATRIX display() について
  私のパネルは、Eピンを必要としていない(図1のピン配置)ので、次のように
 PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);をコメントアウトします。

   //PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C);
   PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
   //PxMATRIX display(64,64,P_LAT, P_OE,P_A,P_B,P_C,P_D,P_E);


3.次に、上記2点を修正すれば、そのままで良いのですが、コメントとESP2866関係の部分を全て削除した
 プログラムを次に表示します。また、weather_icons[] のデータは、分かり易くするために並び替えています。

ESP32による「pixetimes」のプログラム

#include <PxMatrix.h>

// Pins for LED MATRIX
#define P_LAT 22
#define P_A 19
#define P_B 23
#define P_C 18
#define P_D 5
#define P_OE 2
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

#define matrix_width 64
#define matrix_height 32
uint8_t display_draw_time=70; //30-70 is usually fine

//PxMATRIX display(32,16,P_LAT, P_OE,P_A,P_B,P_C);
PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D);
//PxMATRIX display(64,64,P_LAT, P_OE,P_A,P_B,P_C,P_D,P_E);

// Some standard colors
uint16_t myRED = display.color565(255, 0, 0);
uint16_t myGREEN = display.color565(0, 255, 0);
uint16_t myBLUE = display.color565(0, 0, 255);
uint16_t myWHITE = display.color565(255, 255, 255);
uint16_t myYELLOW = display.color565(255, 255, 0);
uint16_t myCYAN = display.color565(0, 255, 255);
uint16_t myMAGENTA = display.color565(255, 0, 255);
uint16_t myBLACK = display.color565(0, 0, 0);
uint16_t myCOLORS[8]={myRED,myGREEN,myBLUE,myWHITE,myYELLOW,myCYAN,myMAGENTA,myBLACK};

uint8_t static weather_icons[]=
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x20,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00
,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x20,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00

,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x07,0xdf,0x07,0xdf,0x07,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x20,0x00,0x20,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x07,0xff,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xdf,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00
,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00
,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00

,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x20
,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x00,0x00,0x00,0x20,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00

,0x00,0x20,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0xff,0xe0
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x07,0xdf,0x07,0xdf,0x07,0xff,0xff,0xe0,0xff,0xe0,0x00,0x00

,0x00,0x00,0xff,0xe0,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00
,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0xff,0xe0,0xff,0xe0,0x00,0x20,0x00,0x00
,0x07,0xdf,0x07,0xdf,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xdf,0x07,0xdf,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00
,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0xff,0xff,0x07,0xff,0x07,0xff,0x07,0xdf,0x07,0xff,0x00,0x00
,0x07,0xff,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xdf,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00

,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x20,0x00,0x00,0x07,0xff,0x00,0x20,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x20,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xdf,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xdf,0x00,0x00,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xdf,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00
,0xff,0xe0,0xff,0xe0,0x07,0xdf,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00

,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0xff,0xe0
,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00
,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0xff,0xe0,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00
,0xff,0xe0,0xff,0xe0,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00

,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x07,0xdf,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x20,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00
,0x07,0xff,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xdf,0x07,0xff,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00
,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00
,0x00,0x00,0xff,0xe0,0xff,0xe0,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00

,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x07,0xff,0x07,0xff,0x00,0x20,0x00,0x00,0x00,0x20
,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xdf,0x07,0xdf,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x07,0xff,0x07,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0xff,0xe0,0xff,0xe0,0x07,0xdf,0x07,0xff,0x07,0xff,0x00,0x00,0x00,0x00,0x00,0x00

,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0xff,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

void IRAM_ATTR display_updater(){
  portENTER_CRITICAL_ISR(&timerMux);
  display.display(display_draw_time);
  portEXIT_CRITICAL_ISR(&timerMux);
}

void display_update_enable(bool is_enable){
  if (is_enable){
    timer = timerBegin(0, 80, true);
    timerAttachInterrupt(timer, &display_updater, true);
    timerAlarmWrite(timer, 4000, true);
    timerAlarmEnable(timer);
  }
  else{
    timerDetachInterrupt(timer);
    timerAlarmDisable(timer);
  }
}

void setup() {
  Serial.begin(9600);
  display.begin(16);
  
  display.clearDisplay();
  display.setTextColor(myCYAN);
  display.setCursor(2,0);
  display.print("Pixel");
  display.setTextColor(myMAGENTA);
  display.setCursor(2,8);
  display.print("Time");
  display_update_enable(true);
  delay(3000);
}

union single_double{
  uint8_t two[2];
  uint16_t one;
} this_single_double;

void draw_weather_icon (uint8_t icon){
  if (icon>10)
  icon=10;
  for (int yy=0; yy<10;yy++) {
    for (int xx=0; xx<10;xx++) {
      uint16_t byte_pos=(xx+icon*10)*2+yy*220;
      this_single_double.two[1]=weather_icons[byte_pos];
      this_single_double.two[0]=weather_icons[byte_pos+1];
      display.drawPixel(1+xx,yy,this_single_double.one);
    }
  }
}
unsigned long last_draw=0;

void scroll_text(uint8_t ypos, unsigned long scroll_delay, String text, 
                        uint8_t colorR, uint8_t colorG, uint8_t colorB){
    uint16_t text_length = text.length();
    display.setTextWrap(false);  // we don't wrap text so it scrolls nicely
    display.setTextSize(1);
    display.setRotation(0);
    display.setTextColor(display.color565(colorR,colorG,colorB));

    for (int xpos=matrix_width; xpos>-(matrix_width+text_length*5); xpos--) {
      display.setTextColor(display.color565(colorR,colorG,colorB));
      display.clearDisplay();
      display.setCursor(xpos,ypos);
      display.println(text);
      delay(scroll_delay);
      yield();
    }
}

uint8_t icon_index=0;

void loop() {
  scroll_text(1,50,"Welcome to PxMatrix!",96,96,250);
  display.clearDisplay();

  draw_weather_icon(icon_index);
  icon_index++;
  if (icon_index>10)
    icon_index=0;
  for (int xx=0; xx<16;xx++) {
    display.drawLine(xx+16,0,xx+16,5,display.color565(xx*16,0,0));
    display.drawLine(xx+16,6,xx+16,10,display.color565(0,xx*16,0));
    display.drawLine(xx+16,11,xx+16,15,display.color565(0,0,xx*16));
  }
  delay(1000);
  for (uint8_t dimm=255; dimm>0; dimm--) {
    display.setBrightness(dimm);
    delay(5);
  }
  for (uint8_t dimm=0; dimm<255; dimm++) {
    display.setBrightness(dimm);
    delay(5);
  }
}
						




  「pixetimes」プログラムの概略


1.ESP32のタイマー割り込みについて
 プログラム中の割り込み記述部分は以下の通りです。

#include <PxMatrix.h>
  ・・・・・・・・・・・・・
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;   ・・・・・・・・・・・・・   ・・・・・・・・・・・・・ void IRAM_ATTR display_updater(){   portENTER_CRITICAL_ISR(&timerMux);   display.display(display_draw_time);   portEXIT_CRITICAL_ISR(&timerMux); }
void display_update_enable(bool is_enable){   if (is_enable){     timer = timerBegin(0, 80, true);     timerAttachInterrupt(timer, &display_updater, true);     timerAlarmWrite(timer, 4000, true);     timerAlarmEnable(timer);   }   else{     timerDetachInterrupt(timer);     timerAlarmDisable(timer);   } }
void setup() {
  ・・・・・・・・・・・・・   display_update_enable(true);   ・・・・・・・・・・・・・ }   ・・・・・・・・・・・・・ void scroll_text(・・・・・・・・・・・・・・・・・・){   ・・・・・・・・・・・・・・・・・・・・・・・・   ・・・・・・・・・・・・・・・・・・・・・・・・   yield(); }

(1)hw_timer_t * timer = NULL; について
 タイマーを設定するために必要なhw_timer_t型(タイマー管理用の構造体)のポインターを設定します。
 これはセットアップ関数で使用します。

(2)portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; について
 同期用変数で、portMUX_TYPE型の変数で、メインループとISR(割込処理)で共用変数を変更する時の同期処理に使用します。

(3)void IRAM_ATTR display_updater(){
     portENTER_CRITICAL_ISR(&timerMux);
     display.display(display_draw_time);
     portEXIT_CRITICAL_ISR(&timerMux);
    }
 について
  これは、ISR関数の構成を記述しています。
 ISR関数のコードを記述するときの注意点:
  *ISR関数は引数を伴わないvoid型でなければならない。
  *ISRは IRAMに配置するため、IRAM_ATTR属性が必要。
  *関数内では割込通知カウンターをインクリメントして、メインループに割り込みの発生を通知する。
  *共用変数のインクリメントなので、portENTER_CRITICAL_ISRと portEXIT_CRITICAL_ISRで挟んだ
   クリティカルセクション内で行う。

(4)timer = timerBegin(0, 80, true);
   timerAttachInterrupt(timer, &display_updater, true);
   timerAlarmWrite(timer, 4000, true);
   timerAlarmEnable(timer);
 について
  これはセットアップで行う初期化処理です。

  * timer = timerBegin(0, 80, true); 使用タイマーの指定と初期化をします。
   timerBegin関数で使用するタイマーの番号などを指定して初期化処理をします。
   この関数はesp-hal-timer.h内で次のようにプロトタイプ宣言されています。
     hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp);
   ・第1引数: 使用するタイマーの番号(0~3)
   ・第2引数: プリスケーラー(1マイクロ秒ごとにインクリメントさせたいなら80を指定)
   ・第3引数: 割込カウンターのインクリメント(カウントアップ)指定

  * timerAttachInterrupt(timer, &display_updater, true); 割込処理関数(ISR)の設定です。
   ISR関数を割込処理に結びつけます。
   この関数もesp-hal-timer.h内で次のようにプロトタイプ宣言されています。
      void timerAttachInterrupt (hw_timer_t * timer, void (* fn)(void), bool edge);
   ・第1引数: 初期化されたタイマー設定用のポインター
   ・第2引数: ISR関数のアドレス
   ・第3引数: エッジ割込指定

  * timerAlarmWrite(timer, 4000, true); タイマーの動作間隔を指定します。
   この関数もesp-hal-timer.h内で次のようにプロトタイプ宣言されています。
      void timerAlarmWrite (hw_timer_t * timer, uint64_t alarm_value, bool autoreload);
   ただし第2引数の単位は、timerBegin()の第2引数のプリスケーラーで80を指定
、    つまりマイクロ秒指定に基づいていることに注意してください。
   ・第1引数: タイマーへのポインター
   ・第2引数: 割込発生までの時間(マイクロ秒)
   ・第3引数: カウンターのリロード指定(定期的に割り込みを生成させる)
   1秒間隔の割込の場合は次のように指定します。
     timerAlarmWrite(timer, 1000000, true);

  * timerAlarmEnable(timer); タイマー変数を引数として渡してタイマーの有効化を宣言します。
   これもesp-hal-timer.h内で次のようにプロトタイプ宣言されています。
      void timerAlarmEnable (hw_timer_t * timer);
   ここでは次のように指定します。
     timerAlarmEnable(timer);

(5)timerDetachInterrupt(timer);
   timerAlarmDisable(timer);
 について

  *timerDetachInterrupt(timer);
  この関数はタイマーからの割り込みを解除するために使用されます。

  * timerAlarmDisable(timer);
  この機能は、タイマーアラームイベントの生成を無効にするために使用されます。

(6) yield();
 知識不足で良く分からない所がありますが、ESP8266 と同様の扱いで良いかと思います。
loop() の内部に while や for などの長時間実行される部分や入力待ちがある場合は、 ウォッチドッグタイマWDTエラーの発生を回避するために、yield()関数を使用して、タイマを 0 に 戻します。Delay(1)コマンドでも同等に使えます。


2.ディスプレイ関連
(1)display.setTextSize(1); 通常、引数は、1か2です。
 「フォントのサイズ」に「1」を指定した場合、1つの文字の高さは「8」、文字の幅は「6」になります。

(2)display.setCursor(posx,posy);
 ある文字の真横(ココでは右隣)に、重なることなく別の文字を表示する場合、
 第1引数には、「現在のカーソル位置」に「6」以上の値を加えた値を設定する必要があります。
  ある文字の真下に、重なることなく別の文字を表示する場合、
 第2引数には「現在のカーソル位置」に「8」以上の値を加えた値を設定する必要があります。

(3)display.print("Pixel");
 シリアルモニタと似たように、print()、println() が使えます。

(4)display.setTextColor(myCYAN);
 表示するテキストのカラー設定です。


3.Weather_icon について
 天気用のアイコンが11個描かれるようにしてあります。

(1)11個のアイコンのデータを直列的なデータ構造として、配列にして初期化してあります。
  分かり易くするために、データを横20個、縦11行の計220個のデータを1ブロックにして並べ替えて、
 uint8_t static weather_icons[] のデータとしています。全部で10ブロックになります。

(2)上記データを以下の共用体の変数に入れて、void draw_weather_icon (uint8_t icon){  }で
 アイコンを表示しています。

union single_double{
  uint8_t two[2];
  uint16_t one;
} this_single_double;

void draw_weather_icon (uint8_t icon){
  ・・・・・・・・・・・・・・・・・・・・・・・・・
  for (int yy=0; yy<10;yy++){
	for (int xx=0; xx<10;xx++){
	  uint16_t byte_pos=(xx+icon*10)*2+yy*220;
	  this_single_double.two[1]=weather_icons[byte_pos];
	  this_single_double.two[0]=weather_icons[byte_pos+1];
	  display.drawPixel(1+xx,yy,this_single_double.one);
	}
  }
}
							

 上記、uint8_t static weather_icons[]のデータで10ブロックの各1行目を集めて並べるとアイコンの データの並びになり、その中の2つのデータがペアで two[1]とtwo[0]に入ります。
 例えば、two[1]=0x00、two[0]=0x00の場合、this_single_double.one=0x0000となり,ポイントに黒色を表示します。
また、two[1]=0xff、two[0]=0xe0の場合、this_single_double.one=0xffe0となり、ポイントに黄色を表示します。

uint8_t static weather_icons[] のデータで10ブロックの各1行目を集めて並べたicon=0は次のようになります。


 次に、10ブロックのデータの各2行目を集めて並べると次のようになりicon=1 を表示します。


 以下、同様にして、icon2~icon10は次のようになります。










3.文字のスクロールについて
 文字列のスクロールは、次のscroll_text()関数で行っています。
    void scroll_text(ypos, scroll_delay, text, colorR, colorG, colorB){ }
 loop() 内で、scroll_text(1,50,"Welcome to PxMatrix!",96,96,250); として、
テキスト「Welcome to PxMatrix!」を表示しスクロールしています。


4.weather_icons とカラーバーの表示
 loop() 内で、draw_weather_icon(icon_index); によりweather_iconsを表示し、
3色のカラーバーを表示して、輝度を変化させています。詳細は省略します。