Seite 1 von 1
Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Mittwoch 25. November 2020, 11:22
von unique24
Hallo,
für einen Raspi möchte ich, das ein Eingang mind. 40ms anliegen muss, um ihn zu übernehmen.
Das debounce löst ja gleich aus und sperrt danach .. was ich so nicht möchte
würde funktionieren, aber ist der Code zu kompliziert?
Zuerst muss ich prüfen ob der Eingang sich geändert hat
Dann muss ich prüfen ob die zeit mind. 40ms waren
Dann muss ich prüfen das die Funktion nur einmal schaltet, wenn der Eingang geschlossen bleibt
Code: Alles auswählen
def checkTriggers(self):
while True:
current = datetime.datetime.now().timestamp() * 1000
# wenn sich der Eingang ändert
sw1 = GPIO.input(Coop.PIN_SWITCH_1)
if (sw1 != Coop.PIN_SWITCH_1_PREV):
# Letzten Wert halten
Coop.PIN_SWITCH_1_PREV = sw1
Coop.PIN_SWITCH_1_LAST_TIMESTAMP = current
else:
if((sw1 == Coop.PIN_SWITCH_1_PREV) and (Coop.PIN_SWITCH_1_LAST_TIMESTAMP + Coop.TRESHOLD) < current):
# Wert nur einmal auslösen
if(Coop.PIN_SWITCH_1_BLOCK != sw1):
Coop.PIN_SWITCH_1_BLOCK = sw1
# Steigende Flanke
if(not sw1):
logger.info("Schalter rechts bei Tür gedrückt")
time.sleep(0.01)
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Mittwoch 25. November 2020, 11:57
von Sirius3
@unique24: um Zeiten zu messen, ist time.monotonic besser als datetime.now().timestamp().
if ist keine Funktion, die ganzen Klammern also unsinnig. Coop kommt aus dem Nichts und Du schreibst dort ständig in irgendwelche Konstanten, was total verwirrend ist.
Das time.sleep ist falsch eingerückt.
Die while-Schleife wird ja nie verlassen.
Wenn sw1 != Coop.PIN_SWITCH_1_PREV, dann ist garantiert sw1 == Coop.PIN_SWITCH_1_PREV.
Code: Alles auswählen
def check_triggers(self, coop):
last_level = None
last_event_level = None
while True:
current = time.monotonic()
level = GPIO.input(coop.PIN_SWITCH)
if level != last_level:
# wenn sich der Eingang ändert
last_level = level
coop.timestamp = current
elif coop.timestamp + coop.treshold < current and last_event_level != level:
# Wert nur einmal auslösen
last_event_level = level
if not level:
# Steigende Flanke
logger.info("Schalter rechts bei Tür gedrückt")
time.sleep(0.01)
Das ist aber ein Busy-Wait-Loop.
Code: Alles auswählen
def check_triggers(self, coop):
# auf Tastendruck warten
GPIO.wait_for_edge(channel, GPIO.RISING)
# 40ms auf Loslassen warten
if GPIO.wait_for_edge(channel, GPIO.FALLING, timeout=40) is None:
logger.info("Schalter rechts bei Tür gedrückt")
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Mittwoch 25. November 2020, 20:06
von unique24
Hallo,
danke, da habe ich einiges zu überarbeiten. Aber vorweg:
Dein letzter Code ... der schaltet wenn man den Taster los lässt, oder?
Wenn ich den Eingang schließe und mind 40ms geschlossen habe, soll danach die Ausgabe erfolgen ... auch wenn der Eingang noch geschlossen ist.
Und mit ".wait_for_edge" ... benötige ich pro Eingang eine Funktion, richtig? oder kann ich für "Channel" ein Array angeben?
EDIT:
hab nun dies gefunden:
Code: Alles auswählen
# wait for up to 5 seconds for a rising edge (timeout is in milliseconds)
channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
if channel is None:
print('Timeout occurred')
else:
print('Edge detected on channel', channel)
Bewirkt das Timout das das Edge mind. 5sek anliegen muss? Also genau was ich suche?
Wenn innerhalb der 5sek der Eingang wieder abfällt, bekomme ich ein Timeout?
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Mittwoch 25. November 2020, 21:56
von Sirius3
Nee, umgekehrt, wenn nicht innerhalb von 5 Sekunden der Eingang ansteigt (raising) bekommst Du einen Timeout.
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 06:43
von unique24
Ahhh ... jetzt hab ich es verstanden. Das macht den code sehr schlank
Heißt aber ich benötige für jeden Eingang einen eigenen Thread? Denn der Code wartet ja an der Position auf einen Input, oder?
Herzlichen Dank!
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 06:52
von unique24
oder kann ich es so kombinieren?:
Code: Alles auswählen
def my_callback(channel):
# 40ms auf Loslassen warten
if GPIO.wait_for_edge(channel, GPIO.FALLING, timeout=40) is None:
logger.info("Schalter rechts bei Tür gedrückt")
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) # add rising edge detection on a channel
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 07:33
von Sirius3
Wie sieht denn dein Hauptprogramm aus, in dem du die ganzen Events verarbeitest?
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 11:45
von __blackjack__
Eventuell lohnt sich auch ein Blick auf das `gpiozero`-Modul anstelle von `RPi.GPIO`. Das hat beispielsweise ein `Button`-Objekt dem man mit dem Attribut `when_held` eine Rückruffunktion geben kann, die nach `hold_time` Sekunden (auch ein Attribut) etwas macht.
Edit: Also auf das Beispiel von unique24 übertragen:
Code: Alles auswählen
#!/usr/bin/env python3
from gpiozero import Button
BUTTON_PIN = ...
def callback(button):
logger.info("Schalter rechts bei Tür gedrückt")
def ...(...):
...
button = Button(BUTTON_PIN)
button.hold_time = 0.04
button.when_held = callback
...
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 14:55
von unique24
gpiozero ist interessant ... aber ich bräuchte auch die 40ms beim loslassen ..."when_held" ist nur beim schließen ... gibt es auch eine Funktion beim loslassen?
Neben Tastern habe ich auch einen Rauchmelder und 2 Reed Kontakte ... dort soll die Flanke erkannt werden und jeder Status muss mind. 40ms anliegen, um ihn zu übernehmen.
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 18:38
von unique24
Hallo,
ich benötige wohl doch nochmal bitte Eure Hilfe.
Mein code verkürzt:
Code: Alles auswählen
# !/usr/bin/env python3
# -*- coding: utf-8 -*-
from threading import Thread
import time
import RPi.GPIO as GPIO
PIN_SENSOR_TOP = 5
PIN_SENSOR_BOTTOM = 24
def setup_pins():
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN_SENSOR_BOTTOM, GPIO.IN)
GPIO.setup(PIN_SENSOR_TOP, GPIO.IN)
def check_trigger_sensor_top():
while True:
# auf Tastendruck warten
GPIO.wait_for_edge(PIN_SENSOR_TOP, GPIO.FALLING)
# 40ms auf Loslassen warten
if GPIO.wait_for_edge(PIN_SENSOR_TOP, GPIO.RISING, timeout=40) is None:
print("check_trigger_sensor_top")
def check_trigger_sensor_bottom():
while True:
# auf Tastendruck warten
GPIO.wait_for_edge(PIN_SENSOR_BOTTOM, GPIO.FALLING)
# 40ms auf Loslassen warten
if GPIO.wait_for_edge(PIN_SENSOR_BOTTOM, GPIO.RISING, timeout=40) is None:
print("check_trigger_sensor_bottom")
class Coop:
def __init__(self):
print("start")
setup_pins()
t_sensor_bottom = Thread(target=check_trigger_sensor_bottom)
t_sensor_bottom.setDaemon(True)
t_sensor_bottom.start()
t_sensor_top = Thread(target=check_trigger_sensor_top)
t_sensor_top.setDaemon(True)
t_sensor_top.start()
while True:
time.sleep(4)
if __name__ == "__main__":
Coop()
Schließe ich den TOP erhalte ich:
check_trigger_sensor_top
check_trigger_sensor_top
check_trigger_sensor_top
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "test.py", line 29, in check_trigger_sensor_bottom
GPIO.wait_for_edge(PIN_SENSOR_BOTTOM, GPIO.FALLING)
RuntimeError: Error waiting for edge
check_trigger_sensor_top
check_trigger_sensor_top
bei BOTTOM erhalte ich gar eine Ausgabe
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 21:30
von Sirius3
GPIO ist nicht gerade für seine Stabilität bekannt, wenn dann noch Threads dazu kommen, ...
__init__ ist dazu da, eine Instanz zu initialisieren, nicht, dass die Methode ewig läuft. Die Klasse an sich ist auch total nutzlos und kann weg.
`as` bei import ist dazu da, das Modul umzubenennen, GPIO wird aber gar nicht umbenannt.
Am Ende muß GPIO.cleanup aufgerufen werden.
Re: Eingang soll mind. 40ms gesetzt sein, um zu schalten
Verfasst: Donnerstag 26. November 2020, 22:53
von unique24
Ok, dann bleibt es. bei meinem Loop
Hab die Codezeilen hier drastisch reduziert und spiegeln nicht mein Programm wieder. Aber danke!