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

Fundamentum Propeller SPIN Programmierung

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:

 

  • CNT

Ein Register im Propeller Chip, der Zählimpulse des Systemtakts zählt.

  • CLKFREQ

Ein Befehl, der den Systemtakt des Propeller Chips in Hz angibt oder die Anzahl Zählimpulse pro Sekunde.

  • WAITCNT(x)

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.

 

  • waitcnt(clkfreq + cnt)

legt eine Pause von 1 Sekunde ein. Bruchteile einer Sekunde lassen sich über Bruchdarstellungen von clkfreq einstellen. Es bedeuten:

  • clkfreq/2 - Anzahl Zählimpulse in einer halben Sekunde; entspricht 0,5 s.
  • clkfreq/10 – Anzahl Zählimpulse in einer zehntel Sekunde; entspricht 0,1 s.
  • clkfreq/1000 – Anzahl Zählimpulse in einer tausendstel Sekunde; entspricht 1 ms.

Schaltskizze für alle Versuche dieses Abschnittes

 

 

 

 

 

 

 

 

 

 

 

Abb. 0

Schaltskizze für alle Versuche des Abschnitts 2.

Alternativ zum Parallax Flip Board lassen sich auch die Propeller Boards AE und BoE einsetzen.

Das BoE verfügt bereits über 10 fest verdrahtete LEDs, so dass nur noch die drei Taster auf dem Steckbrett eingerichtet werden müssen.

Ü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

 

 

 

 

 

 

 

Abb. 1

LED-Blinker, der 1s die LED einschaltet und 0,25s ausschaltet.

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

  • waitcnt(clkfreq + cnt)

ist dann gleichbedeutend mit

  • waitcnt(12.000.000 + cnt).

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

  • 12.000.000 + 50.000.008 = 62.000.008

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.

 

  • CON
  •   _xinfreq = 5_000_000
  •  _clkmode = xtal1 + pll16x

_xinfreq bestimmt die Frequenz des externen Oszillators. Bei den Propeller-Boards AE, BoE und Flip sind das jeweils 5 MHz. Über die Anweisung

  • _clkmode = xtal1 + pll16x

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:

  • pll16x       - Systemtakt: 80 MHz
  • pll8x         - Systemtakt: 40 MHz
  • pll4x         - Systemtakt: 20 MHz
  • pll2x         - Systemtakt: 10 MHz
  • pll1x        - Systemtakt: 5 MHz

Für zeitkritische Prozesse ist die Nutzung des externen Oszillators notwendig. In der Variablen

  • clkfreq

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
  • Übertrage das Programm konstBlink.spin in den SPIN Tool Editor und speichere das Programm ab.
  • Starte das Programm und überprüfe, ob die LED im Sekundentakt an- und ausgeht.

Das Programm konstBlink.spin

 

 

 

 

 

 

Abb. 2

Sekundenblinker. Die zeitkritischen Werte sind über den gelb eingefärbten CON-Block deklariert, der externe 5 MHz Kristall ist mit _xinfreq zugeschaltet worden. Der Vervielfachungsfaktor ist hier mit 1 angegeben. Der Systemtakt liegt bei 5 MHz.

Weitere Aufgaben

  • Tausche im CON-Block die Variable pll1x gegen pll2x aus und starte das Programm erneut. Hat sich jetzt die Blinkfrequenz verändert?
  • Wiederhole den Vorgang, indem du das Programm auch mit pll4x, pll8x und pll16x startest. Ändert sich die Blinkfrequenz?

Die Blinkfrequenz sollte sich bei Systemtakt-Änderung nicht verändert haben.

  • Verändere das Programm aus Übung 5 in den Zeilen 18 und 20. Ersetze clkfreq/2 durch den Zahlenwert 2_500_500 (siehe Abb. 3).
  • Starte das Programm und beobachte die Blinkfrequenz der LED. Die LED sollte im Sekundentakt an- und ausgehen.
  • Tausche im CON-Block die pll1x Variable durch pll2x aus und starte das Programm neu. Ändert sich die Blinkfrequenz? Wiederhole diesen Vorgang mit pll4x und pll8x.
  • Gib eine Erklärung für deine Beobachtungen.

 

 

 

 

 

 

 

 

Abb. 3

In diesem Programm wurden die Programmzeilen 18 und 20 geändert gegenüber dem Programm aus Abb. 2.

 

