Unterrichts- und Lernmaterial für Mikrocontroller
Unterrichts- und Lernmaterial fürMikrocontroller

SPIN2 und Propeller P2

I/O Pin - Teil 4

SPIN2 kennt insgesamt drei Variablen-Typen:

  • BYTE (8 Bit),
  • WORD (16 Bit) ,
  • LONG (32 Bit),

die als singles oder als Arrays deklariert werden können und

 

  • Variablen werden zur Laufzeit auf Null initialisiert.
  • Die Taktfrequenz des Controllers P2 wird im CON-Block über die Konstante _clkfreq gesetzt.

Übung 1 - Variable und ihre Typen, Minimum/Maximum Operatoren

Übung 1 - Variable, Typen, Min/Max Operatoren
Material
  • 1x  P2-Edge-Breadboard und Zubehör
  • 1x  P2-Edge Modul
  • 2x  Taster
  • 8x  LED, rot
  • div. Steckdrähte
Aufgaben
  • Baue die Schaltung nach Schaltskizze auf.
  • Übertrage das Programm Taster_LED_Schieber.spin2 in den Editor und speichere das Programm ab.
  • Überlege an Hand des Programmcodes, wie die Schaltung arbeitet.
  • Überprüfe deine Vermutung mit dem realen Experiment; starte das Programm und vergleiche deine Vorhersage mit dem tatsächlichen Vorgang.

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

 

 

 

 

Abb. 2

Schaltungsaufbau mit acht LEDs und zwei Tastern auf dem P2-Edge-Breadboard.

Den LEDs werden Pullup-Widerstände (1,5 k), den beiden Tastern Pulldown-Widerstände.(15 k) zugeschaltet.

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

  • if pinread(T1) == 1  ist der
  • Rückgabewert -1,

da pinread(T1) eine 1 gespeichert hat, und der Vergleich dadurch wahr wird.

Wird nur

  • if pinread(T1)

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:

  • pinread(T1) speichert eine 0.

Für die Bedingung in 

  • if pinread(T1) == 1 ist der
  • Rückgabewert 0.

Wird nur

  • if pinread(T1)

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

  • faktor <#= 254

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

  • faktor #>= 1

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:

  • Lösche den VAR-Block (s. Abb. 1: Programmzeile 16).
  • Abb. 1: Programmzeile 18: Füge im Anschluss an die Deklaration im Methodenblock eine Pipe (Symbol:  | ) ein, gefolgt von den drei durch Komma getrennten Variablennamen.

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
  • 1x  P2-Edge-Breadboard und Zubehör
  • 1x  P2-Edge Modul
  • 1x  LED, rot
  • div. Steckdrähte

Das erste (schlechte) Programmbeispiel zur Zeiterfassung

 

 

 

 

 

 

 

 

 

 

 

 

Abb. 3

Versuche Schritt-für-Schritt jede Programmzeile des Programms zu verstehen. Beschreibe mit eigenen Worten, was in jeder Zeile passiert.

Der Schaltungsaufbau zum Programm

Abb. 4

Für die Zeiterfassung wird nur die LED an P0 benötigt. Der Schaltungsaufbau aus Übung 1 kann direkt genutzt werden.

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

  • t := getct()

speichert in der Variablen t den aktuellen Zählerstand des Counters und übergibt diesen Wert

in Programmzeile 20 an

  • waitct(t = t + clkfreq) oder waitct(t += clkfreq).

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

  • sekunde := sekunde + 1 oder kürzer: sekunde ++

den Speicherinhalt von sekunde um 1 erhöht.

In Programmzeile 22 wird mit

  • pintoggle(LED) oder pint(LED)

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

  • waitms(10)

in das Programm ein und schauen uns anschließend die Blinkfrequenz mit einem Oszilloskop genauer an. Das Ergebnis sieht so aus:

Abb. 5

Impulsfolge an P0. Für zehn Schaltungen benötigt der Controller 10,1 s. Gemessen mit PicoScope 2000 Series.

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:

  • getct()
  • clkfreq

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.

 

 

Abb. 6

Hier wird nur der Teil des Programms aus Abb. 3 gezeigt, in dem Veränderungen vorgenommen wurden.

Versuche auch hier jede Programmzeile in der REPEAT-Schleife zu verstehen, indem du formulierst, was die Programmzeile jeweils bewirkt.

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

  • waitct(t)

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

  • waitms(10)

ein. Nimmt man die Blinkfrequenz mit einem Oszilloskop auf, ergibt sich:

Abb. 7

Impulsfolge an P0. Für zehn Schaltungen benötigt der Controller 10,0 s. Gemessen mit PicoScope 2000 Series.

 

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

 

 

 

 

 

 

 

 

 

 

 

Abb. 8 - Erfassung der Ticks im ersten Programm

Man erkennt deutlich, dass die Zahl der Ticks pro Durchlauf (pro Sekunde) um 152 Ticks über 20 Mio liegt.

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.

 

 

 

 

 

 

 

 

Abb. 9 - Erfassung der Ticks im zweiten Programm

Man erkennt deutlich, dass sich die Zahl der Ticks pro Durchlauf (pro Sekunde) konstant um 20 Mio erhöht.

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:

  • <var>  oder zahl // n

dabei bedeutet:

  • n        n aus der Menge der natürlichen Zahlen > 0
  • //        ist das Symbol für die Division modulo n; es wird nur der Rest bei Teilung durch n ausgegeben.

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
  • 1x  P2 Edge Breadboard mit Zubehör
  • 1x  P2 Edge
  • 2x  7-Segment-LED-Anzeige, z.B. TDSL 5160
  • duverse Steckdrähte
Aufgaben
  • Baue die Schaltung nach Schaltungsvorlage auf einem Steckbrett auf.
  • Übertrage das Programm modulo6.spin2 in den Editor und speichere es ab.
  • Starte das Programm und überprüfe, ob nur die Zahlen von 0 bis 5 aufsteigend auf der Anzeige erscheinen.

Schaltungsaufbau

 

 

 

 

 

Abb. 10

Aufbau der Schaltung auf einem P2-Edge-Breadboard. Softwaremäßig werden die Pullup-Widerstände zugecshaltet, so dass keine weitere Beschaltung notwendig ist.

Die Steckbuchsenbezeichner sind mit den Pineingängen des Propeller P2 identisch.

Das Programm modulo6.spin2

Abb. 10 - Modulo6.spin2 Programm; die im DAT Block codifizierten Ziffern 6 bis 9 werden in dieser Übung nicht benötigt.

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.

Abb. 11

Segmentzuweisung der Pinanschlüsse der 7-Segment Anzeige (rechts). Links sind den Zahlen Z0 bis Z9 die Pinpegel am Controllerausgang zugeordnet.

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

  • %0110_0111

oder in hexadezimaler Schreibweise

  • $67

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.

Abb. 13

Zeitgenaue Verzögerungs-einstellung von 0,1 s.

 

 

 

 

Abb. 14

Die Zähltaktung liegt bei ca. 0,1 s.

Der Zehntelsekunden-Zähler in Betrieb -> Kurzvideo (17 s).

Druckversion | Sitemap
© Reinhard Rahner - Gettorf