3.1. Mikrocontroller¶
Die OpenMV Cam läuft auf einem Mikrocontroller (MCU): einem einzigen Chip, der eine CPU, Arbeitsspeicher (RAM), Programmspeicher (Flash) und eine Reihe von Peripheriegeräten vereint – Hardwareblöcke für die Interaktion mit der Außenwelt.
Die Peripheriegeräte sind der interessante Teil. Jedes ist ein Stück Silizium, das einer einzigen Aufgabe gewidmet ist: einen Pin auf High oder Low zu treiben, eine analoge Spannung zu messen oder Bytes über einen seriellen Bus herauszutakten. Die CPU konfiguriert und liest jedes Peripheriegerät über Register – feste Speicheradressen, die die Hardware überwacht und aktualisiert.
MicroPython kapselt diese Register in Klassen innerhalb des machine-Moduls. machine.Pin(...) liefert ein Objekt zurück, das einen general-purpose input/output (GPIO) Pin steuert – eine Leitung, die der Chip auf High (etwa 3,3 V) oder Low (etwa 0 V) halten oder als einen dieser beiden Zustände auslesen kann, wenn etwas Externes sie treibt. machine.ADC(...) macht den Analog-Digital-Wandler zugänglich, der die Spannung an einem Pin misst und als Zahl meldet. machine.UART(...) betreibt einen universal asynchronous receiver/transmitter (UART) – ein Peripheriegerät, das Bytes Bit für Bit über ein Leitungspaar sendet und empfängt, TX (Senden) und RX (Empfangen). Andere Klassen decken die restlichen Peripheriegeräte ab. Das Skript liest und schreibt Python-Objekte; MicroPython übersetzt jeden Zugriff in die entsprechenden Registerlese- und -schreibvorgänge, und diese bewegen Bits auf physischen Leitungen.
Eine MCU verpackt CPU, Speicher und Peripheriegeräte in einem einzigen Chip. Jedes Peripheriegerät wird Python durch eine Klasse im machine-Modul zugänglich gemacht.¶
3.1.1. Die Hauptschleife¶
Fast jedes Mikrocontroller-Programm hat dieselbe Struktur: einmalige Einrichtung am Anfang des Skripts (Module importieren, Pins konfigurieren, Busse öffnen), dann eine unendliche while True:-Schleife am Ende. Innerhalb der Schleife liest das Programm Eingaben, trifft Entscheidungen und aktualisiert Ausgaben immer wieder. Die Schleife ist das Programm; wenn das Skript beendet wird, hört das Gerät auf, etwas zu tun.
# 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 ...
Diese Struktur – einmalige Einrichtung, dann endlose Schleife – ist das Hauptschleifen-Muster. Alles Folgende dreht sich darum, was darin passiert.
3.1.2. Echtzeitsteuerung¶
Ein Desktop-Programm läuft neben vielen anderen. Das Betriebssystem plant seine Arbeit über einen oder mehrere Threads – unabhängige Ausführungsströme, zwischen denen es Millisekunde für Millisekunde umschaltet. Wenn ein Thread auf E/A wartet (Festplatte, Netzwerk, Mausbewegung des Benutzers), gibt das BS die CPU an einen anderen ab. Das Programm ist größtenteils ereignisgesteuert: Der Fenstermanager ruft Ihren Code auf, wenn eine Eingabe eintrifft, die HTTP-Bibliothek setzt Ihren Code fort, wenn Bytes am Socket ankommen. Etwas Größeres ruft Sie auf.
Ein Mikrocontroller-Programm ist das Gegenteil. Standardmäßig gibt es kein Betriebssystem, keinen Scheduler und keinen anderen Thread. Die gerade gezeigte Hauptschleife ist die einzige Schleife. Peripheriegeräte lösen Interrupts aus oder stellen Statusflags bereit; die Schleife fragt sie ab (Polling) oder behandelt die Interrupts direkt. Wenn die Schleife in einem time.sleep_ms(1000) hängenbleibt, tut das Gerät während dieser Sekunde nichts; es gibt keinen anderen Thread, der die Lücke füllt.
Daraus ergeben sich zwei Konsequenzen, die überall gelten:
Zeit ist real. Das zweimalige Lesen eines Pins in einer engen Schleife dauert Mikrosekunden; zehn Millisekunden zu schlafen bedeutet zehn Millisekunden, in denen nichts anderes passiert. Das Muster der nicht-blockierenden Zeitmessung ist die Antwort darauf.
Hardware ist real. Das Setzen von
machine.Pin.valueauf1legt etwa 3,3 V an eine physische Leitung an; das Setzen auf0legt dort etwa 0 V an. Andere Teile der Schaltung sehen diese Spannung sofort – einschließlich aller Komponenten, die der Pin beschädigen kann, wenn er falsch angesteuert wird.