- die Proximity Engine
- die Gesture Engine
- die Color Engine
Auch die Proximity-Messwerte werden einem Register entnommen: Der aktuelle ProximityLevel (vgl. Abstandsmessung mit dem APDS9960-Sensor) befindet sich im PDATA-Register (Adresse 0x9C). Ob überhaupt gerade ein Messwert vorliegt, auch das kann mit Hilfe eines Registers in Erfahrung gebracht werden. In diesem Fall ist es das Bit 1 (PVALID) des Registers STATUS (0x93), kurz: STATUS<PVALID>. Den Wert dieses Registers können wir mit dem Property statusRegister ermitteln. Mit der Schleife
Code: Alles auswählen
while (apds9960.statusRegister & 0b00000010) == 0:
pass
Die Proximity Engine
In Abb. 1 sehen wir ein vereinfachtes Flussdiagramm für die Proximity Engine. Mit der enableSensor()-Methode von apds9960.prox wird ENABLE<PEN> (Proximity Enable) auf 1 gesetzt. Damit kann die Proximity Engine ihre Arbeit beginnen. Daten werden gesammelt und im Register PDATA abgelegt. Nun wird PVALID auf 1 gesetzt - ein Zeichen dafür, dass ein Messwert vorliegt. Danach wird kontrolliert, ob sich der Messwert innerhalb des Proximity-Thresholds (vgl. Abstandsmessung mit dem APDS9960-Sensor) befindet. Liegt er innerhalb, also zwischen den Werten in den Registern PILT und PIHT, dann wird zum Ausgang (EXIT) gesprungen. Andernfalls wird das STATUS<PINT> (Proximity Interrupt) auf 1 gesetzt. Wenn zuvor STATUS<PIEN> (s. o.) auf 1 gesetzt worden ist, dann wird der INT-Ausgang auf Low gelegt; damit kann dann ein Interrupt beim TTGO ausgelöst werden. Ansonsten wird wieder zum Ausgang gesprungen (und der INT-Ausgang bleibt auf High). Man beachte: Der INT-Ausgang bleibt auf Low, solange PINT = 1 und PIEN = 1 sind. Deswegen muss innerhalb des Interrupt-Handlers PINT wieder auf 0 gesetzt werden, z. B. mit Hilfe der Methode clearInterrupt(). Auch durch einen Neustart des Programms ändert sich nichts am Zustand von PINT. |
Das Zustandsdiagramm des APDS9960
Im Beitrag Abstandsmessung mit dem APDS9960-Sensor hatten wir schon gesehen, dass mit wenigen Programmzeilen permanent Abstandswerte geliefert werden:
Code: Alles auswählen
s = apds9960.prox # mit apds9960 werden auch apds9960.prox (und apds9960.als) erzeugt
s.enableSensor() # Proximity Sensor einschalten
sleep_ms(7) # EXIT
while True:
sleep_ms(200) # auf nächsten Messwert warten
print(s.proximityLevel)
Folgende Fragen müssen wir nun noch klären:
- Welche Bedeutung hat die Zeile sleep_ms(7) # EXIT SLEEP?
- Wie haben wir eigentlich dafür gesorgt, dass die Proximity Engine und nicht eine andere Engine zur Ausführung kommt?
- Offensichtlich wird die Proximity Engine (ohne weitere Aufforderung durch unser Programm) immer wieder gestartet; ansonsten könnten wir mit s.proximityLevel nicht immer wieder neue Abstandswerte erhalten. Wie ist das zu erklären?
Alle drei Fragen können mit Hilfe des Zustandsdiagramm für den APDS9960 erklärt werden (Abb. 2). In diesem Bild sehen wir unsere drei Engines Proximity, Gesture und Color. Welche dieser Engines zur Ausführung kommt, wird wieder durch entsprechende Bits gesteuert. Im Wesentlichen entscheiden die Bits ENABLE<PEN> (Proximity ENable), ENABLE<GEN> (Gesture ENable) und ENABLE<AEN> (ALS ENable) darüber.
Wir klären jetzt die obigen Fragen, indem wir das Zustand-Diagramm aus Abb. 2 beginnend bei POR (Power Up) Schritt für Schritt durchlaufen. Nach einer internen Initialisierung (welche ca. 5,7 ms) dauert, geht der APDS9960 zunächst in einen (stromsparenden) Schlafzustand (SLEEP) über. Die Zeitspanne von 5,7 ms wird man außer Acht lassen können, solange zwischen dem Einschalten der Stromversorgung und dem Starten des Programms mehr als 5,7 ms vergehen.
Erst wenn ENABLE<PON> auf 1 gesetzt wird (Nebenbei: Dies wird bei der Instanziierung von apds9960 erledigt!), erwacht das Modul und kontrolliert, ob eine der Engines aktiviert worden ist. In unserem Fall ist es die Proximity Engine. Jetzt legt das Modul eine Pause von 7 ms ein; in dieser Zeit steht es uns nicht zur Verfügung. Das beantwortet die erste Frage.
Nun geht der Baustein in den IDLE-Zustand (Leerlauf) über. In unserem Fall verbleibt er aber nicht lange in diesem Zustand, sondern wechselt zur Proximity Engine, denn es sind PEN = 1 und GMODE = 0. Damit ist die 2. Frage beantwortet.
Wir folgen weiter den roten Pfeilen: Weil GMODE = 0, AEN = 0 und SAI = 0 sind (Sleep After Interrupt ist nicht aktiviert!), geht der Baustein wieder in den IDLE-Zustand über, um von dort erneut in die Proximity Engine einzusteigen... Die Proximity Engine wird jetzt also endlos durchlaufen, es sei denn, PEN wird zwischendurch auf 0 gesetzt (z. B. durch s.enableSensor(False)). Damit ist auch die dritte Frage beantwortet.
Die Color Engine und die Gesture Engine funktionieren übrigens nach dem gleichen Prinzip wie die Proximity Engine; allerdings sind sie deutlich komplexer. Für manche Zwecke müssen die Engines auch “vereint” tätig werden; deswegen sind die drei Engines auch nicht einfach “parallel geschaltet”.
.