注釈

FacebookのSunFounder Raspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ!Raspberry Pi、Arduino、ESP32についての知識を深め、同じ趣味を持つ仲間と交流しましょう。

なぜ参加するのか?

  • 専門的なサポート: コミュニティとチームの支援を受けて、販売後の問題や技術的な課題を解決します。

  • 学びと共有: ヒントやチュートリアルを交換してスキルを向上させましょう。

  • 独占的なプレビュー: 新製品の発表や先行プレビューに早期アクセスが可能です。

  • 特別な割引: 最新製品の独占的な割引を楽しみましょう。

  • 祭りのプロモーションとギブアウェイ: ギブアウェイや休日のプロモーションに参加しましょう。

👉 私たちと一緒に探索し、創造しませんか?[こちら]をクリックして今すぐ参加してください!

5.3 4桁7セグメントディスプレイで時間カウンターを作成する

このレッスンでは、 4桁7セグメントディスプレイ を使用して、Raspberry Pi Pico 2 でシンプルな時間カウンターを作成する方法を学びます。ディスプレイは1秒ごとにカウントアップし、経過秒数を表示します。

必要なもの

このプロジェクトでは、以下のコンポーネントが必要です。

以下のリンクからキットを購入すると便利です。

名称

このキットに含まれるアイテム

リンク

Newton Lab Kit

450+

Newton Lab Kit

また、以下のリンクから個別に購入することもできます。

番号

コンポーネント

数量

リンク

1

Raspberry Pi Pico 2

1

購入

2

Micro USB ケーブル

1

3

ブレッドボード

1

購入

4

ジャンパーワイヤー

数本

購入

5

抵抗器

4(220Ω)

購入

6

4桁7セグメント表示

1

7

74HC595

1

購入

4桁7セグメントディスプレイの理解

4桁7セグメントディスプレイは、4つの個別の7セグメントディスプレイが1つのモジュールに統合されたものです。各桁は同じセグメント制御ライン( ag および dp )を共有しますが、各桁には独自の 共通カソード 制御があります。この構成により、どの桁をアクティブにするかを制御できます。

異なる数字を各桁に表示するためには、 マルチプレクシング という技術を使用します。これは、桁ごとに高速で切り替えて更新することで、すべての桁が同時に表示されているように見せる技術です。これは視覚残像の原理を利用したものです。

4digit_control_pins

回路図

sch_4dig

この回路の配線の基本原理は 5.1 74HC595シフトレジスタの使用方法 とほぼ同じですが、異なる点は、Q0~Q7が4桁7セグメントディスプレイのa~gピンに接続されることです。

さらに、G10~G13は、どの7セグメントディスプレイを動作させるかを制御します。

配線図

wiring_4dig

  • セグメント接続(220Ω抵抗を通して):

    • Q0 → セグメント a

    • Q1 → セグメント b

    • Q2 → セグメント c

    • Q3 → セグメント d

    • Q4 → セグメント e

    • Q5 → セグメント f

    • Q6 → セグメント g

    • Q7 → セグメント **dp**(小数点)

  • 共通カソード接続(桁選択ピン):

    • 桁1(左端桁): GP10 に接続

    • 桁2: GP11 に接続

    • 桁3: GP12 に接続

    • 桁4(右端桁): GP13 に接続

コードの記述

注釈

  • 5.3_time_counter.inonewton-lab-kit/arduino/5.3_time_counter フォルダから開くことができます。

  • または、以下のコードを Arduino IDE にコピーしてください。

  • Raspberry Pi Pico 2 ボードを選択し、適切なポートを選択して「アップロード」をクリックしてください。

// Define the connection pins for the shift register
#define DATA_PIN 18   // DS (Serial Data Input)
#define LATCH_PIN 19  // STCP (Storage Register Clock)
#define CLOCK_PIN 20  // SHCP (Shift Register Clock)

// Define the digit control pins for the 4-digit 7-segment display
const int digitPins[4] = { 10, 11, 12, 13 };  // DIG1, DIG2, DIG3, DIG4

// Segment byte maps for numbers 0-9
const byte digitCodes[10] = {
  // Pgfedcba
  0b00111111,  // 0
  0b00000110,  // 1
  0b01011011,  // 2
  0b01001111,  // 3
  0b01100110,  // 4
  0b01101101,  // 5
  0b01111101,  // 6
  0b00000111,  // 7
  0b01111111,  // 8
  0b01101111   // 9
};

unsigned long previousMillis = 0;  // Stores the last time the display was updated
unsigned int counter = 0;          // Counter value

void setup() {
  // Initialize the shift register pins
  pinMode(DATA_PIN, OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);

  // Initialize the digit control pins
  for (int i = 0; i < 4; i++) {
    pinMode(digitPins[i], OUTPUT);
    digitalWrite(digitPins[i], HIGH);  // Turn off all digits
  }
}

void loop() {
  unsigned long currentMillis = millis();

  // Update the counter every 1000 milliseconds (1 second)
  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    counter++;  // Increment the counter
    if (counter > 9999) {
      counter = 0;  // Reset counter after 9999
    }
  }

  // Display the counter value
  displayNumber(counter);
}

void displayNumber(int num) {
  // Break the number into digits
  int digits[4];
  digits[0] = num / 1000;        // Thousands
  digits[1] = (num / 100) % 10;  // Hundreds
  digits[2] = (num / 10) % 10;   // Tens
  digits[3] = num % 10;          // Units

  // Display each digit
  for (int i = 0; i < 4; i++) {
    digitalWrite(digitPins[i], LOW);  // Activate digit
    shiftOutDigit(digitCodes[digits[i]]);
    delay(5);                          // Small delay for multiplexing
    digitalWrite(digitPins[i], HIGH);  // Deactivate digit
  }
}

