Timer interrupt abfrage GPIO

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

Hallo zusammen,

ich habe das Problem, dass ich mehrere Taster welche an meinem GPIO angeschlossen sind auswerten möchte. Unter anderem auch ein ADC der über I2C angeschlossen ist.
Ich habe bisher viel mit C gearbeitet. Hier war es möglich einen Timer zu starten, der alle x ms ein Interrupt auslöst und dann die GPIOs abfragt.
Gibt es in Python auch die Möglichkeit? Habe bisher nichts passendes gefunden. Bin nur auf Threading gestoßen, da bin ich mir aber nicht sicher, ob es das ist was ich brauche.

Oder wie realisiere ich es am besten, dass alle x ms meine GPIO und mein ADC abgefragt werden?
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo basti2s,
wenn Du keine Gui hast, bau dir einen Taktgeber mit dem time Modul.
Mit Gui, da sollte schon etwas dabei sein.
Gruss Peter
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

meinst du ich soll extern einen Taktgeber an den Pi anschließen und diesen pin dann mittels Interrupt abfragen?

Ich war bisher am überlegen, einen Thread zu erstellen, in dem eine Whileschleife ist und die GPIOs überwacht und dann die entsprechenden Funktionen aus dem Hauptprogramm ausführt.

edit: ich habe keine gui
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Mit welcher zeitlichen Genauigkeit willst Du denn die Eingänge abfragen?
Mit Threads kann man recht einfach im Hintergrund regelmäßig einen ADC per i2c abfragen.
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

Sirius3 hat geschrieben: Freitag 11. Dezember 2020, 12:07 Mit welcher zeitlichen Genauigkeit willst Du denn die Eingänge abfragen?
Das weiß ich auch noch nicht so genau. Es sollen halt Taster und ein ADC abgefragt werden. Ich denke alle 10ms ist ein guter Wert, um keinen Tastendruck zu verschlafen?
Sirius3 hat geschrieben: Freitag 11. Dezember 2020, 12:07 Mit Threads kann man recht einfach im Hintergrund regelmäßig einen ADC per i2c abfragen.
Genau das ist ja auch geplant. Ich hätte quasi ein Thread, der mir alle 10ms meine GPIOs und meinen ADC abfragt.
Ich versteh momentan leider nur nicht wie ich dann die gewonnenen Informationen weiterverarbeiten kann. Also rufe ich aus meinem Thread dann einfach eine Funktion auf, oder macht man das so, dass man aus dem Hauptthread die Werte aus dem Thread abfragt?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

10ms ist ziemlich sportlich und viel zu viel. Es gibt fuer GPIOs "Interrupts", durch die du von Tastendruecken in Kenntnis gesetzt wirst. Die sollten diese Tatsache per queue.Queue an den Main-Thread kommunizieren, und der wertet das dann gesammelt aus.
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

wenn der gesamte Code nicht sehr komplex ist, würde ich das so realisieren:

Code: Alles auswählen

import time

def bastis_code():
    while True:
        nano_sek = time.time_ns()
        milli_sek = int(nano_sek / 1000000)
                
        if milli_sek % 2000 == 1:
            print(" 2 Sekunden",  milli_sek)
            taster_auslesen()
        else:
            bastis_weiterer_code()

def taster_auslesen():
    pass

def bastis_weiterer_code():
    pass
                  
if __name__ == "__main__":
    bastis_code()
Gruss Peter
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

__deets__ hat geschrieben: Freitag 11. Dezember 2020, 12:58 Es gibt fuer GPIOs "Interrupts"
Ja, ich habe das ganze auch anfangs über Interrupts versucht, jedoch hatte ich da das Problem, dass meine Taster so stark prellen und ich das ganze lieber periodisch abfragen würde um quasi zu entprellen.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dazu gibt es Mittel und Wege, wie zB bouncetime Argumente eben fuer dieses Verhalten. Oder sich das selbst zu programmieren, indem man Ereignisse eine gewisse Weile lang ignoriert. Das ist alles zielfuehrender, als schlussendlich zu pollen.
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

