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