Ü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

  • Übertrage das Programm BitmusterInv.spin aus Abb. 4 in den Propeller Tool Editor und speichere es ab.
  • Starte das Programm und überprüfe, ob das Bitmuster invertiert wird.

 

 

 

 

 

 

 

 

Abb. 4

Der NOT-Operator invertiert ein vorgegebenes Bitmuster.

Hinweis

Mit den beiden Kürzeln „~“ und „~~“ lassen sich einige Programmzeilen weiter verkürzen. Der

  • Post-Clear-Operator „~“ setzt alle Ausgänge auf 0, der
  • Post-Set-Operator „~~“ setzt alle Ausgänge auf 1.

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

  • OUTA[17..22] := %000000 auch als
  • OUTA[17..22] := 0

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

 

 

 

 

 

 

 

 

 

 

Abb. 5

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:

  1. REPEAT 10
  2. REPEAT until OUTA[22..17] == 10
  3. REPEAT while OUTA[22..17] < 10, siehe Abb. 6

Eine weitere Möglichkeit ist :

  1. REPEAT until OUTA[22..17]++  == 10, wenn man gleichzeitig Zeile 18 im Programm repeat10_1while.spin (Abb. 6) streicht.
  2. REPEAT until ++OUTA[22..17]  == 11

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 „—".

 

 

 

 

 

 

 

 

Abb. 6

Programm repeat10_1while.spin

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 …).

  1. REPEAT while OUTA[22..17]++  < 10, wiederhole, solange Post-Inkrement < 10
  2. REPEAT while ++OUTA[22..17] < 10, wiederhole, solange Pre-Inkrement < 10

 

 

 

 

 

 

 

 

Abb. 7

While-Schleife mit Post-Increment. Die Zählung wird nach der Zahl 9 abgebrochen.

Drei weitere Möglichkeiten der Anwendung einer Wiederholungsschleife zeigen die folgenden Beispiele:

  1. REPEAT OUTA[22..17] from 1 to 10, zählt von 1 bis 10 hoch
  2. REPEAT OUTA[22..17] from 1 to 10 step 2, zählt in 2-er Schritten bis 10
  3. REPEAT while (OUTA[22..17] => 0) and (OUTA[22..17] =< 7)
      
    outa[22..17]++

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

  • Gib das Programm Lichtmuster.spin in den Editor ein und speichere es ab.
  • Versuche herauszufinden, was die sechs LEDs anzeigen werden, indem du jede Programmzeile in ihrer Wirkung erklärst.
  • Starte das Programm und vergleiche dein Ergebnis mit dem Programmablauf.

 

 

 

 

 

 

 

Abb. 8

Finde selbst heraus, was die sechs LEDs anzeigen werden.

Die Anweisung outa[22..17] >>= 1 schiebt das Bitmuster im Register um eine Stelle nach rechts.

Wie arbeitet das Programm Lichtmuster.spin?

 

  • Programmzeile 8 – 10

Die Zeitvariablen für den Systemtakt werden festgelegt.

  • Programmzeile 14

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]~.

  • Programmblock 16 – 21
  • Zeile 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.

  • Zeile 20

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

  • Übertrage das Programm TasterBildmuster.spin in den Propeller Tool Editor und speichere es ab.
  • Starte das Programm.
  • Überprüfe, ob sich die Geschwindigkeit der Bildmusterverschiebung über die Taster T1 und T2 stetig verändern lässt.

Das Programm TasterBildmuster.spin

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Abb. 9

Mit diesem Programm wird die Geschwindigkeit eines Lauflichts über zwei Taster verändert. Der eine erhöht, der andere erniedrigt die Laufgeschwindigkeit.

T1 ist mit P24, T2 mit P26 verbunden.

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,

  • VAR
  • Byte muster, teiler

wird mit dem pipe-Symbol „|“ eine lokale Variable:

  • PUB Lichtmuster  | muster, teiler

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.

 

 

 

 

 

 

Abb. 10

Das Programm Zeitmessung1.spin. Da der Controller für jede Befehlsanweisung mehrere Taktimpulse benötigt (mind. 4), ist der Sekundenblinker sehr ungenau. 

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.

 

 

 

 

 

 

 

 

Abb. 11

Das Programm Zeitmessung2.spin arbeitet wesentlich genauer als das Programm Zeitmessung1.spin. 

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

Druckversion | Sitemap
© Reinhard Rahner - Gettorf