.. include:: /index.rst :start-after: start_hello_message :end-before: end_hello_message .. _py_fun_count: 4.6 Zählgerät ======================= **Einführung** In diesem Projekt bauen Sie ein Personenzählsystem mit einem PIR-Bewegungssensor und einer 4-stelligen 7-Segment-Anzeige. Das System erhöht den angezeigten Zähler jedes Mal, wenn der PIR-Sensor eine Bewegung erkennt. Dieses Projekt eignet sich ideal zur Überwachung des Personenverkehrs in einem Flur oder Eingangsbereich und bietet praktische Erfahrung mit GPIO-Programmierung und Displaysteuerung. ---------------------------------------------- **Was Sie benötigen** Für dieses Projekt werden die folgenden Komponenten benötigt: .. list-table:: :widths: 30 20 :header-rows: 1 * - KOMPONENTENBESCHREIBUNG - KAUFLINK * - :ref:`cpn_breadboard` - |link_breadboard_buy| * - :ref:`cpn_wires` - |link_wires_buy| * - :ref:`cpn_resistor` - |link_resistor_buy| * - :ref:`cpn_pir` - |link_pir_buy| * - :ref:`cpn_4_digit` - \- * - :ref:`cpn_74hc595` - |link_74hc595_buy| * - :ref:`cpn_fusion_hat` - \- * - Raspberry Pi - \- ---------------------------------------------- **Schaltplan** Nachfolgend ist der Schaltplan für dieses Projekt dargestellt: .. image:: img/fzz/4.1.4_sch.png :width: 100% :align: center ---------------------------------------------- **Verdrahtungsdiagramm** Folgen Sie diesem Verdrahtungsdiagramm, um die Komponenten korrekt zu verbinden: .. image:: img/fzz/4.1.4_bb.png :width: 80% :align: center .. note:: Stellen Sie die beiden Potentiometer auf dem PIR-Modul ein, um Empfindlichkeit und Erkennungsdistanz zu optimieren. Drehen Sie beide Regler vollständig gegen den Uhrzeigersinn, um die besten Ergebnisse zu erzielen. .. image:: ../python/img/PIR_TTE.png :width: 300 :align: center ---------------------------------------------- **Beispiel ausführen** Der gesamte in diesem Tutorial verwendete Beispielcode befindet sich im Verzeichnis ``ai-lab-kit``. Führen Sie die folgenden Schritte aus, um das Beispiel auszuführen: .. raw:: html .. code-block:: shell cd ~/ai-lab-kit/python/ sudo python3 4.6_CountingDevice.py Dieses Python-Skript kombiniert einen PIR-Bewegungssensor mit einer 7-Segment-Anzeige, die über ein 74HC595-Schieberegister gesteuert wird. Das Skript führt folgende Aufgaben aus: 1. **Bewegungserkennung**: Ein PIR-Bewegungssensor, der mit GPIO 26 verbunden ist, erkennt Bewegungen. Jede erkannte Bewegung erhöht einen Zähler. 2. **Zahlenanzeige**: - Der aktuelle Zählerwert wird auf einer 4-stelligen 7-Segment-Anzeige dargestellt. - Die Anzeige wird dynamisch aktualisiert, sobald eine Bewegung erkannt wird, und der Wert erhöht sich entsprechend. 3. **Kontinuierliche Überwachung**: Das Skript überwacht kontinuierlich Bewegungen und aktualisiert die Anzeige in Echtzeit. 4. **Sauberes Beenden**: Bei ``Ctrl+C`` werden alle Pins ausgeschaltet, sodass das Skript ordnungsgemäß beendet wird. ---------------------------------------------- **Code** Nachfolgend ist das in diesem Projekt verwendete Python-Skript aufgeführt: .. raw:: html .. code-block:: python #!/usr/bin/env python3 from fusion_hat.pin import Pin, Mode, Pull # Initialize PIR motion sensor on GPIO 22 (input with pull-down) pir = Pin(22, mode=Mode.IN, pull=Pull.DOWN) # 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 (latch) SRCLK = Pin(27, mode=Mode.OUT) # Shift Register Clock # Define GPIO pins used to select one of the 4 digits on the 7-segment display placePin = [Pin(pin, mode=Mode.OUT) for pin in (23, 24, 25, 12)] # Segment code table for digits 0–9 (common-cathode 7-segment display) number = (0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90) # Counter to display the number of detections counter = 0 def clearDisplay(): """Clear the 7-segment display by shifting out 'all off' bits.""" for _ in range(8): SDI.high() # Send a high bit SRCLK.high() # Clock it in SRCLK.low() RCLK.high() # Latch output RCLK.low() def hc595_shift(data): """Shift a full byte of data into the 74HC595 to control the segments.""" for i in range(8): SDI.value(0x80 & (data << i)) # Output next bit of the data SRCLK.high() # Pulse shift clock SRCLK.low() RCLK.high() # Latch data to display RCLK.low() def pickDigit(digit): """Enable one specific digit (0–3) on the multiplexed display.""" for pin in placePin: pin.low() # Disable all digits placePin[digit].high() # Activate the selected digit def display(): """Display the current 4-digit counter value on the 7-segment display.""" global counter # Display ones place clearDisplay() pickDigit(3) hc595_shift(number[counter % 10]) # Display tens place clearDisplay() pickDigit(2) hc595_shift(number[counter % 100 // 10]) # Display hundreds place clearDisplay() pickDigit(1) hc595_shift(number[counter % 1000 // 100]) # Display thousands place clearDisplay() pickDigit(0) hc595_shift(number[counter % 10000 // 1000]) def loop(): """Main loop: continuously update display and detect PIR motion transitions.""" global counter currentState = 0 lastState = 0 while True: display() # Refresh 7-segment display currentState = 1 if pir.value() == 1 else 0 # Read PIR output # Detect rising edge: motion detected now, but not in last cycle if currentState == 1 and lastState == 0: counter += 1 # Increase the count lastState = currentState # Save state for next loop try: loop() # Start main loop except KeyboardInterrupt: # Clean up GPIO pins when exiting SDI.low() SRCLK.low() RCLK.low() pass ---------------------------------------------- **Code verstehen** 1. **Bewegungserkennung:** Der PIR-Sensor erkennt Bewegungen und sendet ein Signal, um den Zähler zu erhöhen. 2. **Anzeige aktualisieren:** Die Funktionen ``hc595_shift`` und ``pickDigit`` arbeiten zusammen, um die 7-Segment-Anzeige zu steuern und den Zähler in Echtzeit zu aktualisieren. 3. **Hauptschleife:** Die Funktion ``loop`` überprüft kontinuierlich den PIR-Sensor und aktualisiert die Anzeige, wenn eine Bewegung erkannt wird. 4. **Interrupt-Behandlung:** Das Skript stellt sicher, dass alle GPIO-Pins beim Abbruch des Programms sicher ausgeschaltet werden, um unerwartetes Verhalten zu vermeiden. ---------------------------------------------- **Fehlerbehebung** 1. **Anzeige funktioniert nicht**: - **Ursache**: Falsche Verdrahtung der 7-Segment-Anzeige oder des Schieberegisters. - **Lösung**: - Überprüfen Sie die Verbindungen zwischen den GPIO-Pins und den Pins SDI, SRCLK und RCLK des Schieberegisters. - Stellen Sie sicher, dass alle ``placePin``-Verbindungen mit den entsprechenden Digit-Pins übereinstimmen. 2. **Bewegungssensor reagiert nicht**: - **Ursache**: Fehlerhafte Verdrahtung des PIR-Sensors oder Störungen aus der Umgebung. - **Lösung**: - Überprüfen Sie die Verbindung des PIR-Sensors mit GPIO 26, der Stromversorgung und der Masse. - Passen Sie gegebenenfalls die Empfindlichkeits- und Verzögerungspotentiometer des PIR-Sensors an. 3. **Zähler erhöht sich nicht**: - **Ursache**: Änderungen im Zustand des Bewegungssensors werden nicht erkannt. - **Lösung**: - Stellen Sie sicher, dass sich der Wert von ``pir.value()`` korrekt aktualisiert. - Fügen Sie Debug-Ausgaben hinzu, um Zustandsänderungen in der Funktion ``loop()`` zu überprüfen. 4. **Flackernde Anzeige**: - **Ursache**: Zu kurze Verzögerung oder falsches Timing bei der Aktualisierung der Anzeige. - **Lösung**: Fügen Sie eine kleine Verzögerung in der Funktion ``display()`` hinzu, um die Anzeige zu stabilisieren: .. code-block:: python import time time.sleep(0.01) ---------------------------------------------- **Erweiterungsideen** 1. **Bidirektionaler Zähler**: Fügen Sie einen weiteren PIR-Sensor hinzu, um Bewegungen in entgegengesetzter Richtung zu erkennen und den Zähler zu verringern: .. code-block:: python pir2 = Pin(16, Pin.IN, pull= Pin.PULL_DOWN) if pir2.value()==1: counter -= 1 2. **Schwellwertbasierte Warnungen**: Lösen Sie eine Warnung (z. B. LED oder Summer) aus, wenn der Zähler einen festgelegten Wert überschreitet: .. code-block:: python from fusion_hat import Buzzer buzzer = Buzzer(Pin(22)) if counter > 50: buzzer.on() else: buzzer.off() 3. **Datenprotokollierung**: Speichern Sie den Zählerwert und Zeitstempel in einer Datei zur späteren Analyse: .. code-block:: python with open("motion_log.txt", "a") as log_file: log_file.write(f"{time.time():.3f}, Counter: {counter}\n") 4. **Zeitgesteuertes Zurücksetzen**: Setzen Sie den Zähler nach einer bestimmten Zeit ohne Bewegung zurück: .. code-block:: python last_motion_time = time.time() if time.time() - last_motion_time > 300: # 5 minutes counter = 0 5. **Ereignisbasierte Aktionen**: Lösen Sie bestimmte Aktionen aus (z. B. das Steuern von Geräten), wenn der Zähler bestimmte Werte erreicht. ---------------------------------------------- **Fazit** Dieses Projekt vermittelt die Grundlagen der Bewegungserkennung und der Anzeige-Steuerung mit einem PIR-Sensor und einer 7-Segment-Anzeige. Es bietet eine praktische Grundlage für weiterführende IoT- und Datenvisualisierungsprojekte.