I/O Pin - Teil 4
SPIN2 kennt insgesamt drei Variablen-Typen:
die als singles oder als Arrays deklariert werden können und
Übung 1 - Variable und ihre Typen, Minimum/Maximum Operatoren
Übung 1 - Variable, Typen, Min/Max Operatoren | |
Material |
|
Aufgaben |
|
Das Programm Taster_LED_Schieber.spin2
Abb. 1
Acht LEDs mit Pullups und zwei Taster mit Pulldown-Widerständen.
Im CON-Block werden vier Größen festgelegt.
Es gibt einen VAR-Block mit drei Variablen vom Typ BYTE (8 Bit), gefolgt von einem PUB-Block.
In der REPEAT-Schleife befinden sich zwei Bedingungsblöcke mit IF. Erst wenn sie durchlaufen sind, wird nach einer Verzögerungszeit ein LED-Muster ausgegeben.
Der Schaltungsaufbau
Das Kurzvideo zum Programm zeigt, wie die Schaltung arbeitet. Je länger der Finger auf einem der beiden Taster bleibt, umso stärker erhöht/erniedrigt sich faktor.
Wie arbeitet das Programm Taster_LED_Schieber.spin2
Vergleichsoperatoren geben wahr (-1) oder falsch (0) zurück. Bei Verwendung in IF- und REPEAT-Blöcken wird der nachfolgende Code ausgeführt, wenn die Bedingung ungleich Null (wahr) ist.
Wenn Taster T1 gedrückt wird, liegt er an 1 und es gilt: Für
da pinread(T1) eine 1 gespeichert hat, und der Vergleich dadurch wahr wird.
Wird nur
verwenden, wird der nachfolgende Codeblock immer noch ausgeführt, wenn T1 gedrückt wird, da pinread(T1) eine 1 speichert, was immer noch ungleich Null ist.
Wenn Taster T1 nicht gedrückt wird, liegt er mit Pulldown-Widerstand an 0 und es gilt:
Für die Bedingung in
Wird nur
verwendet, ist der Rückgabewert des Vergleichsoperators auch 0 und der nachfolgende Codeblock wird übersprungen.
Wir schauen uns nur die Programmzeilen 27 bis 41 an. Die im OBJ-Block aufgeführte Datei dient zur Ansteuerung des Parallax Serial Terminal Fensters und wird an dieser Stelle nicht benutzt.
In der Endlosschleife REPEAT gibt es zwei Entscheidungsblöcke vom Typ IF/ELSEIF. Im ersten Block wird das Bitmuster, wenn es bei %0000_0000 angelangt ist (keine LED leuchtet) auf %1000_0000 zurückgesetzt (die LED an P7 leuchtet).
Im nachfolgenden Entscheidungsblock wird der Eingang von P8 abgefragt. Wurde der Taster gedrückt, dann wird der Wert von der Variablen faktor um 1 erhöht und anschleßend darauf überprüft, ob er größer oder gleich 254 ist. Da faktor vom Typ Byte ist, kann er nur Werte kleiner 255 aufnehmen. Programmzeile 33 begrenzt mit
genau diese Situation.
Anschließend geht es mit Programmzeile 39 weiter; nach einer kurzen Verzögerungszeit wird das neue Bitmuster gesetzt, die entsprechende LED leuchtet.
Wurde der Taster an P8 nicht gedrückt, geht es mit der ELSEIF-Anweisung weiter. Wurde der Taster an P14 gedrückt, reduziert sich der Wert von faktor um 1. Der kleinste anzunehmende Wert von faktor ist 1, deshalb wird mit
genau dies überprüft.
Die nach der pinread-Anweisung eingebaute Verzögerungszeit von 100 ms dient dazu, Tastenprellen zu unterdrücken und eine 1-Schritt Erhöhung des faktor-Wertes zu erreichen.
Lokale und globale Variable
Während wir bisher in den meisten Beispielen nur eine Methode verwendet haben, besitzen Objekte häufig mehr als eine Methode und Anwendungen sind normalerweise eine Sammlung mehrerer Objekte. Die in den Methoden bzw. Objekten vorkommenden Variablen können nur auf eine Methode beschränkt sein (lokale Variable) oder für ein ganzes Objekt gültig sein (globale Variable). Wie man programmtechnisch lokale und globale Variable erstellt, wird hier angesprochen.
Variablen, die im VAR-Block eines Objektes deklariert sind, gelten global für das Objekt. Das heißt, alle Methoden innerhalb eines bestimmten Objekts können auf sie zugreifen.
Jede Methode in einem Objekt kann aber auch lokale Variablen für die eigene Verwendung deklarieren. Sie bestehen nur während der Ausführung der Methode.
Die beiden globalen Variablen im Taster_LED_Schieber-Objekt (s. Abb. 1) können wie folgt durch lokale Variablen ersetzt werden:
Abschließende Bemerkung:
Bei der VAR-Blocksyntax wurden die globalen Variablen vom Typ Byte, Word oder Long definiert. Lokale Variablen werden jedoch automatisch als Long definiert; es gibt keine Option für lokale Variablen mit Byte- oder Wortgröße.
Übung 2 - Betrachtungen zur Zeiterfassung
Für Uhren- und kritische Zeitmessungsanwendungen ist es wichtig, alle möglichen Fehler außer der Genauigkeit des Quarzoszillators aus einem Programm zu eliminieren. Schauen wir uns dazu zwei Programmbeispiele an.
Übung 2 - Betrachtungen zur Zeiterfassung | |
Material |
|
Das erste (schlechte) Programmbeispiel zur Zeiterfassung
Der Schaltungsaufbau zum Programm
Wie arbeitet das Programm?
CON Block
Hier wird die Taktfrequenz eingestellt und festgelegt, mit welchem Port die LED verbunden ist.
PUB Block mit den lokalen Variablen t und sekunde
Ein Pullup-Widerstand von 1,5 kOhm wird an P0 zugeschaltet; anschließend wird Ausgang P0 auf HIGH gezogen. Die LED leuchtet.
In der Wiederholungsschleife REPEAT gibt es vier Anweisungen, die nacheinander abgearbeitet werden. Die Methode in
Programmzeile 19
speichert in der Variablen t den aktuellen Zählerstand des Counters und übergibt diesen Wert
in Programmzeile 20 an
Der Controller wartet genau clkfreq Ticks (bei eingestellten 20 MHz also genau 20.000.000 Ticks oder eine Sekunde), bevor er
in Programmzeile 21 mit
den Speicherinhalt von sekunde um 1 erhöht.
In Programmzeile 22 wird mit
der Ausgangszustand von P0 invertiert: aus HIGH wird LOW, aus LOW wird HIGH. Anschließend geht es zurück zu Programmzeile 19.
Für den Zuschauer entsteht der Eindruck, dass die LED im Sekundentakt blinkt. Aber stimmt das wirklich? Wir wissen ja, dass der Controller für das Abarbeiten jedes Befehls auch Zeit benötigt.
Stellen wir uns vor, dass viele weitere Befehle in der REPEAT-Schleife vorhanden sind und für deren Abarbeitung insgesamt 10 ms vom Controller benötigt werden. Statt verschiedener Befehle fügen wir zur Veranschaulichung eine Verzögerungsschleife von 10 ms nach Programmzeile 21 in Abb. 3 mit
in das Programm ein und schauen uns anschließend die Blinkfrequenz mit einem Oszilloskop genauer an. Das Ergebnis sieht so aus:
Würde es sich hier um den Sekundenzeiger einer Uhr handeln, dann wäre die Zeitmessung sehr ungenau und nicht zu gebrauchen. Abhilfe schafft das folgende Programm, dass die Zeit für die Abarbeitung der einzelnen Befehle im Programm berücksichtigt.
Das zweite Programmbeispiel zur Zeiterfassung
In diesem Programm kommen eine neue Methode und eine Variable vor:
Die Methode getct() hat Zugriff auf den Counter des Prozessors. Sobald der Prozessor aktiviert wird, läuft der los und startet bei Null. Wie schnell gezählt wird, hängt von der eingestellten Taktfrequenz clkfreq ab. Bei 20 MHz schafft der Counter in 1 Sekunde 20.000.000 Ticks, dass ist die Bezeichnung für die Einheit des Counters.
Wie arbeitet das zweite Programm?
Programmzeilen 17 und 18
Der aktuelle Wert des Counters wird ausgelesen, der Variablen t vom Type LONG übergeben und in der Variablen dt (Typ: LONG) die eingestellte Taktfrequenz des Controllers abgelegt.
Programmzeile 21ff
t enthält den aktuellen Zählerstand des Counters plus 20.000.000. Die nachfolgende Anweisung
verzögert die Programmausführung um genau diese 20.000.000 Ticks oder eine Sekunde. Anschließend wird der Wert der Variablen sekunde um 1 erhöht und anschließend der Ausgangszustand von P0 invertiert.
Zwischenzeitlich läuft der Counter gnadenlos weiter. Jede Sekunde schafft er 20.000.000 Ticks plus die Ticks, die der Prozessort benötigt, um die Befehle auszuführen.
Anschließend kehrt er in Programmzeile 17 zurück und das Spiel beginnt von vorne.
Fügen wir zur Veranschaulichung auch hier wie im ersten Programm eine Verzögerungsschleife von 10 ms nach Programmzeile 23 in Abb. 6 mit
ein. Nimmt man die Blinkfrequenz mit einem Oszilloskop auf, ergibt sich:
Verglichen mit Abb. 5 ohne Zeitkorrektur ein sehr genaues Ergebnis, das wir aber noch etwas genauer anschauen wollen. Dazu lassen wir uns die Ticks im Terminalfenster pro Schleifendurchlauf ausgeben. Dieser Wert sollte im Idealfall konstant sein und im schlechtesten Fall sich ständig verändern (vergrößern oder verkleinern).
Auszählung der Ticks pro Schleifendurchlauf
Betrachtet man das erste Programm (s. Abb. 5), dann benötigen die Anweisungen in der Endlosschleife zusammen mit den Terminal-Ausgabebefehlen (sind nicht dargestellt) ca. 152 zusätzliche Ticks pro Schleifendurchlauf. Die Verzögerungszeit nimmt dann pro Durchlauf um ca. 7,6 * 10-7 s zu, ohne dabei die Ungenauigkeit des eingesetzten Quarzkristalls berücksichtigt zu haben. In 24 h wären das ca. 0,66 s.
Für die Darstellung in Abb. 9 wurde auch das zweite Programm, wie das erste, entsprechend mit Befehlen zur Terminalausgabe erweitert. Die gemessenen Ticks pro Schleifendurchlauf erhöhen sich konstant um 20 Mio (Prozessortaktung: 20 MHz), eine Zeitabweichung ist in dem betrachteten Abschnitt (noch) nicht zu erkennen.
Übung 3 - Zähler modulo 6 - Einstieg
In dieser Übung wird ein einfacher Zähler aufgebaut, der von 0 bis 5 (modulo 6) zählen kann. Jede Digitaluhr besitzt einen solchen modulo-Zähler, allerdings vom Typ modulo 60.
Werden zum Beispiel die Sekunden gezählt, dann wird im Sekundentakt von 0 bis 59 hochgezählt und anschließend beim Schritt von 59 auf 60 die nächsthöhere Stelle um 1 erhöht und die Zahl 59 auf 0 zurückgesetzt.
Unser Zähler zählt nur von 0 bis 5 und fängt dann wieder von vorne an zu zählen. Der dazu notwendige SPIN2-Befehl hat folgendes Format:
dabei bedeutet:
Beispiel:
8 mod 5 = 3, denn 8 geteilt durch 5 ist 1, Rest 3
22 mod 6 = 4, denn 22 geteilt durch 6 ist 3, Rest 4
28 mod 7 = 0, denn 28 geteilt durch 7 ist 4, Rest 0.
Übung 3 - Zähler modulo 6 | |
Material |
|
Aufgaben |
|
Schaltungsaufbau
Das Programm modulo6.spin2
Wie arbeitet das Programm modulo6.spin2 ?
Die Daten zum Aufruf der zehn Ziffern 0 ... 9 für die 7-Segment-Anzeige sind im DAT-Block hinterlegt. Wie die Daten codiert wurden zeigt die folgende Abbildung 11. Bei einer modulo 6 Anzeige werden nur die Ziffern Z0 bis Z5 benötigt. Deren binäre Darstellung entnimmt man der linken Tabelle in Abb. 11.
Ziffer 3 wird durch ein HIGH oder eine 1 der LED-Segmente a, b, c, d und g erreicht (s. Tabelle in Abb. 11). Binär entspricht das der Darstellung
oder in hexadezimaler Schreibweise
Dieser Wert findet sich im DAT-Block an vierter Stelle (beachte, in Arrays ist das erste Element das 0-te Element).
Das Programm enthält fünf Blöcke: CON, DAT, VAR, PUB, PRI.
Im Konstanten Block CON werden die Taktfrequenz des Prozessors und die anzusprechenden Pin des Controllers festgelegt. SEG1 spricht die acht Pin der einen 7-Segment-Anzeige, SEG2 die der zweiten an.
Im nachfolgenden DAT-Block sind die Bitbelegungen der Pins für die jeweiligen Zifferndarstellungen auf der Anzeige hexadezimal hinterlegt.
Im VAR-Block ist die globale Laufvariable n vom Typ BYTE für die Zählschleife definiert.
Der PRI-Block ist uns schon aus einem anderen Kapitel bekannt; hier werden die Pullup-Widerstände für die bezeichneten Pinausgänge aktiviert.
Bleibt nur noch das Hauptprogramm im PUB-Block. Zu den Pinausgängen P16 ... P31 werden in zwei Schritten 1k5 Pullup-Widerstände aktiviert und die Laufvariable n auf 0 gesetzt.
Die Wiederholungsschleife REPEAT wird anschließend 30-mal durchlaufen bevor das Programm beendet wird. Die Laufvariable n wird modulo 6 bei jedem Durchlauf erhöht und die entsprechende Bitfolge des DAT-Elements aus dem Array an die Pinausgänge SEG1 gelegt.
Ein Kurzvideo (12 s) zu diesem Programm gibt es hier.
Übung 4 - Dezimalzähler mit einer Vor- und Nachkommastelle
Im folgenden Kurzvideo wird ein Zähler mit einer Vor- und einer Nachkommastelle gezeigt. Versuche dafür ein Programm zu schreiben.
Wenn dir das gelungen ist, verbessere dein Programm so, dass der Zähler als Sekundenzähler mit Zehntelsekunden Angabe arbeitet.
Entwickle ein Programm, das den im Kurzvideo dargestellten Zähler (44 s) mit einer Dezmalen zeigt.
Möglicher Lösungsvorschlag
Abb. 12
Möglicher Lösungsvorschlag für Übung 4. Nicht gezeigt wird die Methode für das Einschalten der Pullup-Widerstände. Dies ist hier bereits an anderer Stelle erfolgt.
Hinweis: Als zeitgenaue Sekundenanzeige mit einer Dezimalen muss der Wert von m jede Sekunde um 1 oder der Wert von n bei jedem Durchlauf um 0,1 s erhöht werden.
Durch Einfügen der beiden unten gezeigten Programmzeilen (s. Abb. 13), ergibt sich eine sehr genaue Zählung im 0,1 s Takt. Eine Überprüfung mit einem Oszilloskop (s. Abb. 14) bestätigt dies.
Der Zehntelsekunden-Zähler in Betrieb -> Kurzvideo (17 s).