Auf Flanken reagieren und mehrer Befehle ausführen

L I V E Stammtisch ab 20:30 Uhr im Chat
  • Hi,

    Ich habe am GPIO Pin 24 eine Pulsierende Gleichspannung und will sobald dort ein längeres Signal anliegt Funksteckdosen schalten und ein Video aufnehmen. Dies soll solange passieren bis eine lange 0 Folge kommt. Zusätzlich soll noch nach dem Auslösen in eine Datei geschrieben werden.

    Hier erstmal mein Code bisher:

    Problem ist:

    - Sobald eine Spannungsspitze ankommt wird ratikal bis 10 gezählt. Dies will ich verhindern. da wirklich die Flanken gezählt werden sollen.

    Als Bsp. jede Sekunde kommt einmal der High zustand. Dieser soll gezählt werden. Also müsste er bei meinem Programm 10 sekunden warten bis eine if anweisung eintritt

    - Der Video Befehl soll nur einmal ausgeführt werden

    - in die Textdatei soll die Tatsächliche Systemzeit geschrieben werden.

    Ihr seht, ich bin ein ziemlicher Anfänger und habe mir das aus etlichen Tutorials zusammen gebaut.

    Probleme sehe ich bei den while schleifen und den if anweisungen.

    Ich hoffe ihr habt ein paar tipps für mich, was in einem Code schief läuft.

    LG

  • Auf Flanken reagieren und mehrer Befehle ausführen? Schau mal ob du hier fündig wirst!

  • Hallo.

    Also so wird das wohl nichts.
    Einfaches Beispiel:
    Stell dir vor, du hast am GPIO Pin ne pulsierende Spannung zw. 0-3,3V .
    Ab einer best. Schaltschwelle wird der GPIO eine 1 erkennen und zwar so lange bis die Schaltschwelle wieder unterschritten wird.
    Die Anzahl deiner gemessenen 1'en ist abhängig von der CPU Taktfreq, und Periodendauer.
    Du willst aber Flankenwechsel erkennen.
    Guck dir mal die pigpio Lib an.
    Flankengesteuerter Interrupt.
    Beispiel:
    Programmbeginn:
    Interrupt init:

    Code
    gpioSetAlertFunc(intp, alert);

    wenn ein Flankenwechsel eintritt, wird ein Int ausgelöst:

    Code
    void alert(int pin, int level, uint32_t tick) {	
    	if (gpioRead(intp) == 0)
    		flag = 0;
    	if (gpioRead(intp) == 1)
    		flag = 1;
    }


    In der main() fragst das Flag ab, ob ein Wechsel stattgefunden hat, und welcher.
    Dann reagierst entspr.
    Somit erkennst du an einer Sinusförmigen Halbwelle genau eine steigende und eine fallende Flanke.
    Selbst die Zeit dazwischen kannst (wenn nötig) messen.
    Das ist ein C Beispiel.
    das ganze geht auch in Python.
    Sind auch Beispiele dabei.

    viel Erfolg
    gruß root

    Einmal editiert, zuletzt von root (21. Dezember 2014 um 14:05)

  • Danke erstmal dafür. Das gucke ich mir mal an. Könnte man aber nicht irgendwie mit wait befehlen arbeiten sobald er die erste 1 registriert hat? Die Taktfrequenz der CPU wird ja sicherlich weitaus höher sein als 1Hz.

    Lg


  • Danke erstmal dafür. Das gucke ich mir mal an. Könnte man aber nicht irgendwie mit wait befehlen arbeiten sobald er die erste 1 registriert hat? Die Taktfrequenz der CPU wird ja sicherlich weitaus höher sein als 1Hz.


    wozu wait.
    Sobald ne 1 erkannt wurde, passiert ja nichts mehr am int.
    Der nächste int kann dann nur eine 0 sein.
    Aber selbst das kannst ja überprüfen.
    Hat doch nichts mit der Taktfrequenz zu tun.
    Ein int wird nur beim Flankenwechsel ausgelöst, das musst Dir verinnerlichen
    siehe:

    Code
    gpioSetAlertFunc	Request a gpio level change callback


    gruß root

    Einmal editiert, zuletzt von root (21. Dezember 2014 um 14:34)

  • Ja klar.

    Mir geht es dabei nicht zwingenden um dem Flankenwechsel... Der Zustand würde auch reichen. Aber zb nur jede Sekunde abgefragt sobald die erste 1 erkannt wurde.

    Er erkennt eine 1 wartet dann 1 Sekunde und fragt wieder den Zustand ab gpio ab. Die Frage ist nur wie setzt man das mit If Anweisungen um


    Lg

  • So funktioniert es, glaube ich

    Code
    if GPIO.input(24) == True:
                    Counter = Counter + 1
                    Counter2 = Counter2 + 1
                    print "Counter " + str(Counter)
                    Counter_False = Counter_False - 1
                    time.sleep(1)

    jetzt muss ich mir nur meine ganzen if anweisungen anschauen.

    Einmal editiert, zuletzt von 9mm (21. Dezember 2014 um 18:06)


  • habe jetzt mein script eine weile laufen und musste eben sehen das ich auf einmal 100% CPU Load habe. voran liegt das jetzt. War vorher nicht so


    Müsste man das komplette Script sehen.
    Im oben gezeigten wird ein sleep() nur dann ausgeführt wenn GPIO auf 1 steht, ansonsten rennt das Ding volle Kanne durch.
    Vermute hast Dich da iwie verhaspelt, aber ... Script zeigen ...;)

    gruß root


  • habe jetzt mein script eine weile laufen und musste eben sehen das ich auf einmal 100% CPU Load habe. voran liegt das jetzt. War vorher nicht so

    Das liegt an der while Schleife ...

    Verstehe auch nicht wieso du nicht Interrupts verwendest? Setz den Counter auf zB 0, addiere bei einem GPIO.input +1 und ansonsten -1. Wenn der Counter dann zB +5 erreicht führst du die Videoaufnahme durch usw

  • ok,

    ich hab mir das jetzt mal angeguckt und verstehe das auch soweit.

    Das Problem ist aber, wie realisiere ich lange "0 - Folgen". Über die Interrupts bekomme ich ja nur eine Zustandsänderung mit. Aber ich will ja abschalten wenn nach 3 Perioden zb kein Signal mehr anliegt.

    lg

  • Hallo, dann klinke ich mich auch noch mal ein.


    Das Problem ist aber, wie realisiere ich lange "0 - Folgen". Über die Interrupts bekomme ich ja nur eine Zustandsänderung mit. Aber ich will ja abschalten wenn nach 3 Perioden zb kein Signal mehr anliegt.

    Da gibt es mehrere Möglichkeiten.
    Wenn du es jetzt mit interrupts gelöst hast, z.B: so
    3 Perioden willst abwarten.
    Bei jeder steigenden Flanke ne Variable hochzählen , also up ++
    Bei jeder fallenden Flanke 2. Variable hochzählen, also dwn ++
    Wenn jede Var auf 3 steht, waren es 3 Perioden.
    Jetzt nen Timer mit x Sec starten.
    Wenn der abgelaufen ist, und beide Vars stehen noch auf 3, hat sich in der Zwischenzeit nix getan .
    Beim Interrupt gibt es keine 1, oder 0 Folgen.
    Nach ner 1 muss ne 0 kommen, und nach ner 0 wieder ne 1.

    So in der Art, aber ich hab wirklich noch nicht so recht verstanden, was du wann schalten willst.
    Nach ner Flanke, dann bißchen warten... und dann ???:denker:

    gruß root

    Einmal editiert, zuletzt von root (21. Dezember 2014 um 22:47)

  • Ok. Danke das hilft mir zum Verständnis.

    Ich will sobald eine Spannung anliegt kurz warten. Um sicher zu stellen das es ein echtes Signal und keine Störung ist. Dann soll ab einem gewissen gezählten Wert funksteckdosen geschaltet werden und dann eine Kamera angeschaltet werden. Sobald das Signal weg ist soll 3 Perioden lang geguckt werden ob das Signal wirklich weg ist und dann funksteckdosen aus Kamera aus und Daten in eine Textdatei schreiben.

    Einmal editiert, zuletzt von 9mm (21. Dezember 2014 um 23:05)

  • Prima.
    Vlt. noch'n kleiner Tipp dazu.
    Diese Interrupt Sachen sind für nen Anfänger etwas gewöhnungsbedürftig, aber das hat man schnell drin :thumbs1:
    Weiter:
    Um nen GPIO der als Eingang geschaltet ist, sauber abzufragen, ist direkt am GPIO Pin ein sog.
    Pulldown Widerstand mit ~470 Ohm empfehlenswert.
    Besonders wenn das Eingangsignal kein Rechteck ist.
    Denn jeder Draht zum Pin ist letztlich zusätzlich wie ne Antenne.
    Also 470 Ohm vom Pin gegen Masse.

    weiterhin gutes Gelingen.
    gruß root

    Einmal editiert, zuletzt von root (21. Dezember 2014 um 23:28)

  • Noch eine Frage hätte ich.

    Ist es möglich das wenn eine Variable ungleich 0 ist einen Timer zu starten. Dieser soll zb 60 sekunden laufen. wird er nicht Resetet soll er die Variable 0 setzen.

    Finde zum them "Timer" irgendwie nichts vernünftiges

    lg

  • Hallo.


    Ist es möglich das wenn eine Variable ungleich 0 ist einen Timer zu starten. Dieser soll zb 60 sekunden laufen. wird er nicht Resetet soll er die Variable 0 setzen.

    Finde zum them "Timer" irgendwie nichts vernünftiges

    Hab mit Python selbst nix am Hut,und kenn mich damit wenig aus.
    Aber wenn ich dich richtig verstehe, willst nen Timer starten, wenn Var X <> 0, und dieser soll 60 sec laufen.
    Wer soll den gestarteten Timer resetten, und vor allem wie.
    Nen Timer zu realisieren, entweder mit sleep() , nen Counter oder nen echten angestossenen Timer.
    Und wenn Du schon beim Interrupt lernen bist... jetzt kommt der nächste Interrupt..... Timerinterrupt...:lol:

    Code
    gpioSetTimerFunc	Request a regular timed callback


    Les dir das mal durch. (ist auch in der pigpio Lib)
    D.h. Deine Main() rennt, startest den Timer, deine main() rennt weiter, wenn 60 sec abgelaufen kommt der Timer int , der resettet deine Var bzw stellt sie auf 0.
    fertig.
    Die Vars müssen demnach Globals sein, denn der Timerint löscht sie, der Flankenint zählt hoch und die main() untersucht sie.

    gruß root

    Einmal editiert, zuletzt von root (22. Dezember 2014 um 00:37)

  • Ich kenn piglib zwar nicht, aber allgemein muss man beachten dass wenn man zB eine while Schleife verwendet, das restliche Script solange blockiert wird. Es kann also nichts anderes parallel ausgeführt werden.
    Der Interrupt läuft über einen separaten Thread, also unabhängig vom Hauptprozess: dem Script selbst.
    Was man dann machen könnte, sofern man neben dem main() auch noch parallel andere Sachen ablaufen lassen möchte wie einen Counter, wäre dies über threading einen weiteren "subprozess" laufen zu lassen und globale Variablen zu ändern.


    [code=php]
    import time
    import RPi.GPIO as GPIO
    import threading

    gpioPin = 27

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(gpioPin, GPIO.IN, pull_up_down = GPIO.PUD_UP)

    CounterUP = 0
    CounterDOWN = 0
    finished = False
    TimerStarted = False

    def Interrupt_event(pin):
    global CounterUP, CounterDOWN, TimerStarted
    if GPIO.input(gpioPin): # if 27 == 1
    print("Rising edge detected on %s"%pin)
    CounterUP = (CounterUP + 1)
    else: # if 27 != 1
    print("Falling edge detected on %s"%pin)
    CounterDOWN = (CounterDOWN + 1)
    if CounterDOWN >= 3 and TimerStarted == False:
    CounterUP = 0
    CounterDOWN = 0
    TimerStarted = True
    thread2 = threading.Thread(target=Timer_Thread)
    thread2.start()
    print("CounterUP: %s" % CounterUP)
    print("CounterDOWN: %s" % CounterDOWN)

    def Timer_Thread():
    global TimerStarted
    TimerCount = 0
    print("Starte Timer!")
    while TimerStarted:
    time.sleep(1)
    TimerCount = (TimerCount + 1)
    print("TimerCount: %s" % TimerCount)
    if TimerCount == 10:
    print("Timer Ende")
    TimerStarted = False #thread while beenden

    try:
    print("Starte Program")
    GPIO.add_event_detect(gpioPin, GPIO.BOTH, callback=Interrupt_event, bouncetime=200)
    while not finished:
    time.sleep(1)

    except KeyboardInterrupt:
    finished = True
    TimerStarted = False
    print("Quit")
    GPIO.cleanup()
    [/php]

    ...Das ist noch nicht 100% fehlerfrei (funktioniert soweit aber schon) und vermutlich auch noch nicht genau das was du haben willst - zeigt aber zumindest schon ein bisschen wie es aussehen könnte :)
    (muss jetzt erst mal zur Arbeit, guck ich mir später noch mal in Ruhe genauer an)

    Was das macht ist relativ simpel:
    Sobald ein Schalter zwischen GPIO-27 und GND schließt, wird CounterDOWN hoch gezählt. Sobald der Schalter öffnet wird CounterUP hoch gezählt.
    Erreicht CounterDOWN = 3 (oder ist höher) und Timer_Thread ist noch nicht gestartet, wird ein eigenständiger Thread ausgeführt und zählt 10 Sekunden hoch. Sind 10 Sekunden vorbei wird der Thread beendet (da die while Schleife im Thread beendet wird)


  • [...]Sind 10 Sekunden vorbei wird der Thread beendet (da die while Schleife im Thread beendet wird)

    Wie kommst du darauf, dass hier der Thread beendet wird? Es steht ja nicht einfach per Gaudi in der Doku (wurde bereits mehrfach hier im Forum erwähnt):

    Zitat

    [...]and threads cannot be destroyed, stopped, suspended, resumed, or interrupted.


    Mach mal nach ``while not finished:`` ein ``print(threading.active_count())``. Hoffe dann, du verstehst, warum obiges in der Doku steht. Den Rest dieses abenteuerlichen Codes kommentier ich gar nicht mehr, denn offensichtlich ist Hopfen und Malz endgültig verloren...

  • Den Rest dieses abenteuerlichen Codes kommentier ich gar nicht mehr, denn offensichtlich ist Hopfen und Malz endgültig verloren...

    Dann machs halt besser anstatt hier nur solche Sprüche abzulassen :-/ So machste dich hier nur unbeliebt..

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!