【Raspberry Pi Pico入門 – 応用編】LEDマトリクス

2024年9月15日Raspberry Pi Pico入門,応用編Arduino,Raspberry Pi Pico

概要

今回はLEDマトリクスを試してみます。電光掲示板等でよく見かけると思いますが、回路としては単純にLEDが大量に並んでいるだけです。これを全てGPIOで制御しようとするとGPIOが何千個も必要なので、専用のICを使って制御するのが一般的です。

ここではLEDマトリクスや7セグの制御でよく使われているMAX7219というICを使ったモジュールを動かしてみます。

実行環境

IDE:Arduino IDE 2.3.2
MCU:Raspberry Pi Pico

LEDマトリクスモジュール:

Amazon等で売られている「FC16」というモジュールを使用します。
このモジュールは「SPI通信」と呼ばれるマイコンではよく使われる通信方式の一つを使ってどのLEDを点灯させるかの情報を制御IC(MAX7219)に送信します。(SPI通信に関する説明は割愛します)またカスケード接続(数珠つなぎに並べて接続)が可能で、何個並べても配線は5本で制御することが出来ます。4個並んでいる商品は8×8のモジュールが最初から4個並んでいるものとなります。

Amazon購入ページより引用
Amazon購入ページより引用

回路

以下のように配線します。SPI通信機能が使えるピンは決まっていて、Raspberry Pi Picoのデフォルト設定は以下のピンになっています。(色々な名前で呼ばれていますが、以下のどれかには該当するはずです)

GPIO0MISO/RX/DINデータ受信
GPIO1CS/SSチップセレクト
GPIO2SCKクロック
GPIO3MOSI/TX/DOUTデータ送信

回路図は以下のようになっています。

ライブラリでの制御(MD_MAX72xx.h)

まずは「〇行目・△列目のLEDを点灯する」という感じの制御をしてみます。
ライブラリはArduino IDEのライブラリマネージャで「MD_MAX72xx」と検索し、以下のライブラリをインストールしてください。

このライブラリを使うと必ずwarningが表示されます。マイコンのどの通信機能を使うかを通知しているものなので無視して大丈夫です。

コーディング①

新しくスケッチを作成し、以下の内容をコピペしてください。まずは一つ一つのLEDをどのように制御する方法を練習します。
幾つかのLEDが付いたり消えたりしたら成功です。

#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define DEVICES_NUM 4

const int PIN_CS = 1;
const int PIN_SCK = 2;
const int PIN_MOSI = 3;

MD_MAX72XX LED = MD_MAX72XX(HARDWARE_TYPE, PIN_CS, DEVICES_NUM);

void setup() {
  //SPIの初期設定
  SPI.setCS(PIN_CS);
  SPI.setSCK(PIN_SCK);
  SPI.setTX(PIN_MOSI);
  SPI.begin();

  //LEDマトリクスの制御開始
  LED.begin();
  //明るさの調整(1~15)
  LED.control(MD_MAX72XX::INTENSITY, 3);
  //setPointをするたびに表示を更新
  LED.update(MD_MAX72XX::ON);
}

void loop() {
  //点滅
  LED.setPoint(0, 0, 1);
  delay(1000);
  LED.setPoint(0, 0, 0);
  delay(1000);

  //座標の確認
  LED.setPoint(7, 0, 1);
  delay(1000);
  LED.setPoint(0, 7, 1);
  delay(1000);
  LED.setPoint(0, 8, 1);
  delay(1000);
  LED.setPoint(0, 16, 1);
  delay(1000);
  LED.setPoint(0, 24, 1);
  delay(1000);

  //全て消灯
  LED.clear();
}

MD_MAX72XX LED = MD_MAX72XX(モジュールの型式, CSピンの番号, モジュールを並べた個数);

インスタンスの生成です。名前は「LED」で定義しています。

LED.begin();

制御を開始する時に実行します。

LED.control(MD_MAX72XX::INTENSITY, 明るさ);

LEDの明るさを調整する関数です。明るさは1~15の15段階です。

LED.update(MD_MAX72XX::ON);

setPoint()等で点灯情報を更新する度にLEDマトリクスの点灯状態が更新されます。
ここでの実行は必須ではないですが、先に実行しておいた方がコーディングが楽です。

LED.setPoint(X座標, Y座標, 点灯するかどうか);

LED1個分の点灯状態を変更します。点灯するかどうかは0で消灯・1で点灯です。(true/falseでもOKです)
X座標、Y座標は下図の向きで右上が原点になっています。モジュールを5個以上繋げたときはY座標の最大値がどんどん大きくなっていきます。

コーディング②

次に点灯パターンを配列で定義して表示してみます。その後、ライブラリの機能を使って上下左右に動かしてみます。

#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW  //デバイス種別
#define DEVICES_NUM 4                      //8x8のマトリクス表示のユニット数

