Signal über gpio auslesen und weiterverarbeiten

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo,
    zuerst mal, bin ich mir nicht sicher, ob dieses Thema hier zu 100% richtig ist, da es auch teilweise um Hardware Fragen geht. Falls es hier falsch ist, bitte verschieben.

    Ich plane zusammen mit einem Kollegen eine kleine Steueranlage mit Relais zu bauen. Die Platine mit den Relais läuft so weit und lässt sich über den PI steuern. Das ganze läuft über 2 Pics, die vom Raspi "Bitkombinationen" durch verschiedene auf high und low geschaltete Outputpins bekommen. Durch die Pics werden die dann die jeweiligen Relais geschaltet, kommt dasselbe Signal nochmal, wird es dementsprechend ausgeschaltet.
    Diese ganze Sache funktioniert so weit und einige Lampen und Geräte lassen sich damit per PHP übers Handy oder Laptop steuern.

    Das ganze wurde jetzt dahingehend erweitert, dass die Lampen auch über normal Taster An/Aus geschaltet werden können, aber das ganze weiterhin über die Pics läuft, bei Druck auf den Taster werden durch Dioden wieder "Bitkombinationen" analog zu denen des PHP Scripts gesendet und die Pics schalten.
    Jetzt wollen wir allerdings das Drücken der Taster auch vom PI registrieren lassen. Dazu sollen bei Druck auf den Taster Kombinationen aus 3 Bit zum Raspi gesendet werden, was mich auch zu meiner Frage bringt.

    Ist es möglich per Python Script und Interrupt diesen Wechsel von Low auf High zu registrieren, es werden halt, je nach Kombination, 3 Pins gleichzeitig auf High gesetzt. Bei einem Pin seh ich da kein Problem, ich hoffe, dass dies auch bei mehreren Pins gleichzeitig kein Problem ist.

    Das Python Script soll dann dafür sorgen, dass die Änderung des Zustandes auch im PHP Script zu sehen ist (wir haben Lampen als Symbole, die dann je nach Zustand leuchten/nicht leuchten).

    Da ich mich mit den Pins als Ausgang nicht so gut auskenne, weil ich fürs Programmieren zuständig bin, frage ich mich auch, ob ein Input nur auf High geschaltet ist, solange Spannung anliegt oder auch ein Impuls dazu führt, dass der Pin auf high steht und er erst beim nächsten Signal wieder auf low umschaltet. Ausserdem frage ich mich, ob sich ein Input Pin auch softwaremäßig auf high/low schalten lässt, meinem bescheidenem Verständnis nach, geht das nicht.

    Ich hoffe es kann mir einer ein wenig helfen.

    Schöne Grüße

  • Hallo.

    Also so ganz verstanden hab ich das ganze nicht :s


    Aber erstmal dazu:


    Da ich mich mit den Pins als Ausgang nicht so gut auskenne, weil ich fürs Programmieren zuständig bin, frage ich mich auch, ob ein Input nur auf High geschaltet ist, solange Spannung anliegt oder auch ein Impuls dazu führt, dass der Pin auf high steht und er erst beim nächsten Signal wieder auf low umschaltet. Ausserdem frage ich mich, ob sich ein Input Pin auch softwaremäßig auf high/low schalten lässt, meinem bescheidenem Verständnis nach, geht das nicht.


    Ein Input-Pin ist ein Eingang, und sonst nichts, der schaltet nicht, sondern guckt nur was für ein Level anliegt, und liefert dem Programm der den Eingang abfragt, ne 0 (low) oder 1 (high)
    Wenn da nur ein Puls kommt, ist er also nur für die Dauer des Pulses high.
    Er "hört" quasi nur.

    Deshalb heißt es ja Eingang/Input, mit dem kannst du nichts schalten.
    Schalten kannst du nen Ausgang, indem du ne 0 (low) oder ne 1 (high) rausschreibst.

    Versuch dein Prob. mal genauer zu formulieren.
    Aber keine Angst, jeder fängt mal an ... :thumbs1:

    gruß root

    Einmal editiert, zuletzt von root (21. März 2015 um 01:03)

  • Danke für die Antwort, das bringt mich schonmal weiter.

    Ich versuche das ganze noch nochmal besser zu Beschreiben.

    Angenommen wir haben 4 Lampen, welche über einen Pic+Relais an/aus geschaltet werden können. Der Pic bekommt vom Raspberry seine Signale, um die Relais zu schalten.
    Das ist mit einer 5 Bit Kombination gelöst, z.B gpio1=low, gpio2=low, gpio=3=high, gpio4=low, gpio5=high. Angenommen wir haben nun 5 mögliche Kombinationen (wir nutzen in der Realität natürlich mehr), damit können wir die 4 Lampen einzeln an-/ausschalten und alle gleichzeitig an-/ausschalten.
    Der Schaltzustand der gpios hält für 100ms an, dann werden alle wieder auf low geschaltet. Der Pic weiß durch diese Kombination, welche Lampe angeschaltet werden soll und schaltet das Relais durch.

    So weit so gut, jetzt will ich das ganze sozusagen andersherum machen, nicht der Pic bekommt die Bit Kombination, sondern der Raspi. Wir haben nämlich Taster verbaut, die dafür sorgen, dass alle Lampen (im Beispiel die 4 Lampen) angeschaltet werden. Durch Dioden wird künstlich diese Bit Kombination erzeugt und an den Pic gesendet, dieser schaltet dementsprechend die Relais. Gleichzeitig wird eine 3 Bit Kombination erzeugt, die an die Input gpios des Raspi gesendet werden.

    Ich möchte nun per Python Script oder evtl. auch direkt in PHP (falls möglich), auf eben diesen Interrupt warten und dann dementsprechend reagieren, sprich, die Lampen die in unserem PHP Script als Anzeige für den Zustand der Lampen entweder leuchtend oder nicht leuchtend anzeigen.

    Meine Frage ist nur, ob eben dieser Interrupt möglich ist, weil 3 Pins überwacht werden müssen und nur die richtige Kombination zum auslösen führen darf oder ob der Raspi damit Probleme bekommen könnte. Sollte dem so sein, würde ich für jeden Taster einen eigenen Pin nehmen (würde aber gerne so wenig wie möglich verwenden).

    Weiterhin stellt sich mir die Frage, ob ich bei dem Signal auf Entprellung achten muss.


    P.S. Mir fällt auf, dass dieses Thema im Hardware Forum vermutlich besser aufgehoben ist, wäre also nett, wenn es jemand verschieben könnte.

    Einmal editiert, zuletzt von KingBuzzo (21. März 2015 um 01:29)

  • Hallo nochmal.


    Meine Frage ist nur, ob eben dieser Interrupt möglich ist, weil 3 Pins überwacht werden müssen und nur die richtige Kombination zum auslösen führen darf oder ob der Raspi damit Probleme bekommen könnte.

    Ist möglich, und er kriegt keine Probleme, auch mit 3 Interrupt's nicht (die ja dann nötig sind).... Ist aber bischen Proggi-Technik erforderlich :D


    Weiterhin stellt sich mir die Frage, ob ich bei dem Signal auf Entprellung achten muss.

    Auf jeden Fall, guckt dich im I-net um, gibt eine Menge einfacher Hardware-Lösungen, geht auch per Software, aber Finger weg wenn du noch unerfahren bist


    P.S. Mir fällt auf, dass dieses Thema im Hardware Forum vermutlich besser aufgehoben ist, wäre also nett, wenn es jemand verschieben könnte.

    ...wird schon ein Moderator machen. (Die Armen .... :lol:)

    ...auf gutes Gelingen... anfangen und weiterfragen, wenns klemmt ...:thumbs1:
    Hilfe bekommst du hier im Forum , zumindest wird es versucht. :)

    gruß root

    Einmal editiert, zuletzt von root (21. März 2015 um 02:05)

  • Danke für die Hinweise.
    Habe nochmal mit meinem Kollegen geredet, die Entprellung findet schon hardwareseitig auf der Platine statt, daher sollte ich damit keine Probleme haben.
    Werde dann einfach mal in Python den Interrupt programmieren und schauen ob es funktioniert. Sollte es Probleme geben, werde ich ich einfach nochmal melden.

  • Hallo,
    so hab jetzt mal versucht, den Interrupt in Python zu programmieren. Es wurde dahingehend geändert, das jetzt nicht mehr mehrere Pins den Interrupt auslösen sollen, sondern nur noch jeweils ein Pin für den jeweiligen Taster.

    Ich füge den Code mal hier an, habe leider gerade keine Hardware hier, um das zu testen, aber vielleicht fällt euch ja so schon ein Fehler auf.

    [code=php]
    #!/usr/bin/python
    import RPi.GPIO as GPIO
    # Counter definieren
    a = 1
    b = 1
    # GPIO definieren
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    # Funktionen definieren
    def taster1(callback):
    global a = a + 1
    if a % 2 == 0:
    # Code ausführen
    sleep(x)
    else
    # Code ausführen
    a = 1
    sleep(x)
    def taster2(callback):
    global b = b + 1
    if a % 2 == 0:
    # Code ausführen
    sleep(x)
    else
    # Code ausführen
    b = 1
    sleep(x)


    GPIO.add_event_detect(25, GPIO.RISING, callback=taster1)
    GPIO.add_event_detect(27, GPIO.RISING, callback=taster2)

    While True:
    sleep(1)
    GPIO.cleanup()
    [/php]

    Der Code der ausgeführt werden soll, soll entweder ein Datenbankeintrag bzw. Ein Update sein, oder direkt eine PHP Variable, ich denke aber, dass eine Datenbank eine wesentlich bessere Datenkonsistenz bietet.

    Durch die Moduloberechnung soll sichergestellt werden, dass entweder eine 1 oder 0 je nach Restwert in die DB geschrieben wird. Die Daten aus der DB sollen dann mittels Ajax in meinem PHP Script nachgeladen werden.

    Bei sleep(x) soll eine sinnvolle Zeit rein, um die Funktion nicht mehrmals hintereinander auszuführen. Ich hoffe, dass das so möglich ist. Evtl. hat da ja sonst jemand eine bessere Idee.

    Feedback bzw. Verbesserungsvorschläge nehme ich gerne entgegen. Ich hoffe, das ganze funktioniert so überhaupt.

    Edit: Ein paar Einrückungsfehler haben sich eingeschlichen, die sind in meinem Ursprungscode nicht enthalten, bekomme die hier aber irgendwie nicht raus.

    Einmal editiert, zuletzt von KingBuzzo (25. März 2015 um 19:25)

  • Hallo KingBuzzo.

    Vlt. mal was grundsätzliches zu Interrupt's.

    Ein Interrupt wird genutzt um plötzlich auftretende oder schnelle Ereignisse mitzubekommen, das z.B für die main() zu umständlich,aufwendig oder nicht möglich wäre (siehe dauerndes pollen in der Main() um nen Taster abzufragen).

    Ein Interrupt ist nicht dazu gedacht in der ISR größere Arbeiten zu erledigen, die soll die main() oder ne sub machen.

    In der ISR setzt man i.d.R. nur Flags, die die main() über den Zustand des Tasters informiert, oder füllt ne Variable... mehr nicht.

    Einfaches Beispiel mit einem deiner Taster.
    Du machst ein:

    Code
    GPIO.add_event_detect(25, GPIO.RISING, callback=taster1up)


    d.h das ist ein Ereignisgesteuerter Int auf steigende Flanke. (und nicht wie du vlt. irrtümlicherweise angenommen hast ... der Int kommt sooft, solange der Pin dann high ist).
    Wer der Taster sauber entprellt ist, tritt wenn du den Taster drückst genau 1x der Int auf, du setzt in der ISR ein Flag, das du in der Main() abfragst und somit über den Taster Bescheid weist.
    taster1up wäre somit "gedrückt"
    Wenn er trotzdem noch prellt gibt es z.B.

    Code
    GPIO.add_event_detect(25, GPIO.RISING, callback = taster1up, bouncetime = 200)


    das "sperrt" einen nächsten Int einer steigenden Flanke an diesem Pin für 200mS

    Wie bekommst du aber per Int mit, ob der Taster wieder losgelassen wurde ?

    Was dir fehlt ist das:

    Code
    GPIO.add_event_detect(25, GPIO.FALLING, callback=taster1dwn)


    Ein Ereignisgestuerter Int auf fallende Flanke.
    sonst würdest du ja nie mitbekommen, dass er wieder losgelassewn wird.
    Also hier ein 2. Flag setzten oder das 1. rücksetzten.... und die main() weis wieder Bescheid.
    Das loslassen kannst dir selbstverständlich auch ersparen, wenn es dich nicht interessiert, denn der nächste Tastendruck kommst bestimmt :D
    Das war nur informativ.

    das hier ist tödlich

    Der Code der ausgeführt werden soll, soll entweder ein Datenbankeintrag bzw.


    in der ISR nen Datenbankeintrag... dauert rel. lange, sowas nie

    das hier ist der Tod inkl. Sense für das System... ein sleep in der ISR

    Zitat


    Bei sleep(x) soll eine sinnvolle Zeit rein, um die Funktion nicht mehrmals hintereinander auszuführen.


    Den sleep brauchst du nicht, wie oben erklärt, der jeweilige Int tritt ja nur einmal bei steigender und einmal bei fallender Flanke auf.
    Weiterhin blockierst du damit die gesammte main().

    ok soviel erst mal.
    Zusammenfassend: Interrupt's ja... aber so kurz wie möglich, denn jeder Int blockiert solange die main().
    Seh einen Int als sehr schnelle Reaktion auf einen "Ausnahmezustand" an.
    Der Int erfasst ihn, die Main() soll ihn behandeln.
    Wenn in der Int zuviel Zeit verbraten wird, kann ein nächster Int für den gleichen Int auftauchen ...mit der er noch gar nicht fertig ist... das Chaos ist damit perfekt.

    Ich hoffe ich hab mich verständlich ausgedrückt, und du versteht Int's jetzt bischen besser :D
    aber erstmal in Ruhe durchlesen :thumbs1:

    gruß root

    Einmal editiert, zuletzt von root (26. März 2015 um 01:45)

  • Hi,
    erstmal Danke für die Antwort, werde mich in Interrupts nochmal ein bisschen einlesen, bin in Python leider auch nicht wirklich fit.

    Die bouncetime scheint genau das zu sein, was ich brauche. Ich möchte genau das, der Interrupt soll für eine bestimme Zeit nicht mehr auf das Signal reagieren.

    Die nächste Frage ist, ob ich einen Interrupt für fallende Flanken brauche. Nur auf die steigende Flanke soll etwas folgen. Oder kann der Interrupt, wenn ich nicht auf eine fallende achte, nicht mehr ausgeführt werden? Es soll einfach bei nächsten Tastendruck der Interrupt wieder ausgelöst werden und durch die modulo operation, weiß das Script dann, dass es den Datenbankeintrag ändern muss.

    Das ganze werde ich dann mal in der main abarbeiten. Da muss ich mir dann was einfallen lassen.

    Grüße,
    KingBuzzo

  • hallo.


    Die nächste Frage ist, ob ich einen Interrupt für fallende Flanken brauche.


    Das liegt bei dir, brauchen tust du ihn nicht, dem System ist das egal.


    Nur auf die steigende Flanke soll etwas folgen. Oder kann der Interrupt, wenn ich nicht auf eine fallende achte, nicht mehr ausgeführt werden?

    Natürlich kann er das, ich denke du hast das ganze nocht nicht ganz verstanden.
    Nochmal kurz:

    Code
    GPIO.add_event_detect(25, GPIO.RISING, callback=taster1up)


    und

    Code
    GPIO.add_event_detect(25, GPIO.FALLING, callback=taster1dwn)


    sind zwei paar Stiefel.
    Die sind Ereignisgesteuert also egal ob einer der beiden scharf gemacht ist oder nicht.
    der "scharfgemachte" Int tritt eben dann auf, wenn das entspr. Ereignis eintritt... (steigende oder fallende Flanke.)

    Anders ausgedrückt:
    Du hast z.B den Int für die steigende Flanke aktiviert, aber keinen für die fallende Flanke. (Taste loslassen).
    Der Int "GPIO.RISING" (steigende Flanke) wird bei jedem erneutem Tastendruck ausgeführt... ob da irgendwann mal ne fallende Flanke dazwischen da war oder nicht ist ihm wurscht... die kennt er ja nicht, und dem System auch...du fragst ja nix nach was fallendem ab.

    Noch einfacher:
    Dein Programm schaltet z.B. nen Pin auf Eingang, fertig.
    Du hängst ne Taster dran dessen Eingang auf 3,3V geht , der andere auf den Pin.
    Du kannst die nächsten x-Jahre den Taster drücken/loslassen... was passiert ? ... nix.
    Du hast ja ausser den Pin auf Eingang zu setzen nix weiter aktiviert, obwohl sich Flanke und Pegel ändern.
    Sprich du bestimmst was das Proggi machen soll, nur verstehen must auch du es ;)

    Jetzt bißchen verständlicher ? :D
    Ich weiß, Interrupt's sind für rel. Unerfahrene bischen kompliziert... sind sie aber nicht :D
    Das kommt rel. schnell mit der Erfahrung ... :thumbs1:
    Man muss sich nur verinnerlichen was ein Int ist, wie er reagiert und was das für Auswirkungen hat.
    Ich will hier keine Bücher schreiben, sondern versuche dir nur bißchen auf die Sprünge helfen:)... ich weiß aller Anfang ist schwer.
    Vlt zur Aufmunderung... wenn man sie begriffen hat, sind Int's oft ein wahres Allheilmittel bei Problemen an denen man sich vorher die Haare gerauft hat :D

    gruß root

    Einmal editiert, zuletzt von root (26. März 2015 um 04:14)

  • Hi,
    nochmal Danke für deine Antwort. Ich denke, ich habe das ganze schon verstanden, dachte nur es wäre evtl. eine Eigenheit von Python z.B. das man auch auf fallende Flanken achten muss um den Interrupt nicht zu blockieren. Programmiersprachen haben da ja manchmal schon sehr komische Konstrukte.
    Ich brauche also für mein Vorhaben kein Interrupt für fallende Flanken.

    Macht es dann mehr Sinn im ISR nur ein Flag zu setzen und alles andere in der Main abzuhandeln oder kann ich die Moduloberechnung noch in der ISR lassen und setze dadurch dann Flags? So wie ich dich verstanden habe, sollte man so wenig wie möglich in der ISR machen, aber eine simple Moduloberechnung sollte doch eigentlich noch drinsitzen?!

    In der main soll eigentlich auch sonst nichts passieren, ausser das halt auf den Interrupt gewartet wird, mehr soll das ganze Programm garnicht machen.

  • Hallo


    ... aber eine simple Moduloberechnung sollte doch eigentlich noch drinsitzen?!

    ...klar kann die in der ISR sitzen ...:D
    ähm... hab bewusst etwas übertrieben ...:lol:
    Aber die Kürze einer ISR sollte man sich schon von Anfang an, immer vor Augen halten.
    Dann gutes Gelingen.

    gruß root

  • Soo, habe jetzt nochmal ein wenig weitergebastelt und hoffe ich komme der Lösung näher.
    Ich habe noch die Funktion GPIO.event_detected() und hoffe, dass ich diese für mein vorhaben nutzen kann.

    Hier erstmal der Code nur auf einen Taster reduziert.

    [code=php]
    #!/usr/bin/python
    import RPi.GPIO as GPIO
    # Counter definieren
    a = 1
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    def taster1(callback):
    global a = a + 1
    global tast1
    if a % 2 == 0:
    tast1 = 1
    else
    tast1 = 0
    a = 1;

    def main():
    GPIO.add_event_detect(25, GPIO.RISING, callback=taster1, bouncetime = 200)
    while true:
    try
    if GPIO.event_detected(25)
    if tast1 == 1:
    #Sqlite Update
    else
    #Sqlite Update

    except KeyboardInterrupt:
    GPIO.cleanup()

    GPIO.cleanup()

    if __name__ == '__main__':
    main()

    [/php]

    Einmal editiert, zuletzt von KingBuzzo (26. März 2015 um 16:31)

  • Hallo.


    Sorry, ich verstehe da etwas nicht (vielleicht auch mehreres): das Programm frisst 100% Rechenzeit ...


    die Frage versteh ich nicht ganz


    ... wozu der Interrupt, das bringt man mit pollen auch fertig?


    ...genau das ist doch der Sinn eines Interrupt's, um das lästige pollen zu vergessen.
    Pollen heist: in iner Schleife andauerndes fragen, hohe Auslastung.Von der man() getrennt, d.h, alles andere bleibt unberücksichtigt.
    Interrupt: pos. Flanke, neg. Flanke etc. wird nur dann ausgeführt, wenn es eintrifft.Aber das Programm bleibt bis zum Eintritt in der main()

    gruß root

    Einmal editiert, zuletzt von root (17. September 2015 um 18:26)

  • Ja ... Blödsinn von mit: ich dachte irgendwie die Hauptschleife "wartet" auf die Interrupts.

    Aber Zusatzfrage: wenn die Hauptschleife schwer beschäftigt ist und einige Interrupts passieren - werden die in eine Warteschlange gestellt oder überlebt nur der letzte?

    Sorry Zusatzfrage 2: wo gibt es mehr Info zum lesen und probieren was man mit Interrupts alles anstellen kann und wie.

    Danke

    Gottfried

  • Hallo Gottfried,

    was mit den Interrupts passiert, hängt in erster Linie von der Interrupt-Behandlungsroutine ab. Diese sollte vom Zeitumfang sehr kurz sein und eigentlich nur wenige Befehle umfassen. Dann kannst Du davon ausgehen, dass Ereignisse, die im ms oder auch > 10 µs-Bereich entstehen, auch alle einzeln erkannt und verarbeitet werden.

    Wenn Du aber beispielsweise eine Ausgabe in der Art "Taster rot" gedrückt um 10:15:34 [335336µs] - zuletzt wurde Taster grün um 10:15:34 [336332 µs] gedrückt", das Ganze noch in eine Log-Datei zu schreiben gedenkst, dann wird das nichts werden.

    Ich habe aus Demo-Zwecken mal einen Interrupt-Handler geschrieben, der auf Datei-Änderungen reagiert. Solche Änderungen liegen in einem ganz anderen Zeitintervall als herkömmliche Interrupts. Hier hast Du immer das Problem, das zwischen Erkennen eines Ereignisses und dessen Be- und Verarbeitung soviel Zeit vergehen kann, dass ein neues Ereignis passieren kann. In diesem Fall steigt die Wahrscheinlichkeit, dass innerhalb der Interrupt-Behandlung ein neuer Interrupt eintritt. Die Interrupt-Behandlung würde dann rekursiv aufgerufen und das neue Ereignbis behandeln. Und so weiter. Wenn mal nichts passiert würde die Behandlung frühere Ereignisse abschließen. Wenn die Ereignislosigkeit ausbleibt, würde es Dir früher oder später das System wegen "Stack Overflow" zum Absturz bringen.

    Ob die Hauptschleife schwer beschäftigt ist, hängt auch wieder vom delay ab. Ich habe beispielsweise Programme geschrieben, die solchen wie [font="Courier New"]top[/font] nachgebildet waren. [font="Courier New"]top[/font] hat zu einer Prozessorauslastung von 4 % beigetragen - meine Nachbildung dagegen nur zu 3 % bei gleichem Leistungsumfang und Aktualisierungsfrequenz. Die Prozessorauslastung ist in erster Linie abhängig vom delay (Verzögerung) innerhalb der Hauptschleife.

    Wenn Du relativ schnelle Ereignisse zu überwachen hast, dann bleibt Dir eigentlich nur die Möglichkeit, diese zu erfassen - und die Verarbeitung "später", also wenn mal keine Ereignise eintrudeln, ablaufen zu lassen.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Einmal editiert, zuletzt von Andreas (20. September 2015 um 10:27)

  • FAQ --> Nützliche Links / Linksammlung --> Interrupt

    Es ist zudem besser GPIO -> GND zu verwenden also einen Pull-Down. Das ist bei weitem nicht so Störanfällig.

    Ich hab mir hier jetzt zwar nicht alles durchlesen, aber was mir aufgefallen ist:

    Code
    GPIO.add_event_detect(25, GPIO.RISING, callback=taster1up)
    GPIO.add_event_detect(25, GPIO.FALLING, callback=taster1dwn)

    Das wird zum einen nicht funktionieren weil dann RPi.GPIO meckert, zum anderen ist das aber auch überflüssig da man stattdessen nur eine Zeile braucht:

    Code
    GPIO.add_event_detect(25, GPIO.BOTH, callback=taster_interrupt)

    Wenn es mehrere Taster sind wäre es zudem besser nur eine Callback zu verwenden, an diese wird nämlich immer der Pin übergeben an dem der ISR erkannt wurde - also brauch man dort dann nur prüfen ob die Übergabe zu einem bestimmten Taster-Pin gehört...


    Den sleep brauchst du nicht, wie oben erklärt, der jeweilige Int tritt ja nur einmal bei steigender und einmal bei fallender Flanke auf.
    Weiterhin blockierst du damit die gesammte main().

    Jein.
    Ein sleep oder allgemein blockieren der Callback ist schlecht und sollte vermieden werden - Ja. Aber die main() wird dabei nicht blockiert da diese in einem anderen Thread läuft. Das Script selbst läuft in einem Thread und das erkennen sowie die Callback läuft in einem anderen Thread. Nur deswegen ist es auch möglich dass das Script durch ein "while True: sleep(0.1)" daran gehindert wird sich zu beenden.

    Beispiel:

    [code=php]
    #!/usr/bin/python
    import RPi.GPIO as GPIO
    import time

    Taster1 = 25
    Taster2 = 27

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(Taster1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(Taster2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    def interrupt_event(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    if GPIO.input(pin) == GPIO.HIGH:
    print "{} Rising edge detected on {}".format(zeit, pin)
    else:
    print "{} Falling edge detected on {}".format(zeit, pin)
    if pin == Taster1:
    print "{} Spezial Taster {}".format(zeit, pin)

    def main():
    GPIO.add_event_detect(Taster1, GPIO.BOTH, callback=interrupt_event, bouncetime=200)
    GPIO.add_event_detect(Taster2, GPIO.BOTH, callback=interrupt_event, bouncetime=200)
    #keep script running
    while True:
    time.sleep(1)

    if __name__ == '__main__':
    try:
    main()
    except (KeyboardInterrupt, SystemExit):
    print "\nQuit\n"
    GPIO.cleanup()
    [/php]

    das Programm frisst 100% Rechenzeit

    Dann ist der "keep script running" zu niedrig oder fehlt.
    Ein "while True:" dreht sich unheimlich schnell im Kreis. Tut es das ungebremst wird 100% CPU Last erzeugt. Um das zu verhindern muss man zumindest ein ' time.sleep(0.1) ' einbauen oder eine andere Möglichkeit um das Script daran zu hindern sich zu beenden - Code wird immer von oben nach unten abgearbeitet. Ich nutze dafür auch gerne das Module 'signal'.

    Ein Interrupt ist generell nicht so CPU-Lastig wie die von dir erwähnte 'poll'-Methode, zumal diese wie gesagt das Problem birgt einen Flankenwechsel zu verpassen, denn entweder man fügt ein sleep in die while ein und blockiert somit auch das prüfen auf einen Flankenwechsel, oder durch ausführen weiterer Aktionen wie das Einfügen in eine Datenbank o.ä. wird das Script ebenfalls blockiert...

    Wie oben erklärt läuft der mithilfe von RPi.GPIO verwendete Interrupt in einem separaten Thread, also quasi einem eigenständigen Prozess/Programm unabhängig vom Script. Das Script ist der sog. Mother-Prozess und der Interrupt ein Child-Prozess.
    Der Interrupt kann aber selbstverständlich auf Variablen oder Funktionen des Scripts zugreifen, sofern diese vorher definiert wurden (also über/vor der " GPIO.add_event_detect " Zeile).

    Wie root und Andreas aber auch schon erwähnte ist es wichtig in der Callback so wenig wie möglich zu machen - am besten nur ein paar Variablen ändern und diese dann im Script in besagter 'while' prüfen bzw weiter verarbeiten. Aber auch hier besteht natürlich das Problem das Änderungen von Variablen verpasst werden wenn die 'while' zu viel zu tun hat...

    Es gibt aber für alles eine Lösung - wäre jetzt nur IMHO zu viel auf einmal zu erklären ;)

    [an=Queue]Das imho beste wäre ein queue[/an]:
    [code=php]
    #!/usr/bin/python
    from __future__ import print_function
    import RPi.GPIO as GPIO
    import time
    import Queue # https://pymotw.com/2/Queue/

    #------------------------------------------------------------------------
    # use the raspi board pin number
    #GPIO.setmode(GPIO.BOARD)
    # use the gpio number
    GPIO.setmode(GPIO.BCM)

    # only one of following for GPIO.IN:
    PULL = GPIO.PUD_DOWN #GPIO -> GND
    #PULL = GPIO.PUD_UP #GPIO -> 3V3

    Taster1 = 25
    Taster2 = 27
    #------------------------------------------------------------------------

    GPIO.setup(Taster1, GPIO.IN, pull_up_down=PULL)
    GPIO.setup(Taster2, GPIO.IN, pull_up_down=PULL)

    queue = Queue.Queue()

    def cputemp():
    with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
    CPUtemp = int(float(f.readline().split()[0]))
    CPUtemp = round((CPUtemp/1000.0), 2)
    return CPUtemp

    def veryBusy():
    print("..Im super heavy busy..")
    time.sleep(5)
    print("..puh..")
    time.sleep(5)
    print("..thats too much for me..")

    def interrupt_event(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    if GPIO.input(pin) == GPIO.HIGH:
    print("{} Rising edge detected on {}".format(zeit, pin))
    queue.put(pin)
    else:
    print("{} Falling edge detected on {}".format(zeit, pin))

    def main():
    GPIO.add_event_detect(Taster1, GPIO.BOTH, callback=interrupt_event, bouncetime=200)
    GPIO.add_event_detect(Taster2, GPIO.BOTH, callback=interrupt_event, bouncetime=200)
    #keep script running
    while True:
    if not queue.empty():
    job = queue.get()
    if job == Taster1:
    print(cputemp())
    elif job == Taster2:
    veryBusy()
    time.sleep(0.5)

    if __name__ == '__main__':
    try:
    main()
    except (KeyboardInterrupt, SystemExit):
    print("\nQuit\n")
    GPIO.cleanup()
    [/php]


  • Es ist zudem besser GPIO -> GND zu verwenden also einen Pull-Down. Das ist bei weitem nicht so Störanfällig.

    Bist Du Dir da wirklich sicher? Ich habe genau die entgegengesetzte Erfahrung gemacht und habe mir das damit erklärt, dass sich Störungen als Spannungssptitzen (woher auch immer) also high zeigen. Ein mit einem Pullup bereits auf high gezogener GPIO kann nicht "higher" werden. Ziehe ich den GPIO nun mit einem Schalter auf low haben diese Spitzen auch keinen Einfluss, da der Schalter faktisch die Signalleitung gegen GND kurzschließt. Baue ich es umgekehrt, also mit z.B. 10k Pulldown, können Spannungsspitzen immer noch dafür sorgen, dass der GPIO auf high gesetzt wird.

    Hast du da andere Erfahrungen gemacht?

  • Hallo Jörg,

    Du kannst Dir ja mal spaßeshalber ausrechnen, welcher Art die eingefangenen Impulse sein müsste, um trotz 10k Widerstand noch ein Signal von > 1,3 V erzeugen zu können. :s Eben! Genau deswegen setzt man einen solche hohen Widerstand ein.

    Für mich ist PullDown und PullUp gleichwertig - vorausgesetzt die Widerstände sind ausreichend bemessen.


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Wie gesagt ist das eine Erfahrung aus meinen Projekten heraus. Wobei ich nicht ganz verstehe was Du meinst. Wenn ich hier meinen Oszi anschmeiße und z.B. meine Arbeitsleuchte Leuchtstoffröhre starte, habe gerade wegen des großen Widerstandes teilweise 7V Impulse auf der Datenleitung. Also um so höher der Pulldown um so größer die Störanfälligkeit.

Jetzt mitmachen!

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