Interrupt wird nicht erkannt

  • Hi

    Habe ein Testprogramm für einen Interrupt an einem GPIO Pin jedoch erkennt er den Taster Druck nicht -> er springt nicht in die ISR. Hat jemand eine Ahnung an was es liegen kann.

    PS: GPIO lib auf neuester Version durch api-update und upgrade hab ich schon gemacht.

    Dankeschön
    Hier der code:

    import RPi.GPIO as GPIO
    import time


    # Variable Counter definieren
    Counter = 0


    # Variable zum debouncen
    Debounce = 0


    # SoC als Pinreferenz waehlen
    GPIO.setmode(GPIO.BOARD)


    # Pin 24 vom SoC als Input deklarieren und Pull-Down Widerstand aktivieren
    GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)


    # ISR
    def Interrupt(channel):
    # Zugriff auf globale Variablen
    global Counter


    # Counter um eins erhoehen und ausgeben
    Counter = Counter + 1
    print ("Counter " + str(Counter))

    # Interrupt Event hinzufuegen. Pin 24, auf steigende Flanke reagieren und ISR "Interrupt" deklarieren
    GPIO.add_event_detect(24, GPIO.BOTH, callback = Interrupt, bouncetime = 200)

    # Endlosschleife
    while True:
    time.sleep(1)

  • GPIO.setmode(GPIO.BOARD)

    Dadurch wird die Pin-Nummer auf dem Board verwendet. Pin#24 ist also GPIO8. Was bzw Wie hast du daran angeschlossen?


    PS: Das nächste mal bitte in CODE posten

  • Hi,
    ich schliesse mich da meigrafd an. Der Vollständigkeit halber noch Folgendes:
    bitte -> Fritzing <-, -> eagle <- oder ähnlich für eine Skizze verwenden.
    Alles andere lässt zu viel Raum für Spekulationen bzw. offene Fragen.

    Thnx,
    -ds-

  • Hm, da du aber auch PULL_DOWN verwendest, solltest du GPIO -> Taster -> GND beschalten, eben Down :fies:

    Zitat

    [...] input channel and 3.3V (pull-up) or 0V (pull-down) [...]

    quelle: http://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/

    Der GPIO ist der 'input channel'. 0V ist GND


    Das von dir verwendete Beispiel von http://kampis-elektroecke.de/?page_id=3740 ist aber auch ein bisschen ungünstig - man sollte so gut es geht 'global' für normale Variablen vermeiden.

    Deine Abänderung des Codes deutet auch hoffentlich auf python3 hin, wegen deiner Verwendung von 'print'. Wenn nicht sei gesagt das python3 in einigen Dingen anders zu handhaben ist als python2 und das Beispiel von kampis-elektroecke sich auf python2 bezieht, du aber 'print' von python3 verwendest...


    Der Vollständigkeit halber um das setzen von 'global' zu vermeiden wäre die wie ich finde einfachste Möglichkeit, stattdessen ein Dictionary zu verwenden. Und gleich dazu noch ein paar kleinere Verschönerungen:

    Spoiler anzeigen

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

    #GPIO pins
    Taster = 24

    # SoC als Pinreferenz waehlen
    GPIO.setmode(GPIO.BCM)

    # Pin 24 vom SoC als Input deklarieren und Pull-Down Widerstand aktivieren
    PULL = GPIO.PUD_DOWN #GPIO -> GND
    #PULL = GPIO.PUD_UP #GPIO -> 3V3
    GPIO.setup(Taster, GPIO.IN, pull_up_down = PULL)

    # Dictionary Counter definieren. http://www.tutorialspoint.com/python/python_dictionary.htm
    dictionary = {}
    dictionary['Counter'] = 0

    # ISR
    def Interrupt(channel):
    # Counter um eins erhoehen und ausgeben
    dictionary['Counter'] += 1
    print "Counter " + str(dictionary['Counter'])

    # Interrupt Event hinzufuegen. Pin 24, auf steigende Flanke reagieren und ISR "Interrupt" deklarieren
    GPIO.add_event_detect(Taster, GPIO.RISING, callback = Interrupt, bouncetime = 200)

    # Endlosschleife
    while True:
    time.sleep(1)
    [/php]Das Dictionary ist automatisch global, da es außerhalb einer Funktion deklariert wird.
    Durch "dictionary = {}" wird das Dictionary initialisiert. Anschließend kann man Keys dafür definieren, wie hier 'Counter' als String. Man kann auch beliebig andere Keys festlegen.

    Das nächste was man aber auch noch anmerken sollte wäre das diese Endlosschleife am Ende des Scripts ebenfalls nicht sehr schön ist, da dies mehr CPU Last erzeugt.
    Hintergrund wieso man das hier macht ist dass das Script ansonsten beendet wird. Scripts werden generell von oben nach unten abgearbeitet und es gibt in diesem Beispiel nichts was das Script beim erreichen des Endes daran hindert sich zu beenden. Also setzt man vereinfacht eine Endlosschleife... Aber das geht auch besser und würde dann auch weitaus weniger Aufmerksamkeit der CPU abverlangen.
    Ich hab mir angewöhnt dafür 'signal' zu verwenden:

    Spoiler anzeigen

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

    #GPIO pins
    Taster = 24

    # SoC als Pinreferenz waehlen
    GPIO.setmode(GPIO.BCM)

    # Pin 24 vom SoC als Input deklarieren und Pull-Down Widerstand aktivieren
    PULL = GPIO.PUD_DOWN #GPIO -> GND
    #PULL = GPIO.PUD_UP #GPIO -> 3V3
    GPIO.setup(Taster, GPIO.IN, pull_up_down = PULL)

    # Dictionary Counter definieren. http://www.tutorialspoint.com/python/python_dictionary.htm
    dictionary = {}
    dictionary['Counter'] = 0

    # ISR
    def Interrupt(channel):
    if GPIO.input(channel):
    print "Rising edge detected on %s" % channel
    else:
    print "Falling edge detected on %s" % channel

    # Counter um eins erhoehen und ausgeben
    dictionary['Counter'] += 1
    print "Counter " + str(dictionary['Counter'])


    # Interrupt Event hinzufuegen. Pin 24, auf steigende Flanke reagieren und ISR "Interrupt" deklarieren
    GPIO.add_event_detect(Taster, GPIO.BOTH, callback = Interrupt, bouncetime = 200)

    # Endlosschleife. keep script running
    signal.pause()
    [/php]Hier hab ich auch noch RISING oder FALLING edge -> BOTH geändert, damit auch dieser Unterschied ersichtlich wird.


    Desweiteren wäre auch noch anzumerken (als nächster Schritt zur Verbesserung) das man einige 'try' und 'except' einbauen sollte um Fehler abzufangen, aber auch um ein sauberes Beenden beim drücken von STRG+C zu erreichen - also um aus der 'Endlosschleife' wieder raus zu kommen. Wenn man das einfügt kann man die GPIO's dann nämlich auch sauber auf 'Werkseinstellung' zurücksetzen und beim nächsten mal starten erscheinen keine Fehlermeldungen...

    Spoiler anzeigen

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

    #GPIO pins
    Taster = 24

    # SoC als Pinreferenz waehlen
    GPIO.setmode(GPIO.BCM)

    # Pin 24 vom SoC als Input deklarieren und Pull-Down Widerstand aktivieren
    PULL = GPIO.PUD_DOWN #GPIO -> GND
    #PULL = GPIO.PUD_UP #GPIO -> 3V3
    GPIO.setup(Taster, GPIO.IN, pull_up_down = PULL)

    # Dictionary Counter definieren. http://www.tutorialspoint.com/python/python_dictionary.htm
    dictionary = {}
    dictionary['Counter'] = 0

    # ISR
    def Interrupt(channel):
    if GPIO.input(channel):
    print "Rising edge detected on %s" % channel
    else:
    print "Falling edge detected on %s" % channel

    # Counter um eins erhoehen und ausgeben
    dictionary['Counter'] += 1
    print "Counter " + str(dictionary['Counter'])

    try:
    # Interrupt Event hinzufuegen. Pin 24, auf steigende Flanke reagieren und ISR "Interrupt" deklarieren
    GPIO.add_event_detect(Taster, GPIO.BOTH, callback = Interrupt, bouncetime = 200)
    # Endlosschleife. keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    GPIO.cleanup()
    print "\nQuit\n"
    [/php]


    Das sollte erst mal als Crashkurs reichen :fies:

  • das ``dict`` ist genau so global wie das andere global. Da ändert sich rein gar nichts. Auf Modulebene sollen nur Konstante, Funktionen und Klassen definiert werden.

    Mittels ``top`` Befehl sehe ich keinen Unterschied zwischen einer ``while`` Schleife mit einer Unterbrechung von 1ms und der ``signal.pause()`` Funktion. Beides wird mit 0.0% CPU Last und 1.3% MEM ausgegeben.

    Des Weiteren einspricht die Namenskonvention nicht Python und darum würde ich diesen "Crashkurs " eher als mahnendes Beispiel ansehen, wie man es nicht machen soll. ;)

  • Hallo,


    Des Weiteren einspricht die Namenskonvention nicht Python und darum würde ich diesen "Crashkurs " eher als mahnendes Beispiel ansehen, wie man es nicht machen soll. ;)


    +1 :)

    Als Ergänzung noch: `dict` ist der Name einer Built-in Python Klasse (Link) und von daher ein dankbar schlechter Name für eine Variable. Dann können nämlich so unschöne Sachen passieren wie:

    [code=php]>>> dict = 0
    >>> a = dict(one=1, two=2, three=3)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: 'int' object is not callable
    >>>
    [/php]

    während der Aufruf `>>> a = dict(one=1, two=2, three=3)` ohne vorheriges `dict = 0` funktionieren würde...

    Und die Verwendung eines Dictionary macht hier so wie so keinen Sinn, weil nur der einer Schlüssel zum Zählen angelegt wird. Dann kann man auch direkt `counter = 0` nehmen.

    Gruß, noisefloor

  • bootsmann: War klar das du dich erst jetzt dazu meldest. Leider machst du auch dies mal nichts außer meckern, aber zeigst nicht wie das stattdessen ginge - wohlgemerkt ohne irgendwelche PEP's oder andere Links zu posten...

    Wir könn das aber gerne noch mal (haben wir schon mal durchgekaut) diskutieren:

    'top' aktualisiert sich standardmäßig nur alle 3 Sekunden. Es wäre also schon großer Zufall wenn du genau dann den Wechsel (ende des blockierenden sleeps, erneut starten der while, erneut starten des blockierenden sleeps) der while mitkriegen würdest.
    Aber selbst wenn du den Update-Intervall auf 1 Sekunde runter stellst ( top -d1 ) ist die Wahrscheinlichkeit weiterhin gering den passenden Moment zu treffen. Erst ein Update-Intervall von z.B. 0,1 ( top -d0,1 ) könnte dich in die Lage versetzen den Unterschied zwischen 'sleep' und 'signal' zu bemerken, aber auch nur wenn du wirklich gute Augen hast - aber dann erzeugt 'top' ebenfalls eine sehr hohe Last (weswegen ich 'top' auch nicht mag).
    Besser wärs über /proc/ die Last des Prozesses direkt auszuwerten - aber das wiederhole ich jetzt nicht noch mal.

    Der Name der ISR Funktion ist nicht auf mein Mist gewachsen. Beschwer dich diesbezüglich also bitte beim Urheber: http://kampis-elektroecke.de
    Ich wollte aber auch nicht auf ein Schlag zu viel verändern, das kann man dann immer noch... Aber dank dir weiß man ja jetzt auch das da 'irgendwas' nicht passt - nur leider wie üblich nicht detailliert genug also kann aus deinem Post nichts dazu gelernt werden (nur wie man kontinuierlich dekonstruktiv meckert)
    Aber weiterführende 'Crashkurs' Beiträge kann ich mir hier jetzt auch schenken, die gingen dann unter ....


    Also, hier der Aufruf an dich:

    Wie kann man bei Verwendung des ISR's einen Counter hoch zählen lassen, ohne 'global' :s
    :denker:


    Als Ergänzung noch: `dict` ist der Name einer Built-in Python Klasse (Link) und von daher ein dankbar schlechter Name für eine Variable.

    Aha oke, dann änder ich das mal... War mir auch erst nicht sicher, wollte ursprünglich 'dictionary' verwenden.
    Aber interessant das auch andere Tutorials dies missachten :denker:

    Dann kann man auch direkt `counter = 0` nehmen.

    Dann kann man ihn aber nicht hochzählen - ansonsten gäbs mit 'global counter' auch wieder für dich/bootsmann was zu meckern ....

    Aber wie gesagt, macht Vorschläge wie mans anders/besser machen kann. Denn ich mach mir zumindest die Mühe sowas zu erarbeiten und zu posten, aber nur meckern ist nicht so der Hit..

  • @maigrafd: Wir hatten da doch schon letztens einen anderen Thread wo das Thema behandelt wurde. Jetzt bin ich mal gespannt auf die Antwort vom bootsmann :shy:

    @maigrafd:

    Sorry, wir haben noch nicht Mai aber es wissen wohl auch so alle wer gemeint war: meigrafd :lol:

  • Hallo,

    meigrafd: Wieso kann man `counter` nicht hochzählen? Klar geht das:

    [code=php]>>> my_dict = {}
    >>> my_dict['counter'] = 0
    >>> my_dict['counter'] = my_dict['counter'] +1
    >>> my_dict['counter']
    1
    >>> counter = 0
    >>> counter = counter + 1
    >>> counter
    1
    >>>
    [/php]

    Ob die eine "direkte" Variable hochzählst oder einen Dict-Schlüssel ist ziemlich gleich.

    Das macht zwar den Gebrauch einer globalen Variablen zwar nicht besser, funktioniert aber ;)

    Gruß, noisefloor

  • Nachträglich sei noch zu sagen, dass je nach Kontext der Ball auch mal flach gehalten werden muss (ja, damit meine ich mich ;)
    Die ganze Diskussion bzgl. ``global`` richtet sich auch an Anfänger, damit diese bei grösseren Programmen darauf verzichten. Neulich erst, war es hier oder im Python Forum, hat jemand ein Programm gezeigt inkl. GUI und wusste nicht, warum sich ein Label nicht so veränderte wie er es wollte. Nachdem er/sie/es die ganzen globalen Scheußlichkeiten sachgemäß entfernte, ging es. Der Grund war, dass eine Methode die Variable permanent überschrieb...

    Zugegeben, bei so einem mini Programm würde ich auch keine Klasse oder eine wrapper-Funktion schreiben oder eine Oracle Enterprise Datenbank dranhängen oder weiss der Teufel was; dies wäre mir auch zu blöd.

    Bsp 1:

    Edit:
    Ein Fehler im Programm ausgebessert. Ob das läuft weiss ich nicht, hab hier einen RPi. Kanns also erst morgen sagen, sei sei denn, jemand testet es...


  • Hallo,

    meigrafd: Wieso kann man `counter` nicht hochzählen? Klar geht das:

  • ...geht trotzdem nicht... selber fehler...

    GPIO brauch man nicht um die Funktion aufzurufen

    Spoiler anzeigen

    [code=php]root@RoPi:~# python
    Python 2.7.3 (default, Mar 18 2014, 05:13:23)
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from __future__ import print_function
    >>> from functools import wraps
    >>> PIN = 24
    >>> def counter(func):
    ... @wraps(func)
    ... def counting():
    ... counting.count += 1
    ... return func()
    ... counting.count = 0
    ... return counting
    ...
    >>> @counter
    ... def print_count_pushed_button(PIN):
    ... print(print_count_pushed_button.count)
    ...
    >>> print_count_pushed_button(PIN)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    TypeError: counting() takes no arguments (1 given)
    >>> [/php]

    ..ein versuch noch - dann wirds aber langsam lachhaft.. an meinem code rum meckern aber selber nix gebacken kriegen :s

Jetzt mitmachen!

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