nichts destotrotz brauche ich das periodische Abfragen für meinen ADC.
Und da ist eben die Frage, wie man das richtig macht. Also die Werteübergabe vom Thread in den Hauptthread? Dazu finde ich nicht wirklich was. Nur leute die das mit globalen Variablen machen...
Zuletzt geändert von basti2s am Freitag 11. Dezember 2020, 14:35, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann mach's halt alle 10ms, wenn es sonst nicht geht.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nachtrag: ich habe schon queue.Queue erwaehnt, und damit macht man die Uebergabe zwischen Threads. Und mit functools.partial auch ohne globale Variablen.

Code: Alles auswählen

import time
import queue
import threading


def background_loop(q):
    while True:
        time.sleep(.1)
        q.put("pillepalle")


def main():
    q = queue.Queue()
    t = threading.Thread(target=background_loop, args=(q, ))
    t.daemon = False
    t.start()
    while True:
        print(q.get())


if __name__ == '__main__':
    main()

basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

Okay, ich komme leider noch nicht ganz mit den queues zurecht.
Ich würde dann quasi in dem background_loop die zustände meines GPIOs oder meines ADCs schreiben. Und dann kann ich den Zustand im Mainthread mittels if abfragen bzw. weiter verwenden?

Wieso nehme ich nicht einfach eine Liste? Ich möchte ja nur die zustände meines background_loop auslesen. Es soll ja kein anderer thread die Werte verändern. Also sollte das doch trotz liste Multithreading sicher sein?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum willst du denn eine Liste? Die queue kenn put und get, und kuemmert sich dann selbst um's aufraeumen. Ausserdem kann das get entweder blockieren, oder definiert warten, bevor es weiter macht, falls nichts drin ist. Das willst du also muehselig alles selbst zusammenfrickeln?

Und was heisst dieses "komme nicht klar"? Du redest viel darueber, was so alles geht und nicht geht, aber zeigst keinen Code und keine Fehlermeldungen. Damit kann man halt auch nix anfangen.
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

mir geht es gerade vielmehr um das prinzipielle verständnis.

Angenommen ich möchte zwei ADC Kanäle und zwei GPIO Eingänge in dem Thread überwachen lassen. Dann hätte ich das so gemacht:

Code: Alles auswählen

import time
import queue
import threading
import RPi.GPIO as GPIO


def background_loop(q):
    GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    while True:
        if GPIO.input(12):
           q.put ("12on")

q = queue.Queue()
t = threading.Thread(target=background_loop, args= (q, ))
t.deamon = False
t.start()

while True:     
    if (str(q.get()) == "12on"):
        print ("Pin 12 ist high")

In dem Backgroundloop würde ich dann noch für jeden ADC Kanal eine queue erstellen. Den zusätzlichen GPIO pin kann ich ja mit auf die Queue q legen. Ist das totaler quatsch oder kann man das so machen?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde keine weitere queue erstellen, sondern einfach verschiedene Nachrichten in die queue stecken, je nach dem, von wem die jetzt kommt.
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

alles klar. Jetzt stellt sich mir nurnoch die Frage, ob es schlauer wäre anstelle der while-Schleife in dem Thread periodisch aufzurufen (alle 50 ms oder so).
Ich hatte da mal was von einem Treadingtimer gelesen. Finde leider nicht mehr das entsprechende Codeschnipsel
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Was meinst Du mit anstelle der while-Schleife? Da würde man doch einfach nur ein 50ms `sleep()` in die Schleife schreiben. Oder mit Berechnung der vergangenen Zeit seit dem letzten Schlafen etwas weniger als 50ms.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
basti2s
User
Beiträge: 29
Registriert: Samstag 14. November 2020, 08:36

Da hast du natürlich recht. Stand da grad auf dem Schlauch
Antworten