🚨

4連ドットマトリクスとテキスト表示

2023/01/15に公開

ライブラリ

https://github.com/MajicDesigns/MD_Parola

  • CSSアニメーションのごとく高度に抽象化されている
  • テキストを左・右・中央に自動配置できる
  • テキストの入退室時の特殊効果を指定できる
  • スクロール処理は自動的に行う
  • 逆に派手な動きを切ってシンプルに表示することもできる
  • ハードウェアに近い操作は MD_MAX72XX にまかせている

ドキュメント

https://majicdesigns.github.io/MD_Parola/class_m_d___parola.html

抽象度のおさらい

対象 特徴
8x8ドットマトリクス 64個のLED集合体。16本の配線が必要になる
MAX7219チップ 5本の配線で済む。連結できるようになる
ドットマトリクスモジュール 上の2つを接続したもの。基板タイプだと物理的な扱いが楽になる
4連ドットマトリクスモジュール 上を4つ連結したもの。文字を流す効果が映えるようになる
MD_MAX72XX ドライバ。4連を1つの画面として扱えるようになる
MD_Parola テキスト視覚効果に特化している。ハードウェアをいじっている感覚はもうない

Hello, world!

もっともシンプルな例
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES   4

#define CLK_PIN  13
#define DATA_PIN 11
#define CS_PIN   10

MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

void setup() {
  P.begin();
  P.print("Hello, world!");
}

void loop() {
}


文字が境界を跨いでいる

疑問

3つのGPIOを使っているのにライブラリには CS_PIN しか知らされていない。CLK_PIN と DATA_PIN が使われていないのに動いているのはなぜだろう?

アニメーションの基本

void loop() {
  if (P.displayAnimate()) {
    P.displayText(
      "Hello",           // 表示文字列
      PA_LEFT,           // 目的の場所 (PA_LEFT, PA_CENTER, PA_RIGHT)
      50,                // 指定ms毎にスクロールする
      1000,              // 目的の場所に来てから指定msだけ立ち止まる
      PA_SCROLL_LEFT,    // この効果を使って来る
      PA_SCROLL_DOWN     // この効果を使って帰る
      );
  }
}
  • displayAnimate
    • 呼び続ける
    • アニメーションが終了すると true を返す
      • 開始時にも1回呼ばれている
      • なので上のコードだと繰り返される
  • displayText
    • まとめて設定できるファサードメソッド
      • 画面全体を一つの画面として捉えているときに使える
    • 効果は29種類ある

displayText を解体する

displayText("Hello", PA_LEFT, 50, 1000, PA_SCROLL_LEFT, PA_SCROLL_DOWN);
setTextBuffer("Hello");
setTextAlignment(PA_LEFT);
setSpeed(50);
setPause(1000);
setTextEffect(PA_SCROLL_LEFT, PA_SCROLL_DOWN);
displayReset();

上の2つは同じ動作になる。

スプライトデータを使う

// データは MD_Parola のサンプルより
const uint8_t F_PACKMAN = 6;  // 指定フレーム数で一周 (アニメーションの長さ)
const uint8_t W_PACKMAN = 8;  // スプライトの横幅相当
const uint8_t PROGMEM packman[F_PACKMAN * W_PACKMAN] = {
  0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
};

void loop() {
  if (P.displayAnimate()) {
    P.setSpriteData(packman, W_PACKMAN, F_PACKMAN, packman, W_PACKMAN, F_PACKMAN);
    P.displayText("Hello", PA_LEFT, 50, 1000, PA_SPRITE, PA_SPRITE);
  }
}
  • setSpriteData
    • 一つのスプライトしか使わないのであれば毎回登録する必要ない
  • スプライトは向きを持ったカーソルのような役割を果たす
  • 行き帰りで自動的に向きを変えてくれている
    • 来たときに文字を残していくのに違和感があれば帰るときだけ適用する

スプライトデータの構造

puts [0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c].collect { |e| "%08b" % e }
# 00000000
# 10000001
# 11000011
# 11100111
# 11111111
# 01111110
# 01111110
# 00111100

パックマンであれば口のある側から定義していく。

便利メソッド

メソッド 意味
setIntensity(intensity) 輝度調整 0..15
setInvert(true) 明暗を反転する

Discussion