Basiskurs 1 – Abschnitt 2 - Verzögerungszeiten mit System
Bestimmte I/O Operationen lassen sich besser verstehen, wenn man das Zeitverhalten von Ereignisse anders steuern kann. Das kann sich zum Beispiel darauf beziehen, wann eine LED ein- oder ausgeschaltet oder wie lange ein Taster gedrückt wird. Die drei grundlegenden Bausteine zur Zeiterfassung mit der Sprache SPIN sind:
Ein Register im Propeller Chip, der Zählimpulse des Systemtakts zählt.
Ein Befehl, der den Systemtakt des Propeller Chips in Hz angibt oder die Anzahl Zählimpulse pro Sekunde.
Ein Befehl, der darauf wartet, bis das CNT-Register einen bestimmten Wert x erreicht hat.
Soll eine Pause von 1 Sekunde eingelegt werden, dann schaut man sich an, welchen Wert das Register CNT gerade enthält und addiert den Wert von CLKFREQ (Anzahl Zählimpulse pro Sekunde) hinzu.
legt eine Pause von 1 Sekunde ein. Bruchteile einer Sekunde lassen sich über Bruchdarstellungen von clkfreq einstellen. Es bedeuten:
Schaltskizze für alle Versuche dieses Abschnittes
Übung 4 - LED 1s an 0,25s aus
In dieser Übung wird eine Blinkschaltung mit einer LED entworfen, die 1s leuchtet und 0,25s nicht leuchtet.
Das Programm
Hinweis
Alle Befehle, die zu einem Befehlsblock gehören, müssen mindestens um zwei Zeichen eingerückt werden. Der repeat-Block zeigt, wie es geht.
Wie arbeitet der waitcnt(clkfreq + cnt) Befehl ?
Sobald ein Programm gestartet wird, überprüft die Propeller Tool Software, ob vom Programmierer irgendwelche Deklarationen für den Systemtakt des Propeller Chips vorgenommen wurden. Geschah dies nicht, wird der Standardwert im CLK Register des Propeller Chips abgelegt und der interne RC Oszillator mit ca. 12 MHz Taktfrequenz eingeschaltet.
Die Anweisung
ist dann gleichbedeutend mit
Sobald der Propeller Chip gestartet wird, steht im CNT-Register ein aktueller Taktimpuls. Nehmen wir an, dass zum Zeitpunkt des Befehlsaufrufes von waitcnt(clkfreq + cnt) im CNT-Register die Zahl 50.000.008 steht. Dann wartet waitcnt mit der weiteren Programmausführung, bis dort die Zahl
steht.
2 - Systemtakt einstellen, Ereignissteuerung
In den Voreinstellungen ist ein Propeller Chip über den internen RC-Oszillator auf ca. 12 MHz Taktfrequenz eingestellt, mit einer Fehlergenauigkeit von > 40 Prozent.
Für zeitkritische Prozesse verfügen alle Propeller Boards über einen externen sehr genauen 5 MHz Oszillator. Sowohl in der Sprache SPIN als auch in Assembler lässt sich über eine Konstantendeklaration der Systemtakt verändern.
In SPIN geschieht das im sogenannten CON-Block, in dem auch globale Variable definiert werden müssen. Ein CON-Block gehört an den Anfang eines SPIN-Programmes.
Mit zwei Programmzeilen im CON-Block kann die Taktfrequenz eines Propeller-Controllers auf bis zu 80 MHz eingestellt werden.
_xinfreq bestimmt die Frequenz des externen Oszillators. Bei den Propeller-Boards AE, BoE und Flip sind das jeweils 5 MHz. Über die Anweisung
setzt der SPIN-Compiler bestimmte Bit im CLK-Register des Chip, sobald das Programm gestartet wird. Mit xtal1 werden schaltungstechnische Schaltkreischarakteristiken so eingestellt, dass externe Kristalle von 4 MHz bis 16 MHz angesprochen werden können.
Über eine PLL-Schaltung auf dem Prop-Chip wird die externe Frequenz multipliziert und dann als Systemtakt zur Verfügung gestellt.
Mit der Konstanten pll16x wird die extern anliegende Frequenz von 5 MHz über die PLL-Schaltung mit dem Faktor 16 multipliziert und als 80 MHz Systemtakt dem Controller zur Verfügung gestellt.
Weitere Einstellungskonstanten zur Systemtakt-Veränderung sind:
Für zeitkritische Prozesse ist die Nutzung des externen Oszillators notwendig. In der Variablen
ist die Frequenz des Systemtaktes hinterlegt; sie gibt die Impulszahl pro Sekunde auf Basis der Systemtakteinstellungen an.
Übung 5 - Konstante Blinkrate
Übung 5 - Sekundenblinker | |
Aufgaben |
|
Das Programm konstBlink.spin
Weitere Aufgaben
Die Blinkfrequenz sollte sich bei Systemtakt-Änderung nicht verändert haben.
Übung 6 - Der bitweise NOT-Operator „!“
Der NOT-Operator „!“ tauscht in einem vorgegebenen Bitmuster eine 1 gegen eine 0 und eine 0 gegen eine 1. Das Bitmuster 1000001 für sechs LEDs wird mit dem NOT-Operator zu 011110.
Aufgaben
Hinweis
Mit den beiden Kürzeln „~“ und „~~“ lassen sich einige Programmzeilen weiter verkürzen. Der
Das Programm aus Abb. 4 hat dann folgendes Aussehen:
Aber Achtung: die Doppeltilde steht unmittelbar nach dem Befehlsnamen, ohne Zuweisungsoperator.
Ein weiteres Kürzel, dass in der folgenden Übung angewendet wird, ist der sogenannte Inkrement-Operator "++" oder die Erhöhung um 1.
Übung 7 - Bitmuster im Register als Binärwert ansprechen
Das Bitmuster eines Registers kann auch als Binärwert interpretiert werden. So lässt sich die Anweisung
angeben, wobei die 0 einer Zahl des Zehnersystems und %000000 einer Zahl aus dem Binärsystem entspricht.
Das nachfolgende IncOut-Objekt addiert bei jedem Schleifendurchlauf von REPEAT eine 1 zum Inhaltswert des Registers OUTA[17..22]. Das Ergebnis wird über die LEDs optisch dargestellt.
Das Programm IncOut.spin
Übung 8 - Die Bedingungsschleife REPEAT ... UNTIL ... / WHILE ...
Gib alle Schleifenaufrufe in den Editor ein und schaue dir die Wirkung an. Bleibt abschließend nur zu klären, was zeigen die LEDs an, wenn Beispiel 3 mit der logischen Verknüpfung and aufgerufen wird?
Gib alle Schleifenaufrufe in den Editor ein und schaue dir die Wirkung an. Bleibt abschließend nur zu klären, was zeigen die LEDs an, wenn Beispiel 3 mit der logischen Verknüpfung and aufgerufen wird?
Die Wiederholungsanweisung REPEAT ist uns bereits bekannt. Wie geht man vor, wenn eine Wiederholung genau 10-mal durchgeführt werden soll? Das wird in dieser Übung geklärt.
Es gibt sehr viele verschiedene Möglichkeiten mit jeweils der gleichen Wirkung:
Eine weitere Möglichkeit ist :
Probiere alle fünf Möglichkeiten mit dem Programm aus Abb. 6 aus und überzeuge dich von der identischen Wirkung.
Wird ++ vor OUTA[22..17] gesetzt, handelt es sich um ein PRE-Increment und es wird ausgeführt, bevor die Bedingung … == 11 überprüft wird. Wird ++ hinter OUTA[22..17] gesetzt, sprechen wir von einem POST-Increment; es wird ausgeführt, nachdem die Bedingung überprüft wurde.
Das hier Gesagte gilt auch für den Dekrement-Operator „—".
Neben einer Wiederholungsschleife, die durchlaufen wird, bis eine Abbruchbedingung eintritt (… UNTIL …) , gibt es auch die Möglichkeit, eine Schleife zu durchlaufen, solange eine Bedingung erfüllt ist (… WHILE …).
Drei weitere Möglichkeiten der Anwendung einer Wiederholungsschleife zeigen die folgenden Beispiele:
Gib alle Schleifenaufrufe in den Editor ein und schaue dir die Wirkung an. Bleibt abschließend nur zu klären, was zeigen die LEDs an, wenn Beispiel 3 mit der logischen Verknüpfung and aufgerufen wird?
Lösung: Es wird bis zur Zahl 8 (binär 001000) hochgezählt.
Bedingungsblöcke mit IF …
Die IF – Anweisung kann …
… nur alleine verwendet werden; alle Befehle, die zu dem Bedingungsblock gehören, müssen um zwei Stellen eingerückt sein. Ist die Bedingung nicht erfüllt, wird der Block übersprungen.
… in Verbindung mit ELSEIF, ELSEIFNOT und ELSE, um komplexere Entscheidungsvorgänge aufzurufen.
Übung 9 – Ein bewegtes Lichtmuster
Wie arbeitet das Programm Lichtmuster.spin?
Die Zeitvariablen für den Systemtakt werden festgelegt.
Die I/O P22 bis P17 werden als Ausgänge deklariert. Standardmäßig werden sie beim Programmstart auf 0 gesetzt, deshalb fehlt der Befehl outa[22..17]~.
Das Ausgangsregister OUTA[22..17] ist 0, deshalb wird der nachfolgende Befehl ausgeführt und 100000 in das Register geschrieben (Zeile 18) und über die LEDs angezeigt.
Nach einer Verzögerungszeit von 0,1 s wird der Inhalt des OUTA-Registers um eine Stelle nach rechts verschoben. Der Registerinhalt lautet jetzt: 010000 und wird über die LEDs angezeigt (Zeile 21).
Die REPEAT-Schleife wird erneut durchlaufen; der Bedingungsblock ist nicht erfüllt (Zeilen 17 + 18) und es geht weiter mit Zeile 20. Nach 0,1 s Verzögerungszeit wird das Lichtmuster um eine Stelle nach rechts verschoben.
Dieser Ablauf wiederholt sich ständig, da keine Abbruchbedingung erfüllt ist.
Übung 10 –Geschwindigkeit eines Lichtmusters mit Tastern steuern
Aufgaben
Das Programm TasterBildmuster.spin
Wie arbeitet das Programm TasterBildmuster.spin ?
Neu ist in diesem Programm der VAR-Block. Die beiden Variablen muster und teilen sind vom Typ Byte. Damit lassen sich Zahlenwerte zwischen 0 und 255 speichern.
Im Repeat-Wiederholungsblock sind zwei Entscheidungsblöcke. Die Wirkung des ersten Blocks kennen wir aus Übung 8 mit dem Unterschied, dass hier der Inhalt des Speichers muster betrachtet wird.
Die Operatoren Limit Minimum „#>“ und Limit Maximum „<#“
Diese beiden Operatoren überprüfen, ob sich der Wert einer Variablen in einem festgelegten Bereich bewegt. Wird einer der beiden Taster gedrückt, zum Beispiel T1 an P24, dann wird die Variable teilen inkrementiert und mit Programmzeile 29 auf 254 begrenzt. Wird T2 an P26 gedrückt, dann wird die Variable teilen dekrementiert und nach unten auf 1 begrenzt.
Die Wartezeit wird über Zeile 34 – je nach Wert von teilen – erhöht oder erniedrigt und führt zu einer schnelleren oder langsameren Verschiebung des Bitmusters.
Lokale Variable
Bisher haben wir in allen Beispielobjekten globale Variable benutzt, die im VAR-Block deklariert wurden. Alle Methoden in einem gegebenen Objekt können damit auf diese Variablen zugreifen.
Für jede Methode eines Objektes lassen sich aber auch lokale Variable definieren, die nur in der Methode selbst sichtbar sind.
Aus der globalen Variablen,
wird mit dem pipe-Symbol „|“ eine lokale Variable:
Lokale Variable werden ausschließlich vom Typ long angelegt. Aus diesem Grund ist keine Typangabe wie bei globalen Variablen möglich.
Zeitmessungen
Bei Zeitmessungen schleichen sich sehr schnell Fehler ein. Betrachte dazu das folgende Beispielprogramm.
Die Warteschleife in Programmzeile 18 dauert genau 1 Sekunde. Dann folgt eine Inkrement-Anweisung (Zeile 19), für die der Controller einige Taktimpulse benötigt. Weitere Taktimpulse werden für die OUTA[19]-Anweisung und den Schleifenbefehl repeat benötigt.
Die Repeat-Schleife wird immer wieder durchlaufen, pro Tag 86.400 mal. Jeder Durchlauf benötigt aber nicht exakt 1s, sondern dauert etwas länger wegen der einzelnen Befehlsausführungen, für die der Prozessor Zeit oder Taktimpulse braucht.
Nehmen wir an, es werden bei jedem Durchlauf 20 Taktimpulse pro Sekunde mehr benötigt. Das macht nach 24 Stunden 1.728.000 Taktimpulse und an drei Tagen gut 5 Mio. Taktimpulse. Das entspricht dann etwa einer Sekunde, die die Uhr oder der Zeitgeber „aus dem Takt“ geraten ist.
Wie lässt sich diese Abweichung auffangen? Schau dir dazu das nachfolgende Programm an.
In diesem Programm tauchen zwei neue Variable dt und T auf. In dt ist der Wert von clkfreq, in T der von cnt abgelegt. Waitcnt(T) ist auf 1s eingestellt. Zusätzlich ist eine Wartezeit von 0,8s in Zeile 25 hinzugekommen. Nehmen wir an, in T steht mit dem Start des Programms die Zahl 1000 und in dt 5.000.000.
Für die Ausführung der Programmzeilen 21 – 25 und der Repeat-Schleife benötigt der Prozessor angenommene 4.000.020 Taktimpulse (4.000.000 für die Warteschleife, 20 für die Ausführung aller Befehle im repeat-Block); in T steht dann 4.001.020 und wenn das Programm wieder in Zeile 21 angekommen ist, der Wert 4.001.020 + 5.000.000 = 9.001.020. Die Verzögerungszeit beträgt wieder 1s.
Die Programmausführung ist unabhängig von der Anzahl der Anweisungen im repeat-Block.
Hier geht es weiter mit dem Basiskurs 2 Abschnitt 1 - Methoden und Kerne