編集履歴一覧に戻る
Nyanrakaのアイコン画像

Nyanraka が 2026年01月31日23時38分52秒 に編集

初版

タイトルの変更

+

SPRESENSEで制御する7セグメントディスプレイの制作

タグの変更

+

7セグメントLED

+

SPRESENSE

+

Arduino-IDE

+

Python

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

製作品

ライセンスの変更

+

(MIT) The MIT License

本文の変更

+

## はじめに 7セグメントLEDは数字の表示に用いられていますが、複数個を組み合わせることで画像や任意のパターン表示を行うことも可能です。 本記事では、SPRESENSEを用いて多数の7セグメントLEDを制御し、画像データや自作パターンを大型ディスプレイとして表示する装置を制作したので、その構成と実装方法について紹介します。 ## システム構成 本システムの構成図を以下に示します. PCで表示したいデータを作成したあとにSPRESENSEよりデータを7セグメントLED制御基板へ送信します. ![システム構成](https://camo.elchika.com/c43c384052acf90149226cf347400dbc16987e51/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f30333830626366382d313334362d346564302d613535342d353034623263626362323761/) ## ハードウェア構成 ### 基板構成 制御はSPRESENSEのメインボードと拡張ボードを使用して制御しました。 7セグメントディスプレイは縦8個 × 横8個、合計128個の7セグメントLEDを実装することで作製しました。 各7セグメントLEDは、シリアル接続されたシフトレジスタによって制御されます。 Autodesk EAGLEで制御基板データを作成し、JLCPCB様に発注しました。 ![回路図](https://camo.elchika.com/bbb28e32c4fb81e9442239d957f531a089ec870a/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f32393637633965342d393530302d346138662d396363392d353230313031363861646137/) ![PCB図](https://camo.elchika.com/641bc749069d808808dcf9ce74bdd24953f163a2/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f65313966616339302d363865622d343332362d623432342d636665346535633965396336/) ![基板表面](https://camo.elchika.com/c70e148625a1e7c5066ce42917e520e96313f46d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f63373862613037392d653633632d346364632d386630322d346631366636306332343664/) ![基板裏面](https://camo.elchika.com/28c779449fbf6079e0a57123457df54c193879a3/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f61643937653139382d613264302d343161312d613462652d376435346361383566623532/) --- ### 制御方式 表示方式はダイナミック点灯を採用しました。 今回用いた7セグメントLEDはカソードコモンです。アノードは1つのセグメントあたり8本あり、行ごとにまとめてシフトレジスタの出力端子に接続しました。また,カソードは列ごとにまとめてトランジスタに接続しました。 カソード制御には合計で8個のトランジスタをシフトレジスタでスイッチング動作させて,制御しました。一般的なドットマトリクスと同じように、網目状に光らせたい7セグメントLEDを光らせることが可能です。 下図に制御基板の一部構成を示します。 ![制御基板構成](https://camo.elchika.com/deacbdaef795ed49cd0cf5fe25597d166ca87422/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f30363265396165312d653630312d346538622d613464382d363761373633336162383038/) 今回は左端の列から順にデジットをダイナミック点灯することで7セグメントLEDを制御しました。 以下に表示する手順を示します。 1. アノード側のシフトレジスタに一番左の列に表示したいシリアルデータを送信します。 2. カソード側のトランジスタアレイを1列だけ(今回は一番左の列)onすることで、一番左側の列を光らせることができます。 上記手順を高速に左端から右端まで行うことで、7セグメントディスプレイに好きなパターンを表示することができます。 --- ### ジグ基板の設計 LED制御用の基板は4つの基板を配線で接続して制御しました。 制御にはSPI通信を使用したのですが、CLK信号の劣化が確認されたため、NOT素子を2個用いたバッファ回路を挿入しました。 また制御基板用の電源回路も搭載しました。 ![ジグ基板](https://camo.elchika.com/773fddcf0e7750d4599217c608af7300e93fa8fa/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f33656566346637652d336234302d343161392d613037382d373633383066376337636263/) --- ### 部品表 最後に使用した部品を以下に示します. | 部品名 | 機能 | 入手先 | |---|---|---| | Spresense メインボード | マイコンボード | ご提供品 | | Spresense 拡張基板 | マイコンボード | ご提供品 | | TC74HC595AF | シフトレジスタ | 秋月電子 | | TBD62083AFG | トランジスタアレイ | 秋月電子 | | NJM7805FA | 3端子レギュレータ | 秋月電子 | | 抵抗/コンデンサ | 受動部品 | 秋月電子 | ### 基板データ 基板データは[こちら](https://github.com/Nanraka/7-segment-LED-display.git)で公開しています. --- ## ソフトウェア構成 SWの構成図とデータ処理のフローを以下に示します。 今回はPythonを使用してデータの前処理をした後に、SPRESENSEを使用してコードを制御基板に送信しました。 ![SW構成](https://camo.elchika.com/ef9822bdb9cdad641377ff89839fbc0841b29404/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f66373034333536372d313933392d346330302d613665322d616164323639363236336163/) --- ### 表示パターン生成 表示パターンは以下の2通りで作成しました。 #### 1. 画像データから生成 任意の画像を7セグメントディスプレイの画素数へとリサイズし画像を2値化することで点灯/非点灯を表現しました。 #### 2. 自作パターン Excel上で7セグメントのデジット配置を作成し、光らせたい部分を「1」、消灯させたい部分を「0」とすることで、任意の表示パターンを作成しました。 --- ### シリアルデータの加工 デジット配置を示すマスクバイナリデータを用意し,表示パターンとANDをとることで必要な部分のみを抽出し、シリアルデータとして連結します。 加工したシリアルデータをmicroSDカードにテキストファイルとして保存し、SPRESENSEより読み出すことで使用しました。 ![表示用データの作成](https://camo.elchika.com/bba05d7a2a93e37780d2524943ea0302156fb706/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f39653230383664372d646332392d343336352d626132332d323561646330333939363832/) --- ### データ送信処理 SPRESENSEより読み出したデータは、LSBファーストで送信端から最も遠いシフトレジスタから順に送信します。 送信後、列単位でカソードをオンしてダイナミック点灯します。 --- ### 作成したコード 完成したコードのうち主要なものを以下に示します. ```C:SPRESENSEでの処理 #include <SDHCI.h> #include <File.h> #include <SPI.h> #define DATA_SIZE 2560 #define ROW_SIZE 8 // 1列当たりの7セグメントLEDの数 #define GROUP_SIZE 64 // 1セットあたりの7セグメントLEDの数 #define GROUP_COUNT 2 // セット数 #define LOOP_COUNT 8 uint8_t rowData[DATA_SIZE]; uint8_t sendData[DATA_SIZE]; SDClass SD; const int DATA_LATCH_PIN = 9; const int TRAN_LATCH_PIN = 3; const int OE_PIN = 1; int tran_pos = 0; uint8_t cathode_data = 0x80; void sendToShiftRegister(int loop) { // 最後のレジスタ分から送る for (int group = GROUP_COUNT; group > 0; group--) { // 列方向の遷移 下から上に上がっていく for (int offset = 0; offset < ROW_SIZE; offset++) { int index = group*GROUP_SIZE - offset - (loop * ROW_SIZE) - 1; SPI.transfer(sendData[index]); } } } void packBitsToBytes() { for (int byteIndex = 0; byteIndex < (DATA_SIZE/8); byteIndex++) { uint8_t value = 0; // 1バイトにする for (int bit = 0; bit < 8; bit++) { value <<= 1; // MSBから詰める value |= (rowData[byteIndex * 8 + bit] & 0x01); } sendData[byteIndex] = value; } } void setup() { Serial.begin(115200); while (!Serial); // SD初期化 if (!SD.begin()) { Serial.println("SD init failed"); return; } File file = SD.open("hi.txt"); if (!file) { Serial.println("File open failed"); return; } int idx = 0; while (file.available() && idx < DATA_SIZE) { char c = file.read(); if (c == '0' || c == '1') { rowData[idx++] = c - '0'; } } file.close(); Serial.print("Loaded: "); Serial.println(idx); packBitsToBytes(); // SPI初期化 SPI.begin(); SPI.beginTransaction(SPISettings(8000000, LSBFIRST, SPI_MODE0)); // ピン設定 pinMode(DATA_LATCH_PIN, OUTPUT); pinMode(TRAN_LATCH_PIN, OUTPUT); pinMode(OE_PIN, OUTPUT); digitalWrite(DATA_LATCH_PIN, HIGH); digitalWrite(TRAN_LATCH_PIN, HIGH); digitalWrite(OE_PIN, HIGH); } void loop() { digitalWrite(OE_PIN, HIGH); for (int loopCount = 0; loopCount < LOOP_COUNT; loopCount++) { digitalWrite(DATA_LATCH_PIN, LOW); digitalWrite(TRAN_LATCH_PIN, HIGH); sendToShiftRegister(loopCount); digitalWrite(DATA_LATCH_PIN, HIGH); digitalWrite(TRAN_LATCH_PIN, LOW); //uint8_t data = (0x80 >> tran_pos); SPI.transfer(cathode_data); digitalWrite(DATA_LATCH_PIN, HIGH); digitalWrite(TRAN_LATCH_PIN, HIGH); digitalWrite(OE_PIN, LOW); tran_pos += 1; cathode_data = cathode_data >> 1; if (tran_pos >= 8){ tran_pos = 0; cathode_data = 0x80; } delay(2); // 出力更新周期 } } ``` ```Python:ディスプレイ用データの作成 import csv # ========================= # 1. CSV読み込み関数 # ========================= def load_1column_csv(path): data = [] with open(path, "r") as f: reader = csv.reader(f) for row in reader: if len(row) == 0: continue data.append(int(row[0])) return data # ========================= # 2. 64要素ブロックごとに並び替える関数 # ========================= def reorder_by_64_blocks(data): BLOCK = 64 ORDER_64 = [ 40, 0, 17, 16, 56, 41, 18, 1, 42, 2, 20, 19, 57, 43, 21, 3, 44, 4, 23, 22, 58, 45, 24, 5, 46, 6, 26, 25, 59, 47, 27, 7, 48, 8, 29, 28, 60, 49, 30, 9, 50, 10, 32, 31, 61, 51, 33, 11, 52, 12, 35, 34, 62, 53, 36, 13, 54, 14, 38, 37, 63, 55, 39, 15 ] assert len(data) % BLOCK == 0, "配列長は64の倍数である必要があります" reordered = [] for base in range(0, len(data), BLOCK): block = data[base:base + BLOCK] reordered.extend(block[i] for i in ORDER_64) return reordered # ========================= # 3. ファイルパス # ========================= MASK_CSV_PATH = "mask_data.csv" INPUT_CSV_PATH = "serial_data.csv" OUTPUT_CSV_PATH = "output.csv" # ========================= # 4. データ読み込み # ========================= MASK_DATA = load_1column_csv(MASK_CSV_PATH) input_data = load_1column_csv(INPUT_CSV_PATH) # ========================= # 5. サイズチェック # ========================= assert len(MASK_DATA) == 8000, "MASK_DATAは8000要素である必要があります" assert len(input_data) == 8000, "input_dataは8000要素である必要があります" # ========================= # 6. AND演算 # ========================= and_result = [ input_data[i] & MASK_DATA[i] for i in range(8000) ] # ========================= # 7. MASK_DATAが1の要素のみ抽出 # ========================= extracted_data = [ and_result[i] for i in range(8000) if MASK_DATA[i] == 1 ] # ========================= # 8. 並べ替え # ========================= result = reorder_by_64_blocks(extracted_data) # ========================= # 9. TXT出力 # ========================= with open("output.txt", "w") as f: for v in result: f.write(f"{v}¥n") # ========================= # 10. CSV出力 # ========================= with open("output.csv", "w", newline="") as f: writer = csv.writer(f) for v in result: writer.writerow([v]) # ========================= # 11. 結果表示 # ========================= print("処理完了") print(f"MASK_DATAの1の数 : {sum(MASK_DATA)}") print(f"抽出されたデータ数 : {len(extracted_data)}") ``` Pythonコード、SPRESENSEのコードの詳細は[こちら](https://github.com/Nanraka/7-segment-LED-display.git)を参照してください。 --- ## 完成品 こちらが完成した作品です。 ![完成品](https://camo.elchika.com/a29eb4b1c8e8cb82067af6ee1a5137457765560a/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f66303038656462352d393565632d346232332d626637342d323036626662366564616231/) 完成した装置が動作している様子を示します。 しっかりと表示したいパターンを視認することができました! ![動作中の様子](https://camo.elchika.com/79aea3a142132437532d5e08c8eee039b2dd03dd/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f39376433316264622d373132332d346435392d386536302d3663663234326163366633322f33333863333636312d613139312d343835632d623130302d396536613730386166386232/) --- ## 今後の展望 今後は以下に対応し、より表現力の高い表示装置へ発展させたいと考えています。 - 動画表示への対応(SPRESENSEのメインコアでmicroSD通信、サブコアで表示処理) - 桁数の増加 - 筐体作製(できればカバンや工具箱など身の回りのものに搭載し,使える作製物にしたいです)