.. note::

    Ciao, benvenuto nella Community di SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts su Facebook! Approfondisci il mondo di Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.

    **Perché unirti a noi?**

    - **Supporto tecnico esperto**: Risolvi problemi post-vendita e sfide tecniche con l'aiuto della nostra comunità e del nostro team.
    - **Impara e condividi**: Scambia consigli e tutorial per migliorare le tue competenze.
    - **Anteprime esclusive**: Ottieni accesso anticipato agli annunci di nuovi prodotti e alle anteprime.
    - **Sconti speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni festive e giveaway**: Partecipa a giveaway e promozioni durante le festività.

    👉 Sei pronto a esplorare e creare con noi? Clicca [|link_sf_facebook|] e unisciti oggi stesso!

.. _1.1.5_py_pi5:

1.1.5 Display a 7 segmenti a 4 cifre
=========================================

Introduzione
-----------------

Ora seguiamo insieme i passaggi per controllare il display a 7 segmenti a 4 cifre.

Componenti Necessari
------------------------------

Per questo progetto, avremo bisogno dei seguenti componenti.

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

È decisamente conveniente acquistare un kit completo, ecco il link:

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

    *   - Nome	
        - COMPONENTI NEL KIT
        - LINK
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

Puoi anche acquistarli separatamente dai link sottostanti.

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

    *   - INTRODUZIONE AI COMPONENTI
        - LINK D'ACQUISTO

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

Schema Elettrico
--------------------------

============ ======== ===
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


Procedure Sperimentali
-----------------------------------

**Passo 1**: Costruisci il circuito.

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

**Passo 2:** Accedi alla cartella del codice.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python-pi5

**Passo 3:** Esegui il file eseguibile.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 1.1.5_4-Digit_zero.py

Dopo l'esecuzione del codice, il programma inizia un conteggio, incrementando di 1 al secondo, e il display a 4 cifre visualizza il conteggio.

.. warning::

    Se viene visualizzato l'errore ``RuntimeError: Cannot determine SOC peripheral base address``, fare riferimento a :ref:`faq_soc`. 

**Code**

.. note::

    Puoi **Modificare/Resettare/Copiare/Eseguire/Fermare** il codice qui sotto. Ma prima, devi andare nella directory del codice come ``raphael-kit/python-pi5``. Dopo aver modificato il codice, puoi eseguirlo direttamente per vedere l'effetto.

.. raw:: html

    <run></run>

.. code-block:: python

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

   # Definizione dei pin GPIO per il registro a scorrimento 74HC595
   SDI = OutputDevice(24)   # Ingresso Dati Seriali
   RCLK = OutputDevice(23)  # Clock del Registro
   SRCLK = OutputDevice(18) # Clock del Registro a Scorrimento

   # Definizione dei pin GPIO per la selezione delle cifre sul display a 7 segmenti
   placePin = [OutputDevice(pin) for pin in (10, 22, 27, 17)]

   # Codici dei segmenti per i numeri 0-9 per il display a 7 segmenti
   number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90)

   counter = 0  # Inizializzazione del contatore per la visualizzazione
   timer1 = 0   # Inizializzazione del timer per l'incremento del contatore

   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)  # Imposta SDI alto/basso in base al bit di dati
           SRCLK.on()  # Genera un impulso di clock al Registro a Scorrimento
           SRCLK.off()
       RCLK.on()  # Latch dei dati all'uscita generando un impulso di clock al Registro
       RCLK.off()

   def pickDigit(digit):
       """ Select a digit for display on the 7-segment display. """
       for pin in placePin:
           pin.off()  # Spegni tutti i pin di selezione della cifra
       placePin[digit].on()  # Accendi la cifra selezionata

   def timer():
       """ Timer function to increment the counter every second. """
       global counter, timer1
       timer1 = threading.Timer(1.0, timer)  # Ripristina il timer per il prossimo incremento
       timer1.start()
       counter += 1  # Incrementa il contatore
       print("%d" % counter)  # Stampa il valore corrente del contatore

   def setup():
       """ Setup initial state and start the timer. """
       global timer1
       timer1 = threading.Timer(1.0, timer)  # Inizializza e avvia il 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):  # Cicla attraverso ciascuna cifra
               clearDisplay()  # Cancella il display prima di impostare la nuova cifra
               pickDigit(i)    # Seleziona la cifra da visualizzare

               # Scegli la cifra del contatore da visualizzare
               digit = (counter // (10 ** i)) % 10

               hc595_shift(number[digit])  # Trasferisci il valore della cifra al 74HC595
               time.sleep(0.001)  # Breve ritardo per la stabilità della visualizzazione

   def destroy():
       """ Cleanup GPIO resources and stop timer on exit. """
       global timer1
       timer1.cancel()  # Ferma il timer
       for device in [SDI, RCLK, SRCLK] + placePin:
           device.close()  # Chiudi i dispositivi GPIO

   try:
       setup()  # Inizializza la configurazione
       while True:
           loop()  # Avvia il ciclo principale
           
   except KeyboardInterrupt:
       # Gestisci l'interruzione dello script (es. Ctrl+C)
       destroy()  # Pulisci le risorse all'uscita


**Spiegazione del Codice**

#. Questi quattro pin controllano i pin del catodo comune dei display a 7 segmenti a 4 cifre.

   .. code-block:: python

       # Definizione dei pin GPIO per la selezione delle cifre sul display a 7 segmenti
       placePin = [OutputDevice(pin) for pin in (10, 22, 27, 17)]

#. Un array di codici di segmenti da 0 a 9 in esadecimale (catodo comune).

   .. code-block:: python

       # Codici dei segmenti per i numeri 0-9 per il display a 7 segmenti
       number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90)

