.. 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!

.. _2.1.6_py_pi5:

2.1.6 Drehencoder-Modul
=================================

Einleitung
-------------------

In diesem Projekt werden Sie den Drehencoder kennenlernen. Ein Drehencoder ist ein elektronischer Schalter mit einer Reihe von regelmäßigen Impulsen in streng zeitlicher Reihenfolge. In Verbindung mit einem IC kann er zur Erhöhung, Verringerung, zum Umblättern und für andere Operationen wie Maus-Scrolling, Menüauswahl usw. verwendet werden.

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

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

.. image:: ../python_pi5/img/2.1.6_rotary_encoder_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	
        - IN DIESEM KIT ENTHALTENE TEILE
        - LINK
    *   - Raphael Kit
        - 337
        - |link_Raphael_kit|

Sie können sie auch separat über die unten stehenden 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_rotary_encoder`
        - |link_rotary_encoder_buy|

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

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

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

**Schritt 1:** Bauen Sie den Schaltkreis auf.

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

In diesem Beispiel können wir den Drehencoder direkt mit dem Raspberry Pi über ein Steckbrett und ein 40-Pin-Kabel verbinden, den GND des Drehencoders mit GND, 「+」mit 5V, SW mit digitalem GPIO27, DT mit digitalem GPIO18 und CLK mit digitalem GPIO 17 verbinden.

**Schritt 2:** Öffnen Sie die Code-Datei.

.. raw:: html

   <run></run>

.. code-block::

    cd ~/raphael-kit/python-pi5

**Schritt 3:** Führen Sie den Code aus.

.. raw:: html

   <run></run>

.. code-block::

    sudo python3 2.1.6_RotaryEncoder_zero.py

Sie werden den Zählerstand in der Shell sehen. Wenn Sie den Drehencoder im Uhrzeigersinn drehen, wird der Zähler erhöht; wenn Sie ihn gegen den Uhrzeigersinn drehen, wird der Zähler verringert. Wenn Sie den Schalter am Drehencoder drücken, werden die Messwerte auf null zurückgesetzt.

.. 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 unten stehenden 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 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:
      # Monitor rotary encoder continuously and process changes
      while True:
         rotary_change()  # Handle rotary encoder changes
         sleep(0.1)  # Short delay to reduce CPU load

   except KeyboardInterrupt:
      # Gracefully handle a keyboard interrupt (Ctrl+C)
      pass


**Code-Analyse**

#. Importiert die Klassen ``RotaryEncoder`` und ``Button`` aus der Bibliothek ``gpiozero`` und die Funktion ``sleep`` für Verzögerungen.

   .. code-block:: python

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

#. Initialisiert den Drehencoder mit den GPIO-Pins 17 und 18 und einen Knopf am GPIO-Pin 27.

   .. code-block:: python

      # 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

#. Deklariert eine globale Variable ``global_counter``, um die Position des Drehencoders zu verfolgen.

   .. code-block:: python

      global_counter = 0  # Track the rotary encoder's position

#. Definiert eine Funktion ``rotary_change``, um den globalen Zähler basierend auf der Drehung des Drehencoders zu aktualisieren.

   .. code-block:: python

      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

#. Definiert eine Funktion ``reset_counter``, um den globalen Zähler auf null zurückzusetzen, wenn der Knopf gedrückt wird.

  .. code-block:: python

      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

#. Weist die Funktion ``reset_counter`` dem Druckereignis des Knopfes zu.

   .. code-block:: python

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

#. In einer kontinuierlichen Schleife ruft das Skript ``rotary_change`` auf, um Änderungen am Drehencoder zu bearbeiten, und führt eine kurze Verzögerung ein, um die CPU-Last zu verringern. Verwendet einen try-except-Block, um KeyboardInterrupts anmutig zu behandeln.

   .. code-block:: python

      try:
         # Monitor rotary encoder continuously and process changes
         while True:
            rotary_change()  # Handle rotary encoder changes
            sleep(0.1)  # Short delay to reduce CPU load

      except KeyboardInterrupt:
         # Gracefully handle a keyboard interrupt (Ctrl+C)
         pass