void shiftOutDigit(byte data) {
  // Send data to the shift register
  digitalWrite(LATCH_PIN, LOW);
  shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, data);
  digitalWrite(LATCH_PIN, HIGH);
}

コードをアップロードすると、4桁7セグメントディスプレイが「0000」からカウントを開始し、1秒ごとに1ずつ増加します。 カウントの進行は次のようになります:0000、0001、0002、...、9999、その後0000にリセットされます。

コードの理解

  1. 制御ピンの定義:

    • DATA_PIN (DS): 74HC595にシリアルデータを送信

    • LATCH_PIN (STCP): シフトレジスタのデータを出力ピンに固定

    • CLOCK_PIN (SHCP): シフトレジスタへのデータ送信を制御

    #define DATA_PIN   18  // DS (シリアルデータ入力)
    #define LATCH_PIN  19  // STCP (ストレージレジスタクロック)
    #define CLOCK_PIN  20  // SHCP (シフトレジスタクロック)
    
  2. 桁制御ピンの定義:

    • 各桁の共通カソードは個別のGPIOピンに接続されます。

    • LOW に設定するとその桁が有効になり、HIGH で無効になります。

    const int digitPins[4] = {10, 11, 12, 13}; // DIG1, DIG2, DIG3, DIG4
    
  3. セグメントのバイトマップ作成:

    • 各バイトは、共通カソードの7セグメントディスプレイに表示する数字 (0~9) のセグメントを表します。

    • 各ビットはセグメント a から g および dp に対応しています。

    const byte digitCodes[10] = {
      0b00111111, // 0
      0b00000110, // 1
      0b01011011, // 2
      0b01001111, // 3
      0b01100110, // 4
      0b01101101, // 5
      0b01111101, // 6
      0b00000111, // 7
      0b01111111, // 8
      0b01101111  // 9
    };
    
  4. セットアップ関数:

    • DATA_PINLATCH_PINCLOCK_PIN を出力ピンとして設定。

    • すべての桁制御ピンを HIGH に設定し、最初はすべての桁を無効化。

    void setup() {
      // シフトレジスタのピンを初期化
      pinMode(DATA_PIN, OUTPUT);
      pinMode(LATCH_PIN, OUTPUT);
      pinMode(CLOCK_PIN, OUTPUT);
    
      // 桁制御ピンの初期化
      for (int i = 0; i < 4; i++) {
        pinMode(digitPins[i], OUTPUT);
        digitalWrite(digitPins[i], HIGH); // 初期状態で全桁をオフ
      }
    }
    
  5. ループ関数:

    • millis() を使用し、プログラムをブロックせずに経過時間を追跡。

    • counter を1秒ごとに増加し、9999を超えたらリセット。

    void loop() {
      unsigned long currentMillis = millis();
    
      // 1000ミリ秒 (1秒) ごとにカウンターを更新
      if (currentMillis - previousMillis >= 1000) {
        previousMillis = currentMillis;
        counter++; // カウントを増加
        if (counter > 9999) {
          counter = 0; // 9999を超えたらリセット
        }
      }
    
      // カウンター値を表示
      displayNumber(counter);
    }
    
  6. 数値の表示:

    • counter の値を千の位、百の位、十の位、一の位に分割。

    • 各桁を順番にアクティブにし、対応するセグメントデータを送信後、非アクティブに。

    • 高速で桁を切り替えることで、すべての桁が同時に点灯しているように見せる。

    void displayNumber(int num) {
      // 数値を個々の桁に分解
      int digits[4];
      digits[0] = num / 1000;         // 千の位
      digits[1] = (num / 100) % 10;   // 百の位
      digits[2] = (num / 10) % 10;    // 十の位
      digits[3] = num % 10;           // 一の位
    
      // 各桁を順番に表示
      for (int i = 0; i < 4; i++) {
        digitalWrite(digitPins[i], LOW); // 現在の桁を有効化
    
        // 現在の桁に対応するセグメントデータを送信
        shiftOutDigit(digitCodes[digits[i]]);
    
        delay(5);                        // マルチプレクシングのための短い遅延
        digitalWrite(digitPins[i], HIGH); // 現在の桁を無効化
      }
    }
    
  7. セグメントデータのシフト出力:

    • 74HC595シフトレジスタにセグメントデータを送信。

    • shiftOut() を使用して、最上位ビット (MSBFIRST) から1ビットずつ送信。

    • LATCH_PIN をトグルして出力ピンにデータをラッチ。

    void shiftOutDigit(byte data) {
      // シフトレジスタにデータを送信
      digitalWrite(LATCH_PIN, LOW);
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, data);
      digitalWrite(LATCH_PIN, HIGH);
    }
    

さらなる実験

  • リセットボタンを追加する:

    ボタンをPicoに接続し、押したらカウンターがリセットされるようにします。

  • 異なるデータを表示する:

    センサーの値 (温度や光の強さ) を表示するようにコードを変更できます。

  • ストップウォッチを作成する:

    スタート、ストップ、リセット機能を追加し、ストップウォッチとして使用できるようにします。

結論

このプロジェクトでは、シフトレジスタを使用して4桁7セグメントディスプレイを制御する方法を学びました。 millis() を利用して適切なタイミング管理を行い、表示の滑らかさを損なうことなく正確な時間カウンターを実現しました。