const int test_pattern[8][8] = {
  { 0, 0, 0, 0, 0, 1, 1, 0 },
  { 0, 0, 0, 0, 1, 0, 0, 1 },
  { 0, 0, 0, 0, 1, 0, 0, 0 },
  { 0, 0, 0, 0, 1, 0, 0, 1 },
  { 0, 0, 0, 0, 0, 1, 1, 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 }
};

const int PIN_CS = 1;
const int PIN_SCK = 2;
const int PIN_MOSI = 3;

int i, j;
MD_MAX72XX LED = MD_MAX72XX(HARDWARE_TYPE, PIN_CS, DEVICES_NUM);

void setup() {
  //SPIの初期設定
  SPI.setCS(PIN_CS);
  SPI.setSCK(PIN_SCK);
  SPI.setTX(PIN_MOSI);
  SPI.begin();

  //LEDマトリクスの制御開始
  LED.begin();
  //明るさの調整(1~15)
  LED.control(MD_MAX72XX::INTENSITY, 1);
  //setPointをするたびに表示を更新
  LED.update(MD_MAX72XX::ON);

  // "c"と表示
  for (i = 0; i < 8; i++) {
    for (j = 0; j < 8; j++) {
      LED.setPoint(i, 7 - j, test_pattern[i][j]);
    }
  }
}

void loop() {
  //左シフト
  for (i = 0; i < 28; i++) {
    LED.transform(MD_MAX72XX::TSL);
    delay(100);
  }
  delay(1000);

  //右シフト
  for (i = 0; i < 28; i++) {
    LED.transform(MD_MAX72XX::TSR);
    delay(100);
  }
  delay(1000);

  //下シフト
  for (i = 0; i < 3; i++) {
    LED.transform(MD_MAX72XX::TSD);
    delay(100);
  }
  delay(1000);

  //上シフト
  for (i = 0; i < 3; i++) {
    LED.transform(MD_MAX72XX::TSU);
    delay(100);
  }
  delay(1000);
}

LED.transform(動かしたい方向);

現在表示されているものを全て1つずつシフトします。シフトしたい方向を表すマクロは以下です。

TSL左にシフトします。
TSR右にシフトします。
TSU上にシフトします。
TSD下にシフトします。
TFLR左右反転します。
TFUD上下反転します。
TRC時計回りに90℃回転します。
TINV全ての点灯/消灯を反転します。

その他の関数

公式のドキュメントには他にも多数の関数について解説されています。

ライブラリでの制御(MD_Parola.h)

細かいことはおまかせしてとにかく動かしたい!という型にはMD_Parola.hというライブラリがおすすめです。MD_MAX72xx.hの面倒なところをうまいことやってくれるライブラリで、文字を打つと電光掲示板のように流すところまで自動でやってくれます。

Arduino IDEのライブラリマネージャで「MD_Parola」と検索し、以下のライブラリをインストールしてください。

コーディング

よくある電光掲示板のように文字をスクロールさせてみます。

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define DEVICES_NUM 4

const int PIN_CS = 1;
const int PIN_SCK = 2;
const int PIN_MOSI = 3;

const long DlInterval_ms = 100;  //LED.displayAnimate()を実行するたびにスクロールを行って停止するインターバル。小さいほど早くスクロールが速くなる。
const long DlStopTime_ms = 0;    //すべてのアニメーションが停止した後の停止時間

MD_Parola LED = MD_Parola(HARDWARE_TYPE, PIN_CS, DEVICES_NUM);

void setup() {
  //SPIの初期設定
  SPI.setCS(PIN_CS);
  SPI.setSCK(PIN_SCK);
  SPI.setTX(PIN_MOSI);
  SPI.begin();

  LED.displayReset();
  LED.begin();

  LED.displayText("CoTechWorks", PA_LEFT, DlInterval_ms, DlStopTime_ms, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

void loop() {
  //LED.displayTextで設定したアニメーションを実行する。
  //終了するとtrueを返すので1秒待ってからリセットする。
  if(LED.displayAnimate() == true)
  {
    LED.displayReset();
    delay(1000);
  }
}

MD_Parola LED = MD_Parola(モジュールの型式, CSピンの番号, モジュールを並べた個数);

MD_MAX72xx.hと同じ使い方です。インスタンスの型が変わっているので注意してください。

LED.displayText(文字, 文字寄せの方向, スクロールスピード, 一時停止, フェードインの向き,フェードアウトの向き );

流れる文字の動きや内容を設定します。設定できる内容はかなり多いので公式のドキュメントのリンクを紹介します。

◆文字寄せの方向/textPosition_t

◆フェードイン・フェードアウト/textEffect_t

LED.setFont(自作のフォント配列)

自作のフォントを表示することも出来ます。フォント配列はWebアプリでフォントエディタが用意されています。

フォントを作成して「Export」をクリックすると配列が表示されるので、Arduino IDEの新しいタブで「〇〇〇〇.h」というファイルを作り、配列をコピペします。
今回は「ForClock」というフォントを作ったので、LED.setFont(ForClock);で自作のフォントを適用できます。

その他の関数

その他にも色々な関数が用意されています。以下が関数の一覧です。