.. include:: /index.rst :start-after: start_hello_message :end-before: end_hello_message .. _py_4_segment: 1.8 4桁7セグメントディスプレイ ==================================== **はじめに** このプロジェクトでは、4桁の7セグメントディスプレイを制御してカウンターを作成する方法を学びます。カウンターは1秒ごとに1ずつ増加し、それに合わせて表示も更新されます。このプロジェクトでは、GPIOピンと74HC595シフトレジスタを使用して複数桁の表示を効率的に制御する方法を紹介します。 ---------------------------------------------- **必要なもの** このプロジェクトを完了するには、以下のコンポーネントが必要です。 .. list-table:: :widths: 30 20 :header-rows: 1 * - COMPONENT - PURCHASE LINK * - :ref:`cpn_breadboard` - |link_breadboard_buy| * - :ref:`cpn_wires` - |link_wires_buy| * - :ref:`cpn_resistor` - |link_resistor_buy| * - :ref:`cpn_4_digit` - \- * - :ref:`cpn_74hc595` - |link_74hc595_buy| * - :ref:`cpn_fusion_hat` - \- * - Raspberry Pi - \- ---------------------------------------------- **回路図** 以下の回路図は、74HC595シフトレジスタを4桁7セグメントディスプレイおよびRaspberry PiのGPIOピンに接続する方法を示しています。シフトレジスタを使用することで必要なGPIOピンの数を削減でき、効率的にディスプレイを制御することができます。 .. image:: img/fzz/1.1.5_sch.png :width: 100% :align: center ---------------------------------------------- **配線図** 以下の手順に従って回路を組み立ててください。 1. ブレッドボード上に4桁7セグメントディスプレイと74HC595シフトレジスタを配置します。 2. 74HC595の出力ピンをディスプレイの各セグメントに接続します。 3. データ入力(SER、SDIとも呼ばれる)、シフトレジスタクロック(SRCLK)、ラッチレジスタクロック(RCLK)には、Fusion HAT+ のデジタルピンを使用します。 4. ディスプレイの各セグメントに流れる電流を制限するため、抵抗を追加します。 .. image:: img/fzz/1.1.5_bb.png :width: 80% :align: center ---------------------------------------------- **サンプルの実行** このチュートリアルで使用するすべてのサンプルコードは ``ai-lab-kit`` ディレクトリにあります。 以下の手順に従ってサンプルを実行してください。 .. raw:: html .. code-block:: shell cd ~/ai-lab-kit/python/ sudo python3 1.8_4-Digit.py スクリプトを実行すると、4桁の7セグメントディスプレイに1秒ごとに1ずつ増加するカウンターが表示されます。現在のカウンター値はコンソールにも出力されます。プログラムは ``Ctrl + C`` を押して停止するまで継続して動作します。 ---------------------------------------------- **コード** 以下のPythonコードは、ディスプレイの初期化、カウンターの更新、およびディスプレイ更新ループの管理を行います。 .. raw:: html .. code-block:: python #!/usr/bin/env python3 from fusion_hat.pin import Pin, Mode import time import threading # Define GPIO pins for the 74HC595 shift register SDI = Pin(17,mode=Mode.OUT) # Serial Data Input RCLK = Pin(4,mode=Mode.OUT) # Register Clock SRCLK = Pin(27,mode=Mode.OUT) # Shift Register Clock # Define GPIO pins for digit selection on the 7-segment display placePin = [Pin(pin,mode=Mode.OUT) for pin in (23, 24, 25, 12)] # Define segment codes for numbers 0-9 for the 7-segment display number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90) counter = 0 # Initialize counter for display timer1 = 0 # Initialize timer for counter increment def clearDisplay(): """ Clear the 7-segment display. """ for _ in range(8): SDI.high() SRCLK.high() SRCLK.low() RCLK.high() RCLK.low() def hc595_shift(data): """ Shift a byte of data to the 74HC595 shift register. """ for i in range(8): SDI.value(0x80 & (data << i)) # Set SDI high/low based on data bit SRCLK.high() # Pulse the Shift Register Clock SRCLK.low() RCLK.high() # Latch data on the output by pulsing Register Clock RCLK.low() def pickDigit(digit): """ Select a digit for display on the 7-segment display. """ for pin in placePin: pin.low() # Turn off all digit selection pins placePin[digit].high() # Turn on the selected digit def timer(): """ Timer function to increment the counter every second. """ global counter, timer1 timer1 = threading.Timer(1.0, timer) # Reset timer for next increment timer1.start() counter += 1 # Increment counter print("%d" % counter) # Print current counter value def setup(): """ Setup initial state and start the timer. """ global timer1 timer1 = threading.Timer(1.0, timer) # Initialize and start the timer timer1.start() def loop(): """ Main loop to update the 7-segment display with counter value. """ global counter while True: for i in range(4): # Loop through each digit clearDisplay() # Clear display before setting new digit pickDigit(i) # Select digit for display # Choose the digit of counter to display digit = (counter // (10 ** (3-i))) % 10 hc595_shift(number[digit]) # Shift digit value to 74HC595 time.sleep(0.001) # Short delay for display stability def destroy(): """ Cleanup GPIO resources and stop timer on exit. """ global timer1 timer1.cancel() # Stop the timer for device in [SDI, RCLK, SRCLK] + placePin: device.close() # Close GPIO devices try: setup() # Initialize the setup while True: loop() # Start the main loop except KeyboardInterrupt: # Handle script interruption (e.g., Ctrl+C) destroy() # Cleanup resources on exit このPythonスクリプトは、Raspberry Pi と 74HC595 シフトレジスタを使用して4桁の7セグメントディスプレイを制御します。実行すると次のように動作します。 1. ディスプレイには1秒ごとに更新されるカウンターが表示されます。 2. カウンターの値はデバッグ用としてコンソールにも出力されます。 ユーザーが ``Ctrl+C`` を押してスクリプトを停止するまで、プログラムは継続してカウンターを増加させながら動作します。 ---------------------------------------------- **コードの解説** 1. **GPIOピンの初期化** シフトレジスタおよび桁選択用のGPIOピンを設定します。 .. code-block:: python # Define GPIO pins for the 74HC595 shift register SDI = Pin(17,Pin.OUT) # Serial Data Input RCLK = Pin(4,Pin.OUT) # Register Clock SRCLK = Pin(27,Pin.OUT) # Shift Register Clock # Define GPIO pins for digit selection on the 7-segment display placePin = [Pin(pin,mode=Mode.OUT) for pin in (23, 24, 25, 12)] 2. **セグメントコード** ``number`` 配列は、0〜9の各数字に対応するバイナリ表現を定義しています。 .. code-block:: python number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90) 3. **ディスプレイ更新処理** ``loop`` 関数は各桁を順番に選択し、対応するデータを送信してディスプレイを継続的に更新します。 .. code-block:: python def loop(): global counter while True: for i in range(4): clearDisplay() pickDigit(i) digit = (counter // (10 ** (3-i))) % 10 hc595_shift(number[digit]) time.sleep(0.001) 4. **カウンター更新** ``timer`` 関数は1秒ごとにカウンターを増加させます。 .. code-block:: python def timer(): global counter, timer1 timer1 = threading.Timer(1.0, timer) timer1.start() counter += 1 print("%d" % counter) 5. **クリーンアップ** ``destroy`` 関数はプログラム終了時にタイマーを停止し、GPIOリソースを解放します。 .. code-block:: python def destroy(): """ Cleanup GPIO resources and stop timer on exit. """ global timer1 timer1.cancel() # Stop the timer for device in [SDI, RCLK, SRCLK] + placePin: device.close() # Close GPIO devices ---------------------------------------------- **トラブルシューティング** 1. **ディスプレイに何も表示されない** - **原因**: 配線ミス、またはGPIOピン設定の誤り。 - **解決方法**: 74HC595シフトレジスタへの接続を再確認し、GPIOピン(17、4、27)が定義されている変数( ``SDI`` 、 ``RCLK`` 、 ``SRCLK`` )と一致していることを確認してください。 2. **数字が正しく更新されない** - **原因**: タイミングの問題、またはマルチプレクス処理の設定ミス。 - **解決方法**: ``loop()`` 関数内の ``time.sleep(0.001)`` が、ディスプレイを安定して更新するのに十分であることを確認してください。 3. **カウンターが予期せずリセットされる** - **原因**: ``timer1`` のスレッドタイマーが正しく動作していない可能性があります。 - **解決方法**: ``setup()`` 関数がメインの ``loop()`` の前に実行され、タイマーが正しく開始されていることを確認してください。 4. **KeyboardInterrupt が機能しない** - **原因**: 割り込み時に ``destroy()`` 関数が正しく実行されていない可能性があります。 - **解決方法**: ``destroy()`` 内ですべてのGPIOデバイスが適切に閉じられていること、および ``except KeyboardInterrupt`` ブロック内で呼び出されていることを確認してください。 ---------------------------------------------- **発展アイデア** 1. **カウンター動作のカスタマイズ** カウンターをカウントダウンに変更したり、特定の値でリセットするようにしたり、特定のパターンを表示するように変更できます。 2. **マルチモード表示** 以下のような表示モードを追加できます。 - 固定メッセージ表示 - カウンター表示と事前定義メッセージの交互表示 3. **カウンター速度の変更** ユーザーがカウンターの増加速度を動的に変更できるようにします。 .. code-block:: python speed = float(input("Enter counter speed in seconds: ")) timer1 = threading.Timer(speed, timer) 4. **リアルタイムクロック** カウンターの代わりにリアルタイムクロックを表示するように変更します。 .. code-block:: python from datetime import datetime now = datetime.now() counter = now.hour * 100 + now.minute # Display as HHMM ---------------------------------------------- **まとめ** このプロジェクトでは、74HC595シフトレジスタとGPIOプログラミングを使用して4桁7セグメントディスプレイを制御する方法を紹介しました。ここで学んだ技術は、より複雑な表示装置やインタラクティブシステムの開発にも応用することができます。