Arduinoで7セグLEDシリアルドライバモジュールを使う

![ae7seg1920.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/1b423cac-af3d-f653-2703-2fd1ce33d930.jpeg)

秋月電子の [**7セグメントLEDシリアルドライバモジュール**](https://akizukidenshi.com/catalog/g/g110194/) を使うと、簡単に 7セグLED を扱えるようになります。
この記事では Arduino Nano を使用しています。配線は異なりますが、回路とプログラムは Arduino Uno にも対応しています。

Arduino 自体の使い方については他の記事をご参照ください。

# モジュールの特徴

7セグLED の点灯は各LEDごとの配線が煩雑になりがちです。さらに、複数桁を点灯させるために配線がさらに多くなり、場合によりダイナミック点灯の制御が必要になります。

これらの問題を一挙に解決するのがこのモジュールです。

- **信号線は3本のみ** : SDI, SCK, LATCH のみ
- **桁数に制限なし** : 電源が確保できればいくらでも増設可、しかも信号線は増えません
- **スタティック点灯** : 消費電流は大きいですが、原理的にちらつきがありません
- **表示中の制御の必要なし** : 表示以外にCPUリソースを割けます
- **5V, 3.3V駆動可** : ただし表示色の制限があります（後述）

# 用意するもの

|部品名|画像|はんだ付け|入手先 (参考)|
|---|:--:|---|---|
|**Arduino Nano**<br/>(Arduino UNO でも可)|<img width="240" alt="Arduino Nano" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/ff90ed3f-6be4-a534-6dbd-45beba4906d2.jpeg">|必要なし|[秋月電子](https://akizukidenshi.com/catalog/g/g109059/)<br/>[千石電商](https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4UWW) など |
|**7セグLEDシリアルドライバモジュール**<br/>完成品|<img width="240" alt="AE-7SEG-BOARD" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/a4839139-9cb3-56ed-e929-1081f430a71d.jpeg">|必要なし|秋月電子: [赤色](https://akizukidenshi.com/catalog/g/g112642/),  [緑色](https://akizukidenshi.com/catalog/g/g112570/), [青色](https://akizukidenshi.com/catalog/g/g112643/)|
|**7セグLEDシリアルドライバモジュール**<br/>DIP化キット|<img width="240" alt="AE-7SEG-BOARD" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/9c47eb38-6801-381e-3ac9-b5e34c8635be.jpeg">|**必要**|[秋月電子](https://akizukidenshi.com/catalog/g/g110360/)|
|**7セグLEDシリアルドライバモジュール**<br/>基板のみ|<img width="240" alt="AE-7SEG-BOARD" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/8849d937-3958-8587-7dfe-f4b0331ab3ff.jpeg">|**必要**|[秋月電子](https://akizukidenshi.com/catalog/g/g110194/)|

7セグLEDモジュールは必要な桁数のみご用意ください。完成品、DIP化キット、基板のみの3種が存在します。

**完成品** はやや割高ですが、はんだ付け不要ですぐに使え、赤、緑、青の3色がラインナップされています。
**DIP化キット** は部品のみのセットで、はんだ付けされていません。またキットは赤色のみです。
**基板のみ** は最安ですが、7セグLEDが同梱されていません。好みの7セグLEDを使えます。

どのセットでも表面実装部品はすでに実装済みです。

## 電源電圧

![電源電圧の注意](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/2dfa4251-0be1-16f7-18c8-656b0f0a7341.png)

7セグLEDの電源を Arduino Nano の 5V から供給すると、V<sub>F</sub> (LED の順方向電圧)が高い青色や緑色の7セグであっても問題なく点灯できます。
しかし、電源が 3.3V の場合は V<sub>F</sub> が足りず、青色や緑色は点灯しないことがあります。

7セグLEDモジュールの電源ピンと各ピンに入力する信号の H レベルは同一としてください。

## モジュールに適合する7セグLED

![適合する7セグLED](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/49d584e5-fe44-02c7-43d2-73abcd1642f8.png)

自前の 7セグLED を使用する際は **カソードコモン** 品を使用してください。7セグLEDモジュールに実装されている各セグメントの電流制限抵抗は **470Ω** です。ピン配置、寸法は図を確認してください。また、モジュールの電源電圧が LEDの V<sub>F</sub> を十分上回っているか確認してください。


# 回路

<table>
<tr>
<td>回路図</td>
<td>#</td>
<td>ピン名</td>
<td>説明</td>
</tr>
<tr>
<td rowspan="8"><img width="200" alt="AE-7SEG-BOARD" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/6166d5a8-459d-5c29-36f9-a39ac51e6906.png"></td>
<td>1, 9</td><td>VDD</td>
<td>5V または 3.3V</td>
</tr>
<tr>
<td>2, 10</td><td>GND</td>
<td>グランド</td>
</tr>
<tr>
<td>3</td><td><b>SCK</b></td>
<td><b>クロック入力</b></td>
</tr>
<tr>
<td>4</td><td><b>SDI</b></td>
<td><b>シリアル入力</b></td>
</tr>
<tr>
<td>5</td><td>SDO</td>
<td>シリアル出力</td>
</tr>
<tr>
<td>6</td><td>MR#</td>
<td>リセット</td>
</tr>
<tr>
<td>7</td><td><b>LATCH</b></td>
<td><b>ラッチ入力</b></td>
</tr>
<tr>
<td>8</td><td>OE</td>
<td>出力有効化</td>
</tr>
</table>

モジュールには 10 本のピンがあります。2本ずつある VDD と GND はどちらか1本ずつ接続すれば十分です。

1桁だけ点灯する場合は、太字で示した **SCK, SDI, LATCH** の3本のみを通信用のピンとして使います。
2桁以上の場合はさらに、**SDO** ピンを使い、次の桁の **SDI** ピンと接続します。

MR#, OE ピンは未接続で構いません。

## SPI接続の場合

<table>
<tr>
<td>回路図</td>
<td>Arduino側ピン</td>
<td>モジュール側ピン</td>
<td>説明</td>
</tr>
<tr>
<td rowspan="5"><img width="240" alt="SPI接続の場合" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/fc1b0ea8-f505-1675-3ef9-a80041009d31.png"></td>
<td>5V または 3V3</td><td>VDD</td>
<td></td>
</tr>
<tr>
<td>GND</td><td>GND</td>
<td></td>
</tr>
<tr>
<td>SCK (D13)</td><td><b>SCK</b></td>
<td><b>クロック入力</b></td>
</tr>
<tr>
<td>MOSI (D12)</td><td><b>SDI</b></td>
<td><b>シリアル入力</b></td>
</tr>
<tr>
<td>D9</td><td><b>LATCH</b></td>
<td><b>ラッチ入力</b> （どのピンでも可）</td>
</tr>
</table>

SPI の割り当てがあるピンへ SCK, SDI を接続します。LATCH は /SS （D10）以外のピンに接続してください。

## GPIO接続の場合

<table>
<tr>
<td>回路図</td>
<td>Arduino側ピン</td>
<td>モジュール側ピン</td>
<td>説明</td>
</tr>
<tr>
<td rowspan="5"><img width="240" alt="GPIO接続の場合" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/90bdfcdc-3d76-73b7-91bd-22004a30f4b0.png"></td>
<td>5V または 3V3</td><td>VDD</td>
<td></td>
</tr>
<tr>
<td>GND</td><td>GND</td>
<td></td>
</tr>
<tr>
<td>D4</td><td><b>SCK</b></td>
<td><b>クロック入力</b> （どのピンでも可）</td>
</tr>
<tr>
<td>D5</td><td><b>SDI</b></td>
<td><b>シリアル入力</b> （どのピンでも可）</td>
</tr>
<tr>
<td>D9</td><td><b>LATCH</b></td>
<td><b>ラッチ入力</b> （どのピンでも可）</td>
</tr>
</table>

SCK, SDI, LATCH はお好きなGPIOピンに接続してください。

# スケッチ

秋月電子のサイトで用意されているサンプルプログラムを参考に、専用のライブラリ [**ae7seg**](https://github.com/nanase/ae7seg) を作りました。ライブラリをインストール後、ヘッダファイル `ae7seg.h` をインクルードしてください。

```cpp
#include "ae7seg.h"
```

SPI と GPIO とでは宣言の仕方が異なるだけで、以降の関数の呼び出しは全く同じです。

## SPI接続の場合

`AE7SEGSPI` を使用してください。コンストラクタにはどのピンを LATCH として使うかを指定します。
SDI, SCK はそれぞれ、SPI の MOSI, SCK に対応します。MISO, /SS は使用しません。

```cpp
#include "ae7seg.h"

#define PIN_LATCH 9

AE7SEGSPI ae7seg(PIN_LATCH);
```

## GPIO接続の場合

`AE7SEGGPIO` を使用してください。コンストラクタにはどのピンを LATCH, SDI, SCK として使うかを指定します。

```cpp
#include "ae7seg.h"

#define PIN_SDI 5
#define PIN_SCK 4
#define PIN_LATCH 9

AE7SEGGPIO ae7seg(PIN_LATCH, PIN_SDI, PIN_SCK);
```

以下、簡略化のために `AE7SEGSPI` を使い、LATCH ピンとして 9 を指定したプログラム例を示しますが、GPIO として使う場合は適宜読み替えてください。

## 例: カウンタのスケッチ

0 から 9 までの数字を表示します。
数字を表示するには、`beginWrite()` と `endWrite()` の間に `writeNumber(number)` を呼びます。

```cpp:counter.ino
#include "ae7seg.h"

#define PIN_LATCH 9
#define INTERVAL 1000

AE7SEGSPI ae7seg(PIN_LATCH);

void setup() {}

void loop() {
  static uint16_t count = 0;

  ae7seg.beginWrite();
  ae7seg.writeNumber(count % 10);
  ae7seg.endWrite();
  delay(INTERVAL);

  count++;
}
```

書き込みに成功すると、1秒ごとに数字がカウントアップしていきます。

![counter](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/a672e681-1dd8-da3c-d0b7-d6f4f2588bef.gif)


# 発展

## 16進表示

ライブラリは16進表示にも対応しています。
実は上述のカウンタスケッチの `loop()` 関数内を以下のように変更すると、

```cpp:hex_counter.ino
void loop() {
  static uint16_t count = 0;

  ae7seg.beginWrite();
  ae7seg.writeNumber(count % 16);  // <- 0 から 15 が入るように修正
  ae7seg.endWrite();
  delay(INTERVAL);

  count++;
}
```

0 から F までカウントアップするようになります。

![hexcounter](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/2597e1bc-df36-dbef-4b65-db752c7ead3e.gif)


## 複数桁表示

複数桁の表示にも対応しています。物理的スペースや電源の確保ができれば桁数の制限はありません。
`beginWrite()` と `endWrite()` の間に、必要な桁数分だけ `writeNumber(number)` を呼び出すだけです。
ただし、必ず上位桁から呼び出す点に注意してください。

```cpp:multi_digit.ino
void loop() {
  ae7seg.beginWrite();
  ae7seg.writeNumber(4);  // 上位桁
  ae7seg.writeNumber(2);  // 下位桁
  ae7seg.endWrite();
}
```

42 と表示されます。

![42](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/aa18efa0-48b0-ccdb-8ca3-e9f039ebf2d7.jpeg)

## ドットセグメント表示

もちろんドットの表示にも対応しています。
`writeNumber(number, true)` を使ってください。第二引数を指定しない場合は暗黙的にドットが非表示となります。

```cpp:dot_segment.ino
void loop() {
  ae7seg.beginWrite();
  ae7seg.writeNumber(4, true);  // 上位桁, ドット表示あり
  ae7seg.writeNumber(2);        // 下位桁, ドット表示なし
  ae7seg.endWrite();
}
```

4.2 と表示されます。

![4.2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/edfc1547-6478-6548-2ed3-efb076800fab.jpeg)

## 1/100秒タイマー

複数桁とドット表示を応用したタイマーを作ります。
モジュールを4つ使用した 1/100 秒（疑似）タイマーです。2桁目にドットを表示しています。

```cpp:timer.ino
#define INTERVAL 10

void loop() {
  static uint16_t count = 0;

  ae7seg.beginWrite();
  {
    if (count >= 1000)
      ae7seg.writeNumber((count / 1000) % 10);
    else
      ae7seg.clear();

    ae7seg.writeNumber((count / 100) % 10, true);
    ae7seg.writeNumber((count / 10) % 10);
    ae7seg.writeNumber(count % 10);
  }
  ae7seg.endWrite();
  delay(INTERVAL);

  count++;

  if (count >= 10000)
    count = 0;
}
```

`clear()` は全セグメントを消灯する関数です。0〜10秒までの最上位桁の消灯に使っています。

![timer](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/9a729dda-f260-a833-5a08-60439fcf0b2f.gif)


## 任意のセグメントの表示

`writeDigit(digit)` を使うと、数字以外のセグメントの表示が行なえます。引数の `digit` には8ビット整数を指定し、上位7ビットが7つのセグメントA〜G、残りの下位1ビットがドットセグメントDPに対応しています。各ビットにおいて、`0` のとき消灯、`1` のとき点灯します。

```cpp:animation.ino
#define INTERVAL 100

const uint8_t FRAME[] PROGMEM = {
  0b10000000,
  0b01000000,
  0b00000010,
  0b00001000,
  0b00010000,
  0b00100000,
  0b00000010,
  0b00000100,
};

void loop() {
  for (uint8_t i = 0; i < sizeof(FRAME); i++) {
    ae7seg.beginWrite();
    ae7seg.writeDigit(pgm_read_byte_near(FRAME + i));
    ae7seg.endWrite();
    delay(INTERVAL);
  }
}
```

![animation](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/7741c93b-8866-4593-c146-a0fd74320919.gif)

# 参考

- [**秋月電子 7セグメントLEDシリアルドライバモジュール 組立説明書**](https://akizukidenshi.com/catalog/g/g110194/)<br/>
   https://akizukidenshi.com/catalog/g/g110194/