ArduinoでLEDマトリクスを点灯させてみる

最近はコロナのせいで余計家からでなくなり、鬱気味の僕です。
昔から電子回路について興味があり、Arduinoなどをちょこっと触っていたのですが、飽きやすい性格なので電子パーツなど部屋の隅に眠らせていました。
ということで、今回は眠らせていたArduinoとシフトレジスタを使い、LEDマトリクスを光らせて行きたいと思います。
自分は電子工作初心者なので、間違っている部分が多々あると思いますがご了承ください。

# 必要なもの

### Arduino
こちらはArduino nanoの互換機で、[Amazon](https://www.amazon.co.jp/ELEGOO-Arduino-Nano%E3%83%9C%E3%83%BC%E3%83%89-ATmega328P%E3%80%81Arduino-V3-0%E4%BA%92%E6%8F%9B/dp/B072F5NS4X/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=arduino+nano&qid=1607483309&s=industrial&sr=1-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUExSk9XOFFZN1c1SlRUJmVuY3J5cHRlZElkPUEwNTkzMjE3M1NCSVY3UERGWTBVSyZlbmNyeXB0ZWRBZElkPUExOEM0TTdBUUZXR0FZJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==)で3個1500円ほどです。
Arduino nanoと同じように扱えます。
詳しい仕様については今回は割愛します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/a97eb3e3-5037-effd-aded-1643a821f623.jpeg" width="50%">

### シフトレジスタ
74HC595APというシフトレジスタです。
シフトレジスタとはシリアル信号をパラレル信号に変換してくれるものです。
例えば8bitのシリアル信号を一つのピンに入力すると、各bitの値が8個のピンそれぞれから出力されるイメージです。
今回の規模だとArduino側のOUTPUTピンの数でことは足りますが、シフトレジスタの動きを理解したい為あえて使用します。
詳しい使い方は[こちら](https://stupiddog.jp/note/archives/1152)が参考になると思います。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/00a217a8-83e1-9ce0-c9d9-aeb2faf3c323.jpeg" width="50%">
簡単なイメージです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/8e14d19c-bad9-ca0c-551b-f58791c0686f.jpeg" width="50%">

### LEDマトリクス
昔使っていたLED時計から拝借したものです。
5x7のLEDがついています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/4fce5a5b-d20e-aaf1-9b59-240f6d44cd0c.jpeg" width="50%">
LEDマトリクスの裏には14個のピンがついており、丸がついた数字がアノードコモンとなっています。（左の図）
各ピンがどのLEDに対応しているかは右の図に表わしています。
2,10,4(11),5,13は縦方向に対応しており、6,1,7,3(12),8,14,9は横方向に対応しています。
たとえば10のピンに信号を送り、7のピンをGNDに接続した場合その交差するLEDがつきます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/2068ad71-fcc9-847e-e36b-296bc65ebf30.jpeg" width="50%">
しかし以下の場合はどうでしょう。
星のついたLEDを点灯したい場合、アノード側は10,4、カソード側は7,3となります。
一度に点灯させようとすると、4つのLEDが点灯してしまいます。
解決策としてはダイナミック点灯と呼ばれる点灯方式を使います。
横方向か縦方向一列ずつを順次に瞬間的に点灯させることで不要なLEDを点灯させないようにできます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/21377821-0fde-e60e-1aeb-46cd2bba80b0.jpeg" width="50%">
以下がダイナミック点灯のイメージです。
横方向一列を上から順に点灯させています。
わかりやすいようにディレイを入れていますが、ディレイをなくすと同じタイミングでLEDが点灯しているように見えます。
![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/885c83db-2acb-82f5-f70f-6cc6cd89f38e.gif)

# 実装する
以下のように各ピンを接続しています。
・ArduinoのD2ピン -> シフトレジスタのSRCLKピン
・ArduinoのD3ピン -> シフトレジスタのRCLKピン
・ArduinoのD5ピン -> シフトレジスタのSERピン
・ArduinoのD13,A0からA5ピン -> LEDマトリクスの各カソード側
・シフトレジスタのVCCピン -> Arduinoの5Vピン
・シフトレジスタのSRCLRピン -> Arduinoの5Vピン
・シフトレジスタのOEピン -> ArduinoのGNDピン
・シフトレジスタのGNDピン -> ArduinoのGNDピン
・シフトレジスタのQAからQEピン -> LEDマトリクスの各アノード側
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/752e48e4-38ae-f769-55a5-701849878034.jpeg" width="50%">

# コードを書く
今回はLEDマトリクスの横方向一列を上から順に点灯させていくため、カソード側と接続したArduino側のピンをHIGH（5V), LOW(0V, GND)を切り替えて制御していきます。

```
// シフトレジスタと繋いだピン
const int PIN_SRCLK = 2;
const int PIN_RCLK  = 3;
const int PIN_SER   = 5;

// LEDマトリクスのカソード側と繋いだピン
const int PIN_ROW_1 = 14;
const int PIN_ROW_2 = 15;
const int PIN_ROW_3 = 16;
const int PIN_ROW_4 = 17;
const int PIN_ROW_5 = 18;
const int PIN_ROW_6 = 19;
const int PIN_ROW_7 = 13;

// LED点灯パターン
const byte patterns[] = {
  B10101000,
  B01010000,
  B10101000,
  B01010000,
  B10101000,
  B01010000,
  B10101000,
};

const int rows[] = {
  PIN_ROW_1,
  PIN_ROW_2,
  PIN_ROW_3,
  PIN_ROW_4,
  PIN_ROW_5,
  PIN_ROW_6,
  PIN_ROW_7,
};

void setup() {
  pinMode(PIN_SRCLK, OUTPUT);
  pinMode(PIN_RCLK,  OUTPUT);
  pinMode(PIN_SER,   OUTPUT);
  pinMode(PIN_ROW_1, OUTPUT);
  pinMode(PIN_ROW_2, OUTPUT);
  pinMode(PIN_ROW_3, OUTPUT);
  pinMode(PIN_ROW_4, OUTPUT);
  pinMode(PIN_ROW_5, OUTPUT);
  pinMode(PIN_ROW_6, OUTPUT);
  pinMode(PIN_ROW_7, OUTPUT);

　// カソード側を全てHIGHで初期化（点灯させないように）
  digitalWrite(PIN_ROW_1,  HIGH);
  digitalWrite(PIN_ROW_2,  HIGH);
  digitalWrite(PIN_ROW_3,  HIGH);
  digitalWrite(PIN_ROW_4,  HIGH);
  digitalWrite(PIN_ROW_5,  HIGH);
  digitalWrite(PIN_ROW_6,  HIGH);
  digitalWrite(PIN_ROW_7,  HIGH);
}

void loop() {
  for(int i = 0; i < 7; i++) {
    // ラッチをLOWにする
    digitalWrite(PIN_RCLK, LOW);
    // シリアル信号を送信
    shiftOut(PIN_SER, PIN_SRCLK, LSBFIRST, patterns[i]);
    // 対象の行のカソードをGNDにする
    digitalWrite(rows[i], LOW);
    // ラッチをHIGHにすることでLEDに信号がおくられる
    digitalWrite(PIN_RCLK, HIGH);
    // ディレイを入れないと点灯から消灯まで短すぎて、正常に表示されない
    delay(1);
    // 対象の行のカソードをHIGHにすることで消灯させる
    digitalWrite(rows[i], HIGH);
  }
}
```

# 動作させてみる
正常に動きました！
今流行りの市松模様です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323720/48a32444-98d4-ade1-7215-a6781b765017.jpeg" width="50%">

# おわりに
電子回路の知識ナシでシフトレジスタを触るべきではないと思いました。
一応動作はしましたが、シフトレジスタの詳しい仕様や動作などは理解していません。
しかし電子工作の楽しさは分かったので、基礎から少しづつ勉強していけたらなと思っています。