31. Lektion: Interrupts

Aus Attraktor Wiki

Wechseln zu: Navigation, Suche

Interrupts

Die Interrupts funktionieren NICHT mit der REPL. Also immer aus dem Editor starten! 

Was ist ein Interrupt?

Interrupt bedeutet unterbrechen. Genau das macht ein Interrupt. Er unterbricht das laufende Programm und führt stattdessen eine Interrupt-Service-Routine aus. Anschließend wird das zuvor unterbrochene Programm fortgesetzt. Interrupts werden in der Regel von einer Hardware ausgelöst. Z.B.

  • Taster
  • Timer
  • ADC

Um einen Interrupt zu implementieren sind 2 Dinge erforderlich:

  1. Eine Interrupt-Service-Routine (ISR) auch Callback-Funktion (Cb) oder Interrupt Handler genannt, die den Interrupt bearbeitet.
  2. Eine Interruptquelle, die mit der ISR verbunden wird.

Micropython kennt 2 Interruptquellen:

  1. Pin-Interrupts
  2. Timer-Interrupts


Micropython stellt für die Pin Interrupts bereit. Dazu dient die Methode Pin.irq().

>>> from m5import import *
>>> from machine import Pin
>>> dir(Pin)
['__class__', '__name__', 'value', '__bases__', '__dict__', 'IN',
'IRQ_FALLING', 'IRQ_RISING', 'OPEN_DRAIN', 'OUT', 'PULL_DOWN',
'PULL_HOLD', 'PULL_UP', 'WAKE_HIGH', 'WAKE_LOW', 'init', 'irq', 'off', 'on']

Interrupts einrichten

Die Interruptfunktion ist eine Methode der Klasse Pin.
Wir müssen 3 Dinge tun um einen Interrupt zu implementieren:

  1. Zuerst muss der Pin als Eingang konfiguriert werden.
  2. Dann sollte der Handler definiert werden.
  3. Und schließlich kann der Interrupt eingerichtet werden.
Pin.irq(handler=None, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, *, priority=1, wake=None, hard=False)
Beispiel

Hier mit Lambda-Funktion als Interrupt-Handler.

# int_test_01.py

from machine import Pin

int_pin = Pin(14, Pin.IN, Pin.PULL_DOWN)
led_pin = Pin(22, Pin.OUT)
led_pin.value(1)

int_pin.irq(handler=lambda t:led_pin.toggle(), trigger=int_pin.IRQ_RISING)

Interrupt Trigger

Pin.IRQ_FALLING
Pin.IRQ_RISING
Pin.IRQ_LOW_LEVEL
Pin.IRQ_HIGH_LEVEL

Trigger können auch ODER (|) verknüpft werden (Pin.IRQ_FALLING | Pin.IRQ_RISING) .

Interrupt Handler

# Source: Electrocredible.com, Language: MicroPython
from machine import Pin
import time
interrupt_flag=0
debounce_time=0
pin = Pin(5, Pin.IN, Pin.PULL_UP)
led = Pin("LED", Pin.OUT)
count=0

def callback(pin):
    global interrupt_flag, debounce_time
    if (time.ticks_ms()-debounce_time) > 500:
        interrupt_flag= 1
        debounce_time=time.ticks_ms()

pin.irq(trigger=Pin.IRQ_FALLING, handler=callback)

while True:
    if interrupt_flag is 1:
        interrupt_flag=0
        print("Interrupt Detected")
        led.toggle()

Interrupts aus dem Kurs von 2022

13.02.2023 Micropython Kurs 2022 1 Interrupts Was ist ein Interrupt? Interrupt bedeutet unterbrechen. Genau das macht ein Interrupt. Er unterbricht das laufende Programm und führt stattdessen eine Interrupt-Service-Routine aus. Anschließend wird das zuvor unterbrochene Programm fortgesetzt. Interrupts werden in der Regel von einer Hardware ausgelöst. Z.B. Taster, Timer oder ADC
Um einen Interrupt zu implementieren sind 2 Dinge erforderlich: ● Eine Interrupt-Service-Routine (ISR) auch Callback- Funktion (Cb) oder Interrupt Handler genannt, die den Interrupt bearbeitet. ● Eine Interruptquelle, die mit der ISR verbunden wird. Micropython kennt 2 Interruptquellen: ● Pin-Interrupts ● Timer-Interrupts
Micropython stellt für die Pin Interrupts bereit. Dazu dient die Methode Pin.irq().

>>> from m5import import *
>>> from machine import Pin
>>> dir(Pin)
['__class__', '__name__', 'value',
'__bases__', '__dict__', 'IN',
'IRQ_FALLING', 'IRQ_RISING',
'OPEN_DRAIN', 'OUT', 'PULL_DOWN',
'PULL_HOLD', 'PULL_UP', 'WAKE_HIGH',
'WAKE_LOW', 'init', 'irq', 'off',
'on']

Wir müssen 3 Dinge tun um einen Interrupt zu implementieren: 1. Zuerst muss der Pin als Eingang konfiguriert werden. 2. Dann sollte der Handler definiert werden. 3. Und schließlich kann der Interrupt eingerichtet werden.

