3.1. Mikrovezérlők¶
Az OpenMV Cam egy mikrovezérlőn (MCU) fut: ez egyetlen chip, amely egyesíti a CPU-t, a munkamemóriát (RAM), a programtárolót (flash memória) és egy sor perifériát – a külvilággal való kommunikációért felelős hardveres blokkokat.
A perifériák jelentik az érdekes részt. Mindegyik egy-egy szilíciumdarab, amelyet egyetlen feladatra szántak: egy láb magasra vagy alacsonyra hajtása, egy analóg feszültség mérése, bájtok kiléptetése egy soros buszon. A CPU minden perifériát regisztereken keresztül konfigurál és olvas – ezek rögzített memóriacímek, amelyeket a hardver figyel és frissít.
A MicroPython ezeket a regisztereket osztályokba csomagolja a machine modulon belül. A machine.Pin(...) egy objektumot ad vissza, amely egy általános célú be-/kimeneti (GPIO) lábat vezérel – egy vezetéket, amelyet a chip magasra (körülbelül 3,3 V) vagy alacsonyra (körülbelül 0 V) tarthat, illetve beolvashat e két állapot egyikeként, amikor valami külső eszköz hajtja. A machine.ADC(...) az analóg-digitális átalakítót teszi elérhetővé, amely megméri egy láb feszültségét, és számként jelenti azt. A machine.UART(...) egy univerzális aszinkron adó-vevőt (UART) működtet – ez egy periféria, amely bájtokat küld és fogad bitenként egy vezetékpáron, a TX (adás) és RX (vétel) vonalon keresztül. A többi osztály a többi perifériát fedi le. A szkript Python objektumokat olvas és ír; a MicroPython minden hozzáférést a megfelelő regiszterolvasásokká és -írásokká fordít, ezek pedig biteket mozgatnak a fizikai vezetékeken.
Egy MCU egyetlen chipbe csomagolja a CPU-t, a memóriát és a perifériákat. Minden perifériát a machine modul egy-egy osztálya tesz elérhetővé a Python számára.¶
3.1.1. A fő ciklus¶
Szinte minden mikrovezérlő-program ugyanazt a felépítést követi: egyszeri beállítás a szkript elején (modulok importálása, lábak konfigurálása, buszok megnyitása), majd egy végtelen while True: ciklus a végén. A cikluson belül a program újra és újra beolvassa a bemeneteket, döntéseket hoz és frissíti a kimeneteket. A ciklus maga a program; amikor a szkript kilép, az eszköz beszünteti minden tevékenységét.
# setup, runs once
from machine import Pin
led = Pin("P0", Pin.OUT)
# main loop, runs forever
while True:
led.value(1)
# ... do work ...
led.value(0)
# ... do other work ...
Ez a felépítés – egyszeri beállítás, majd örökös ciklus – a fő ciklus minta. Minden további arról szól, hogy mi kerül a belsejébe.
3.1.2. Valós idejű vezérlés¶
Egy asztali program sok másikkal együtt fut. Az operációs rendszer egy vagy több szál között ütemezi a munkáját – ezek független végrehajtási folyamok, amelyek között ezredmásodpercről ezredmásodpercre vált. Amikor az egyik szál I/O-ra vár (lemez, hálózat, az egér mozgatása a felhasználó által), az operációs rendszer átadja a CPU-t egy másiknak. A program többnyire eseményvezérelt: az ablakkezelő hívja meg a kódodat, amikor bemenet érkezik, a HTTP-könyvtár folytatja a kódodat, amikor bájtok érkeznek a socketen. Valami nagyobb dolog hív téged.
Egy mikrovezérlő-program ennek az ellenkezője. Alapértelmezés szerint nincs operációs rendszer, nincs ütemező, és nincs másik szál. Az imént bemutatott fő ciklus az egyetlen ciklus. A perifériák megszakításokat váltanak ki vagy állapotjelzőket tesznek elérhetővé; a ciklus lekérdezi ezeket, vagy közvetlenül kezeli a megszakításokat. Ha a ciklus megreked egy time.sleep_ms(1000) hívásban, az eszköz egy másodpercig semmit sem csinál; nincs másik szál, amely betöltené a rést.
Két következmény adódik ebből, és ezek mindenütt érvényesek:
Az idő valós. Egy láb kétszeri beolvasása egy szoros ciklusban mikromásodperceket vesz igénybe; tíz ezredmásodperc alvás tíz olyan ezredmásodpercet jelent, amely alatt semmi más nem történik. A nem blokkoló időzítés minta erre a válasz.
A hardver valós. A
machine.Pin.value1értékre állítása nagyjából 3,3 V-ot helyez egy fizikai vezetékre;0értékre állítása nagyjából 0 V-ot helyez oda. Az áramkör többi része azonnal látja ezt a feszültséget – beleértve minden olyan alkatrészt is, amelyet a láb tönkretehet, ha helytelenül hajtják meg.