Prerušenia

Prerušenie (z angl. interrupt) umožňuje mikrokontroléru reagovať na udalosť, napr. stlačenie tlačidla, bez toho, aby program neustále kontroloval stav pinu. Keď udalosť nastane, mikrokontrolér preruší vykonávanie programu a zavolá funkciu na obsluhu prerušenia, tzv. ISR (z angl. Interrupt Service Routine). Princíp prerušení je vysvetlený v prednáške o spotrebe energie. Táto kapitola ukazuje, ako sa s prerušeniami pracuje v jazyku MicroPython.

Externé prerušenie na pine

Externé prerušenie sa nastavuje nad objektom triedy machine.Pin metódou .irq(). Tá má dva hlavné parametre:

  • trigger – udalosť, pri ktorej sa prerušenie vyvolá,
  • handler – funkcia, ktorá prerušenie obslúži; ako parameter dostane objekt pinu, na ktorom prerušenie vzniklo.

Nasledujúca ukážka vypíše správu pri každom stlačení tlačidla. Tlačidlo je pripojené k pinu 20 a k zemi, a preto pin používa pull-up rezistor. V kľude je na pine úroveň HIGH a stlačenie tlačidla vyvolá dobežnú hranu:

from machine import Pin


def handle_button(pin):
    print('>> Button was pressed.')


button = Pin(20, Pin.IN, Pin.PULL_UP)
button.irq(trigger=Pin.IRQ_FALLING, handler=handle_button)

Vypisovanie správy vo vnútri ISR slúži len na ukážku. V skutočnom programe sa výpisom vo vnútri ISR vyhnite (pozri pravidlá pre ISR).

Prerušenie na pine zrušíte tak, že metóde .irq() odovzdáte namiesto funkcie hodnotu None:

button.irq(handler=None)

Hodnoty parametra trigger

Hodnoty parametra trigger sú konštanty triedy Pin a dajú sa kombinovať operátorom |:

Hodnota Prerušenie sa vyvolá
Pin.IRQ_RISING pri nábežnej hrane (z LOW na HIGH)
Pin.IRQ_FALLING pri dobežnej hrane (z HIGH na LOW)
Pin.IRQ_RISING | Pin.IRQ_FALLING pri každej zmene úrovne

Niektoré porty jazyka MicroPython poznajú aj prerušenia na úrovni signálu (Pin.IRQ_LOW_LEVEL a Pin.IRQ_HIGH_LEVEL). Na doske Raspberry Pi Pico 2 W s mikrokontrolérom RP2350 však nie sú k dispozícii. Podporované hodnoty zistíte v dokumentácii alebo priamo na zariadení:

>>> from machine import Pin
>>> [name for name in dir(Pin) if name.startswith('IRQ')]
['IRQ_FALLING', 'IRQ_RISING']

Pravidlá pre ISR

Funkcia na obsluhu prerušenia preruší hlavný program v ľubovoľnom okamihu, preto pre ňu platia prísnejšie pravidlá ako pre bežné funkcie. Dokumentácia jazyka MicroPython odporúča [1]:

  • kód ISR má byť čo najkratší a najjednoduchší,
  • vo vnútri ISR nealokovať pamäť, teda nepridávať prvky do zoznamov ani slovníkov a nepoužívať desatinné čísla,
  • na prenos viacerých hodnôt medzi ISR a hlavným programom používať vopred vytvorené objekty typu bytearray alebo array.array,
  • pri práci so zdieľanými údajmi v hlavnom programe dočasne zakázať prerušenia,
  • vyhradiť pamäť pre výpis výnimiek, ktoré vzniknú vo vnútri ISR.

Ak je potrebné pri prerušení vykonať zložitejšiu činnosť, ISR ju môže pomocou funkcie micropython.schedule() naplánovať. Naplánovaná funkcia sa vykoná až po skončení prerušenia, keď už pre ňu tieto obmedzenia neplatia:

import micropython
from machine import Pin

micropython.alloc_emergency_exception_buf(100)

count = 0


def report(pin):
    print('Button pressed', count, 'times.')


def handle_button(pin):
    global count
    count += 1
    micropython.schedule(report, pin)


button = Pin(20, Pin.IN, Pin.PULL_UP)
button.irq(trigger=Pin.IRQ_FALLING, handler=handle_button)

Funkcia micropython.alloc_emergency_exception_buf() vyhradí pamäť, do ktorej sa zapíše výnimka vzniknutá vo vnútri ISR. Bez nej by ju nebolo možné vypísať, pretože vo vnútri ISR nie je možné alokovať pamäť.

Ďalšie zdroje

  1. MicroPython: Writing interrupt handlers – pravidlá a odporúčania pre obsluhu prerušení
  2. MicroPython: machine.Pin.irq() – dokumentácia metódy .irq()

Literatúra

[1] MicroPython. In [online]. Dostupné na internete: <http://micropython.org>.