MAX7219で8×8マトリックスLEDをドライブ
74HC595使ってみてICのコントロールが楽しかったので、今度はMAX7219を使ってみる。
ICの価格差10倍。あんまり失敗できないw
まずはArduino単体でダイレクトにマトリックスLEDを使うとこんな配線。アナログ入力PINも動員して何とか、という感じ。
アナログ入力をデジタル出力として使うとPIN14〜19になるから、PIN2〜9が行、PIN10〜17が列になるように結線してる。
あと、手元のブレッドボードだとマトリックスLEDがショートしなようにうまく刺さらなかったので、ピンソケットで浮かせて下に配線が回り込むようにしてる。使ってるマトリックスLEDはこれ。
各セルの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 0 | X | 0 | 0 | 0 | 1 |
Digit 1 | X | 0 | 0 | 0 | 0 |
Digit 2 | X | 0 | 0 | 1 | 1 |
Digit 3 | X | 0 | 1 | 0 | 0 |
Digit 4 | X | 0 | 1 | 0 | 1 |
Digit 5 | X | 0 | 1 | 1 | 0 |
Digit 6 | X | 0 | 1 | 1 | 1 |
Digit 7 | X | 1 | 0 | 0 | 0 |
Decode Mode | X | 1 | 0 | 0 | 1 |
Intensity | X | 1 | 0 | 1 | 0 |
Scan Limit | X | 1 | 0 | 1 | 1 |
Shutdown | X | 1 | 1 | 0 | 0 |
で、配線してみる。IC使っても配線の数は減らないので、このへんはあんまり楽にはならない。
Arduino側を
PIN4 | CLOCK |
PIN3 | LATCH(データシートのLOADってやつ) |
PIN2 | DATA |
とした。
ISETでLEDの明るさを調整するから間に抵抗を挟む。抵抗を10kΩにしたらめちゃめちゃ明るくなって不安なんで47kΩ以上にした。100kΩでも試したけど十分。
いつもながら分かりにくい写真。回路図とか書くことも考えないとなー。ブレッドボードの写真じゃ後に残す資料にならないね。
で、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のことがベースでよく分からない。ここを見たりして探ってみると
- スキャンリミットレジスタの初期化(読み取る桁数の指定)
- インテンシティレジスタの初期化(明るさの指定)
- デコードモードレジスタの初期化(コードBデコードを使うかどうかの指定)
- 最後にシャットダウン(というか起動?)
という感じっぽい。間違ってるかもしれん。ひとまず、分かる範囲でやってみる。
データシート見ながら以下の設定に。
インテンシティがちょっとよく分からないので、色々なサイトを参考にしつつも適当。
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ライブラリを使えば、レジスタがどうのとか考えずにもっと簡単にピコピコできるんですけどね。