.. note::

    Hallo und willkommen in der SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasten-Gemeinschaft auf Facebook! Tauchen Sie tiefer ein in die Welt von Raspberry Pi, Arduino und ESP32 mit anderen Enthusiasten.

    **Warum beitreten?**

    - **Expertenunterstützung**: Lösen Sie Nachverkaufsprobleme und technische Herausforderungen mit Hilfe unserer Gemeinschaft und unseres Teams.
    - **Lernen & Teilen**: Tauschen Sie Tipps und Anleitungen aus, um Ihre Fähigkeiten zu verbessern.
    - **Exklusive Vorschauen**: Erhalten Sie frühzeitigen Zugang zu neuen Produktankündigungen und exklusiven Einblicken.
    - **Spezialrabatte**: Genießen Sie exklusive Rabatte auf unsere neuesten Produkte.
    - **Festliche Aktionen und Gewinnspiele**: Nehmen Sie an Gewinnspielen und Feiertagsaktionen teil.

    👉 Sind Sie bereit, mit uns zu erkunden und zu erschaffen? Klicken Sie auf [|link_sf_facebook|] und treten Sie heute bei!

.. _1.1.5_py_pi5:

1.1.5 4-stellige 7-Segment-Anzeige
====================================

Einführung
-----------------

Kommen Sie und versuchen Sie mit mir, die 4-stellige 7-Segment-Anzeige zu steuern.

Benötigte Komponenten
------------------------------

Für dieses Projekt benötigen wir die folgenden Komponenten.

.. image:: ../python_pi5/img/1.1.5_4_digit_list.png

Es ist definitiv praktisch, ein ganzes Kit zu kaufen, hier ist der Link:

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Name	
        - INHALT DES KITS
        - LINK
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

Sie können sie auch separat über die untenstehenden Links kaufen.

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - KOMPONENTENVORSTELLUNG
        - KAUF-LINK

    *   - :ref:`cpn_gpio_board`
        - |link_gpio_board_buy|
    *   - :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|

Schaltplan
--------------------------

============ ======== ===
T-Board Name physical BCM
GPIO17       Pin 11   17
GPIO27       Pin 13   27
GPIO22       Pin 15   22
SPIMOSI      Pin 19   10
GPIO18       Pin 12   18
GPIO23       Pin 16   23
GPIO24       Pin 18   24
============ ======== ===

.. image:: ../python_pi5/img/1.1.5_4_digit_schmatic.png

Experimentelle Verfahren
-----------------------------------

**Schritt 1**: Baue den Schaltkreis.

.. image:: ../python_pi5/img/1.1.5_4-Digit_circuit.png

**Schritt 2:** Wechseln Sie in den Ordner des Codes.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python-pi5

**Schritt 3:** Führen Sie die ausführbare Datei aus.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 1.1.5_4-Digit_zero.py

Nachdem der Code ausgeführt wurde, nimmt das Programm eine Zählung vor, die jede Sekunde um 1 erhöht, und die 4-stellige Anzeige zeigt die Zählung an.

.. warning::

    Wenn die Fehlermeldung ``RuntimeError: Cannot determine SOC peripheral base address`` angezeigt wird, lesen Sie bitte :ref:`faq_soc`

**Code**

.. note::

    Sie können den untenstehenden Code **modifizieren/zurücksetzen/kopieren/ausführen/stoppen**. Aber zuvor müssen Sie zum Quellcodepfad wie ``raphael-kit/python-pi5`` gehen. Nachdem Sie den Code modifiziert haben, können Sie ihn direkt ausführen, um den Effekt zu sehen.

.. raw:: html

    <run></run>

.. code-block:: python

   #!/usr/bin/env python3
   from gpiozero import OutputDevice
   import time
   import threading

   # Define GPIO pins for the 74HC595 shift register
   SDI = OutputDevice(24)   # Serial Data Input
   RCLK = OutputDevice(23)  # Register Clock
   SRCLK = OutputDevice(18) # Shift Register Clock

   # Define GPIO pins for digit selection on the 7-segment display
   placePin = [OutputDevice(pin) for pin in (10, 22, 27, 17)]

   # 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.on()
           SRCLK.on()
           SRCLK.off()
       RCLK.on()
       RCLK.off()

   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.on()  # Pulse the Shift Register Clock
           SRCLK.off()
       RCLK.on()  # Latch data on the output by pulsing Register Clock
       RCLK.off()

   def pickDigit(digit):
       """ Select a digit for display on the 7-segment display. """
       for pin in placePin:
           pin.off()  # Turn off all digit selection pins
       placePin[digit].on()  # 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 ** 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


**Code-Erklärung**

#. Diese vier Pins steuern die gemeinsamen Anodenpins der vierstelligen 7-Segment-Anzeigen.

   .. code-block:: python

       # Define GPIO pins for digit selection on the 7-segment display
       placePin = [OutputDevice(pin) for pin in (10, 22, 27, 17)]

#. Ein Segmentcode-Array von 0 bis 9 in Hexadezimal (gemeinsame Anode).

   .. code-block:: python

       # Define segment codes for numbers 0-9 for the 7-segment display
       number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90)

#. Initialisiert einen Timer, der jede Sekunde die Funktion ``timer`` auslöst. Dies richtet die wiederkehrende Zählererhöhung ein.

   .. code-block:: python

       def setup():
           """ Setup initial state and start the timer. """
           global timer1
           timer1 = threading.Timer(1.0, timer)  # Initialize and start the timer
           timer1.start()

#. Nachdem der Timer 1,0 s erreicht hat, wird die Timer-Funktion aufgerufen; 1 zum Zähler addieren, und der Timer wird erneut verwendet, um sich selbst jede Sekunde wiederholt auszuführen.

   .. code-block:: python

       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

#. Verschiebt ein Byte Daten in das 74HC595-Schieberegister, um die Anzeigesegmente zu steuern.

   .. code-block:: python

       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.on()  # Pulse the Shift Register Clock
               SRCLK.off()
           RCLK.on()  # Latch data on the output by pulsing Register Clock
           RCLK.off()

#. Aktualisiert kontinuierlich die Anzeige mit dem aktuellen Zählerwert, indem jede Ziffer sequenziell angezeigt wird.

   .. code-block:: python

       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
                   digit = (counter // (10 ** i)) % 10
                   hc595_shift(number[digit])  # Shift digit value to 74HC595
                   time.sleep(0.001)  # Short delay for display stability

#. Löscht die 7-Segment-Anzeige, indem alle Segmente ausgeschaltet werden, bevor die nächste Ziffer angezeigt wird.

   .. code-block:: python

       def clearDisplay():
           """ Clear the 7-segment display. """
           for _ in range(8):
               SDI.on()
               SRCLK.on()
               SRCLK.off()
           RCLK.on()
           RCLK.off()

#. Wählt aus, welche Ziffer der 7-Segment-Anzeige aktiviert werden soll. Jede Ziffer wird von einem separaten GPIO-Pin gesteuert.

   .. code-block:: python

       def pickDigit(digit):
           """ Select a digit for display on the 7-segment display. """
           for pin in placePin:
               pin.off()  # Turn off all digit selection pins
           placePin[digit].on()  # Turn on the selected digit

#. Gibt die GPIO-Ressourcen ordnungsgemäß frei und stoppt den Timer, wenn das Programm unterbrochen wird.

   .. code-block:: python

       except KeyboardInterrupt:
           # Handle script interruption (e.g., Ctrl+C)
           destroy()  # Cleanup resources on exit