# Pin von Button A konfigurieren
from m5import import *
from machine import Pin
int_pin = Pin(37, Pin.IN, Pin.PULL_UP)
def int_handler():
pass
int_pin.irq(trigger=Pin.IRQ_FALLING,
handler=int_handler)
from m5import import *
from machine import Pin
from time import sleep_ms
lcd.clear()
main_loop_zahl = 0
interrupt_zahl = 0
main_text_box =
M5TextBox(20, 10, str(main_loop_zahl), lcd.FONT_DejaVu24, 0xFFFFFF, rotate=0)
interrupt_text_box =
M5TextBox(120, 10, str(interrupt_zahl), lcd.FONT_DejaVu24,0xFFFFFF, rotate=0)
int_pin = Pin(37, Pin.IN, Pin.PULL_UP) # Pin von Taster A mit Pullup-R
def int_handler(int_info): # muss einen Parameter haben
global interrupt_zahl
global interrupt_text_box
interrupt_zahl += 1
interrupt_text_box.setText(str(interrupt_zahl))
interrupt_text_box.show()
print('Interrupt wurde ausgelöst!')
return
int_pin.irq(trigger=Pin.IRQ_FALLING, handler=int_handler)
while True:
main_loop_zahl += 1
main_text_box.setText(str(main_loop_zahl))
main_text_box.show()
sleep_ms(1000)

Wir wollen jetzt den an den Interrupt-Handler übergebenen Wert näher untersuchen. Dazu schaffen wir eine zweite Interruptquelle mit GPIO26.

# int_test_006.py
from m5import import *
from machine import Pin
from time import sleep_ms
lcd.clear()
interrupt_data = 0
interrupt_data_text_box = M5TextBox(60, 30, str(interrupt_data),
lcd.FONT_DejaVu24,0xFFFFFF, rotate=0)
int_pin37 = Pin(37, Pin.IN, Pin.PULL_UP) # Pin von Taster A
int_pin26 = Pin(26, Pin.IN, Pin.PULL_UP) # Pin GPIO26

def int_handler(int_data): # muss einen Parameter haben
global interrupt_data
print(int_data)
print(type(int_data))
interrupt_data = int_data
interrupt_data_text_box.setText(str(interrupt_data))
interrupt_data_text_box.show()
if int_data == Pin(37):
print('Interrupt 37 wurde ausgelöst!')
elif int_data == Pin(26):
print('Interrupt 26 wurde ausgelöst!')
else:
print('Fehler!')
return

int_pin37.irq(trigger=Pin.IRQ_FALLING, handler=int_handler)
int_pin26.irq(trigger=Pin.IRQ_FALLING, handler=int_handler)
while True:
pass

Bei dem an den Interrupthandler übergebenen Wert int_info handelt es sich um das Objekt des Pins an dem der Interrupt eingegangen ist. Ich hatte aufgrund der Darstellung im Display angenommen es wäre ein String. Wenn dieser Wert ausgewertet werden soll dann so: if int_info == Pin(37): Also keine Anführungszeichen! Es ist der Name einer Instanz der Klasse Pin.
nterrupts können ein- und ausgeschaltet werden. int_state speichert den Interrupt Status. Das ist z.B. wichtig, wenn eine Programmsequenz nicht unter- brochen werden darf. Funktioniert nicht in der REPL.

import machine
int_state = machine.disable_irq()
machine.enable_irq(int_state)
count = 0
def cb(): # An interrupt callback
count +=1
def main():
# Code to set up the interrupt
# callback omitted
while True:
count += 1

Einschränkungen für Interrupt-Handler. Interrupt Handler können keinen Speicher benutzen. Deshalb ist ihre Anwendung eingeschränkt. Alles was zusätzlichen Speicher benötigt kann in einer ISR nicht ausgeführt werden. Z.B: ● Es können keine Fließkommazahlen benutzt werden. ● Listen und Dictionaries können nicht erweitert werden. ● Es können nicht mehrere Werte zurückgegeben werden. ● Texte können nicht bearbeitet werden. ● Es können keine Fehlermeldungen erzeugt werden.
Interrupt Handler schreiben. ISR’s sollten immer so kurz wie möglich gehalten werden. Nur Aktivitäten sie sofort ausgeführt werden müssen (z.B. Notstop) sollten in der ISR ausgeführt werden. Alles, was etwas warten kann sollte erst in der Hauptschleife bearbeitet werden. Dort gelten auch die eben dargestellten Einschränkungen nicht. Dazu ist in der ISR ein Flag zu setzen und in der Hauptschleife abzufragen.
Probleme bei Interrupts. Interrupts arbeiten auf Maschinencode Ebene. Deshalb kann es passieren, das ein Pythonbefehl mitten in seiner Ausführung unterbrochen wird und erst die ISR abgearbeitet wird bevor der Pythonbefehl zu Ende ausgeführt wird. Das kann zu Fehlern führen wenn die ISR etwas verändert, das vom Hauptprogramm bearbeitet wird. Dadurch können Fehler entstehen, die nur sporadisch auftreten und sehr schwer zu finden sind.



Hinweise zum Schreiben von Interrupt Handlern: http://docs.micropython.org/en/latest/reference/isr_rules.html

Navigation

Zurück zur "Micropython Kurs 2023 Teil 2" Startseite
Zurück zur "Micropython Kurs 2023" Startseite
Zurück zur Programmieren Startseite
Zurück zur Wiki Startseite