MAX7219で8×8マトリックスLEDをドライブ

DSC09502


74HC595使ってみてICのコントロールが楽しかったので、今度はMAX7219を使ってみる。
ICの価格差10倍。あんまり失敗できないw


まずはArduino単体でダイレクトにマトリックスLEDを使うとこんな配線。アナログ入力PINも動員して何とか、という感じ。
アナログ入力をデジタル出力として使うとPIN14〜19になるから、PIN2〜9が行、PIN10〜17が列になるように結線してる。
あと、手元のブレッドボードだとマトリックスLEDがショートしなようにうまく刺さらなかったので、ピンソケットで浮かせて下に配線が回り込むようにしてる。使ってるマトリックスLEDはこれ


DSC09419


各セルのLEDの点灯/消灯は以下のロジックになってる。

LED
LOW LOW 消灯
LOW HIGH 消灯
HIGH HIGH 消灯
HIGH LOW 点灯

行を常にHIGHにしておいて、列をLOWにして点灯/HIGHで消灯にすればいいから、配列に各セルの状態を指定しておいて

boolean matrix[8][8] = {
  {0, 0, 0, 0, 1, 1, 1, 1},
  {0, 0, 0, 0, 1, 1, 1, 1},
  {0, 0, 0, 0, 1, 1, 1, 1},
  {0, 0, 0, 0, 1, 1, 1, 1},
  {1, 1, 1, 1, 0, 0, 0, 0},
  {1, 1, 1, 1, 0, 0, 0, 0},
  {1, 1, 1, 1, 0, 0, 0, 0},
  {1, 1, 1, 1, 0, 0, 0, 0},
};

for(int i=2; i<=9; i++){
    digitalWrite(i, HIGH);

    for(int j=10; j<=17; j++){
      digitalWrite(j, !matrix[i-2][j-10]);
      delay(100);
      digitalWrite(j, HIGH);
    }

    digitalWrite(i, LOW);
}

とかやれば、わりと直感的に描画できる。
文字記号のbitパターンとかどっかで拾ってくれば、これでも十分遊べる。


ただ、結論から言うとMatrixライブラリとSpriteライブラリのほうが直感的で使い勝手がいいのでMAX7219オススメ。
そんなわけでMAX7219を使いたいんだけど、いきなりライブラリで楽しちゃうと面白くないので、まずはデータシートを見てみる。

PIN1 DIN(16bitシリアルデータの入力)
PIN2, 3, 5, 6, 7, 8, 10, 11 DIG 0–DIG 7(アノード側)
PIN12 LOAD(HIGHでlatch)
PIN13 CLK(CLOCK、HIGHでシフトレジスタにシフト)
PIN14〜17, 20〜23 SEG A–SEG G, DP(カソード側)
PIN18 ISET(抵抗値で明るさの調整)

とある。あとは電源とGNDとか。

LOADとCLOCKは前回の74HC595と同じなので迷わない。
DINが16bitで、D0〜7はデータ(MSB)。D8〜11はレジスタのアドレス。それ以降は無効bit。

16bitのシリアルデータフォーマット

D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
MSB X X X REGISTER ADDRESS (←MSB) DATA (LSB→)

レジスタのアドレス

REGISTER D15-12 D11 D10 D9 D8
No-Op X 0 0 0 0
Digit 0X0001
Digit 1X0000
Digit 2X0011
Digit 3X0100
Digit 4X0101
Digit 5X0110
Digit 6X0111
Digit 7X1000
Decode ModeX1001
IntensityX1010
Scan LimitX1011
ShutdownX1100


で、配線してみる。IC使っても配線の数は減らないので、このへんはあんまり楽にはならない。

Arduino側を

PIN4 CLOCK
PIN3 LATCH(データシートのLOADってやつ)
PIN2 DATA

とした。

ISETでLEDの明るさを調整するから間に抵抗を挟む。抵抗を10kΩにしたらめちゃめちゃ明るくなって不安なんで47kΩ以上にした。100kΩでも試したけど十分。


DSC09501 DSC09504

いつもながら分かりにくい写真。回路図とか書くことも考えないとなー。ブレッドボードの写真じゃ後に残す資料にならないね。


で、ShiftOutするんだけど引数が16bitでMSBなところ以外は595のときに基本的に同じ手順。

updateLED(384);//000110000000

void updateLED(int val) {
  digitalWrite(LATCH, LOW);
  
  shiftOut(DATA, CLOCK, MSBFIRST, val);

  digitalWrite(LATCH, HIGH);
  delay(1);
  digitalWrite(LATCH, LOW);
}

これで端っこのLEDが点灯するんだけど、先に動かしたスケッチの状態が残ってたりして正しく動かないときがあった。
どうやら各レジスタの初期化をしないといけないっぽい。

データシート見ても7セグLEDのことがベースでよく分からない。ここを見たりして探ってみると

  1. スキャンリミットレジスタの初期化(読み取る桁数の指定)
  2. インテンシティレジスタの初期化(明るさの指定)
  3. デコードモードレジスタの初期化(コードBデコードを使うかどうかの指定)
  4. 最後にシャットダウン(というか起動?)

という感じっぽい。間違ってるかもしれん。ひとまず、分かる範囲でやってみる。


データシート見ながら以下の設定に。
インテンシティがちょっとよく分からないので、色々なサイトを参考にしつつも適当。

SCAN LIMIT D2 D1 D0
Display digits 0 1 2 3 4 5 6 7 1 1 1
INTENSITY DUTY CYCLE D2 D3 D1 D0
25/32 1 1 0 0
DECODE MODE D7 D6 D5 D4 D3 D2 D1 D0
No decode for digits 7–0 0 0 0 0 0 0 0 0
SHUTDOWN MODE D7 D6 D5 D4 D3 D2 D1 D0
Normal Operation 0 0 0 0 0 0 0 0
void setup() {
  pinMode(CLOCK, OUTPUT);
  pinMode(LATCH, OUTPUT);
  pinMode(DATA,  OUTPUT);
  initLED();
  clearLED();
}

void initLED() {
  updateLED(0x0B07);
  updateLED(0x0A0C);
  updateLED(0x0900);
  updateLED(0x0C01);
}


あとは、byte matrix[8]とか作ってビットシフトしながらゴニョゴニョやれば・・・という感じなんだけど。
素人がデータシート見ながら試行錯誤した結果なんで間違ってるところも多々ある。はず。
まぁ、Matrixライブラリを使えば、レジスタがどうのとか考えずにもっと簡単にピコピコできるんですけどね。