.. 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セグメントディスプレイを制御する方法を紹介しました。ここで学んだ技術は、より複雑な表示装置やインタラクティブシステムの開発にも応用することができます。