.. 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 i problemi post-vendita e le 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!

.. _2.1.6_py_pi5:

2.1.6 Modulo Encoder Rotativo
================================

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

In questo progetto imparerai a conoscere l'encoder rotativo. Un encoder 
rotativo è un interruttore elettronico che emette una serie di impulsi 
regolari in una sequenza temporale rigorosa. Quando viene utilizzato con 
un circuito integrato (IC), può consentire operazioni come incremento, 
decremento, scorrimento di pagine e altre operazioni, come lo scrolling del 
mouse, la selezione dei menu, ecc.

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

Per questo progetto, avremo bisogno dei seguenti componenti.

.. image:: ../python_pi5/img/2.1.6_rotary_encoder_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_rotary_encoder`
        - |link_rotary_encoder_buy|

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

.. image:: ../python_pi5/img/2.1.6_rotary_encoder_schematic.png
   :align: center

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

**Passo 1:** Costruisci il circuito.

.. image:: ../python_pi5/img/2.1.6_rotary_encoder_circuit.png

In questo esempio, possiamo collegare il pin dell'encoder rotativo direttamente 
al Raspberry Pi utilizzando una breadboard e un cavo a 40 pin. Collega il GND 
dell'encoder rotativo a GND, 「+」a 5V, SW a GPIO digitale 27, DT a GPIO digitale 
18 e CLK a GPIO digitale 17.

**Passo 2:** Apri il file del codice.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python-pi5

**Passo 3:** Esegui.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 2.1.6_RotaryEncoder_zero.py

Vedrai il conteggio sul terminale. Quando ruoti l'encoder rotativo in senso orario, il conteggio aumenta; quando lo ruoti in senso antiorario, il conteggio diminuisce. Se premi l'interruttore sull'encoder rotativo, il conteggio si azzererà.


.. 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 accedere alla 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 RotaryEncoder, Button
   from time import sleep

   # Initialize the rotary encoder and button
   encoder = RotaryEncoder(a=17, b=18)  # Rotary Encoder connected to GPIO pins 17 (CLK) and 18 (DT)
   button = Button(27)                  # Button connected to GPIO pin 27

   global_counter = 0  # Track the rotary encoder's position

   def rotary_change():
      """ Update the global counter based on the rotary encoder's rotation. """
      global global_counter
      global_counter += encoder.steps  # Adjust counter based on encoder steps
      encoder.steps = 0  # Reset encoder steps after updating counter
      print('Global Counter =', global_counter)  # Display current counter value

   def reset_counter():
      """ Reset the global counter to zero when the button is pressed. """
      global global_counter
      global_counter = 0  # Reset the counter
      print('Counter reset')  # Indicate counter reset

   # Assign the reset_counter function to button press event
   button.when_pressed = reset_counter

   try:
      # Monitora continuamente l'encoder rotativo e gestisci le variazioni
      while True:
         rotary_change()  # Gestisci le variazioni dell'encoder rotativo
         sleep(0.1)  # Breve pausa per ridurre il carico della CPU

   except KeyboardInterrupt:
      # Gestisci in modo corretto un'interruzione da tastiera (Ctrl+C)
      pass



**Analisi del Codice**

#. Importa le classi ``RotaryEncoder`` e ``Button`` dalla libreria ``gpiozero``, e la funzione ``sleep`` per gestire i ritardi.

   .. code-block:: python

      #!/usr/bin/env python3
      from gpiozero import RotaryEncoder, Button
      from time import sleep

#. Inizializza l'encoder rotativo con i pin GPIO 17 e 18, e un pulsante sul pin GPIO 27.

   .. code-block:: python

      # Inizializza l'encoder rotativo e il pulsante
      encoder = RotaryEncoder(a=17, b=18)  # Encoder rotativo collegato ai pin GPIO 17 (CLK) e 18 (DT)
      button = Button(27)                  # Pulsante collegato al pin GPIO 27

#. Dichiara una variabile globale ``global_counter`` per tracciare la posizione dell'encoder rotativo.

   .. code-block:: python

      global_counter = 0  # Variabile globale per tracciare la posizione dell'encoder rotativo

#. Definisce una funzione ``rotary_change`` per aggiornare il contatore globale in base alla rotazione dell'encoder rotativo.

   .. code-block:: python

      def rotary_change():
         """ Aggiorna il contatore globale in base alla rotazione dell'encoder rotativo. """
         global global_counter
         global_counter += encoder.steps  # Aggiorna il contatore in base agli step dell'encoder
         encoder.steps = 0  # Resetta gli step dell'encoder dopo aver aggiornato il contatore
         print('Global Counter =', global_counter)  # Mostra il valore corrente del contatore

#. Definisce una funzione ``reset_counter`` per resettare il contatore globale a zero quando viene premuto il pulsante.

   .. code-block:: python

      def reset_counter():
         """ Resetta il contatore globale a zero quando viene premuto il pulsante. """
         global global_counter
         global_counter = 0  # Resetta il contatore
         print('Contatore resettato')  # Indica che il contatore è stato resettato

#. Assegna la funzione ``reset_counter`` da eseguire quando il pulsante viene premuto.

   .. code-block:: python

      # Assegna la funzione reset_counter all'evento di pressione del pulsante
      button.when_pressed = reset_counter

#. In un ciclo continuo, lo script chiama ``rotary_change`` per gestire le variazioni dell'encoder rotativo e introduce una breve pausa per ridurre il carico della CPU. Utilizza un blocco try-except per gestire in modo corretto le interruzioni da tastiera.

   .. code-block:: python

      try:
         # Monitora continuamente l'encoder rotativo e gestisci le variazioni
         while True:
            rotary_change()  # Gestisci le variazioni dell'encoder rotativo
            sleep(0.1)  # Breve pausa per ridurre il carico della CPU

      except KeyboardInterrupt:
         # Gestisci in modo corretto un'interruzione da tastiera (Ctrl+C)
         pass