#. Inizializza un timer che attiva la funzione ``timer`` ogni secondo. Questo imposta l'incremento ricorrente del contatore.

   .. code-block:: python

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

#. Dopo che il timer raggiunge 1.0s, la funzione Timer viene chiamata; incrementa di 1 il contatore e il timer viene nuovamente utilizzato per eseguirsi ripetutamente ogni secondo.

   .. code-block:: python

       def timer():
           """ Timer function to increment the counter every second. """
           global counter, timer1
           timer1 = threading.Timer(1.0, timer)  # Ripristina il timer per il prossimo incremento
           timer1.start()
           counter += 1  # Incrementa il contatore
           print("%d" % counter)  # Stampa il valore corrente del contatore

#. Trasferisce un byte di dati nel registro a scorrimento 74HC595, controllando i segmenti del display.

   .. 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)  # Imposta SDI alto/basso in base al bit di dati
               SRCLK.on()  # Genera un impulso di clock al Registro a Scorrimento
               SRCLK.off()
           RCLK.on()  # Latch dei dati all'uscita generando un impulso di clock al Registro
           RCLK.off()

#. Aggiorna continuamente il display con il valore corrente del contatore, mostrando ciascuna cifra in sequenza.

   .. 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):  # Cicla attraverso ciascuna cifra
                   clearDisplay()  # Cancella il display prima di impostare la nuova cifra
                   pickDigit(i)    # Seleziona la cifra da visualizzare
                   digit = (counter // (10 ** i)) % 10
                   hc595_shift(number[digit])  # Trasferisci il valore della cifra al 74HC595
                   time.sleep(0.001)  # Breve ritardo per la stabilità della visualizzazione

#. Cancella il display a 7 segmenti spegnendo tutti i segmenti prima di visualizzare la cifra successiva.

   .. code-block:: python

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

#. Seleziona quale cifra del display a 7 segmenti attivare. Ogni cifra è controllata da un pin GPIO separato.

   .. code-block:: python

       def pickDigit(digit):
           """ Select a digit for display on the 7-segment display. """
           for pin in placePin:
               pin.off()  # Spegni tutti i pin di selezione della cifra
           placePin[digit].on()  # Accendi la cifra selezionata

#. Rilascia correttamente le risorse GPIO e ferma il timer quando il programma viene interrotto.

   .. code-block:: python

       except KeyboardInterrupt:
           # Gestisci l'interruzione dello script (es. Ctrl+C)
           destroy()  # Pulisci le risorse all'uscita

