- Das Experimentierhandbuch, Teil 2: Anwendungen -
Mit freundlicher Genehmigung des Franzis-Verlags
5 Programmstrukturen und Beispielprogramme
6 Fortgeschrittene Anwendungen
Anhang
Viele einfache Beispiele wurden bereits in den ersten Kapiteln vorgestellt. Hier sollen nun weitere folgen, die auch komplexere Programmstrukturen enthalten. Die vorgestellten Strukturen gibt es in jeder Programmiersprache, sie könnten also in ähnlicher Weise auch in Assembler, Basic oder C umgesetzt werden. Die gezeigten Verfahren gehen also über die Anwendung der TPS hinaus und sind als Grundmuster auch bei anderen Systemen anwendbar. Programmierübungen mit der TPS können daher auch den Weg in andere Mikrocontroller-Anwendungen erleichtern.
Ein Vorgang soll z.B. genau fünfmal ausgeführt werden. Dazu bildet man eine Zählschleife. Ein Sprungbefehl wird in diesem Fall fünfmal ausgeführt, danach nicht mehr. Die Zählvariable heißt C. Der Zählerwert 5 muss zuerst in A geladen werden und von da in C. Der Befehl A2 führt einen absoluten Sprung auf 02 aus und verkleinert zugleich den Inhalt der Variablen C um Eins. Wenn C den Wert Null erreicht hat, wird der Sprung nicht mehr ausgeführt. Die absolute Sprungadresse bezieht sich auf die angegebene Seite. Bei einem Programm auf der Seite 0 darf der Seiten-Befehl 80 auch weggelassen werden. Er ist aber unbedingt nötig, wenn eine andere Seite angesprungen wird.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
4 |
5 |
A = 5 |
01 |
5 |
2 |
C = A |
02 |
1 |
5 |
Port = 0101 |
03 |
2 |
8 |
500 ms |
04 |
1 |
A |
Port = 1010 |
05 |
2 |
8 |
500 ms |
06 |
8 |
0 |
Seite 0 |
07 |
A |
2 |
C-mal 02 |
08 |
3 |
0 |
Ende |
45 52 15 28 1A 28 80 A2 30
Listing 5.1: Eine Zählschleife
Testen Sie das Programm. Die LEDs zeigen bei jedem Durchgang die Muster 0101 und 1010. Allerdings wird dieser Programmteil offensichtlich nicht fünfmal, sondern genau sechsmal durchlaufen. Zwar wird der Sprungbefehl in Adresse 07 tatsächlich genau fünfmal ausgeführt. Um aber zum ersten Mal an diese Stellen zu gelangen, wird schon ein Blinkvorgang durchgeführt. Deshalb blinkt das Programm insgesamt sechsmal. Ändern Sie die Zählvariable auf den Wert 4 und testen Sie das Programm erneut. Nun blinken die LEDs genau fünfmal.
Man kann die Zählschleife auch so verwenden, dass nicht zurück, sondern vorwärts gesprungen wird. Diesmal wird der Vorgang tatsächlich fünfmal ausgeführt, wenn C am Anfang mit dem Wert 5 geladen wurde. Die jeweils übersprungene Adresse 04 enthält einen relativen Sprung auf sich selbst, und damit eine Endlosschleife, die als Programm-Ende dient.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
4 |
5 |
A = 5 |
01 |
5 |
2 |
C = A |
02 |
8 |
0 |
AdrHi =0 |
03 |
A |
5 |
C-mal 05 |
04 |
3 |
0 |
Ende |
05 |
1 |
5 |
Port = 0101 |
06 |
2 |
8 |
Warte 500 ms |
07 |
1 |
A |
Port = 1010 |
08 |
2 |
8 |
Warte 500 ms |
09 |
3 |
6 |
Springe - 6 |
45 52 80 A5 30 15 28 1A 28 36
Listing 5.2: Fünfmal Blinken
Zwei Zahlenwerte sollen verglichen werden. In Abhängigkeit vom Ergebnis des Vergleichs wird Sprung ausgeführt. Die beiden Zahlenwerte müssen sich in A und B befinden. Im folgenden Beispiel wird B mit der Zahl 5 geladen. A erhält sein Ergebnis vom Analogeingang AD1. Hier kann z.B. ein Lichtsensor angeschlossen sein wie in Kap. 2.4. Das Programm soll nun laufend die folgende Aktion durchführen:
Wenn AD1 > 5
dann: Alle LEDs an
sonst: Alle LEDs aus
Im Endergebnis erhält man einen Dämmerungsschalter. Da der LDR gegen GND angeschlossen ist, führt mehr Helligkeit zu einer kleineren Spannung an AD1. Die LEDs gehen aus, sobald eine gewisse Helligkeit überschritten, also eine gewisse Spannung unterschritten wird. Der Grenzwert liegt beim Wert 6, denn das Messergebnis muss größer als 5 sein.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
4 |
5 |
A = 5 |
01 |
5 |
1 |
B = A |
02 |
8 |
0 |
AdrHi = 0 |
03 |
6 |
9 |
A = AD1 |
04 |
C |
1 |
Skip if A>B |
05 |
9 |
8 |
Adr 08 |
06 |
1 |
F |
LEDs 1111 |
07 |
3 |
4 |
Adr 03 |
08 |
1 |
0 |
LEDs 0000 |
09 |
3 |
6 |
Adr 03 |
45 51 80 69 C1 98 1F 34 10 36
Listing 5.3: Einfacher Dämmerungsschalter
Testen Sie das Programm, indem Sie den Lichtsensor mit der Hand mehr oder weniger abschatten. Sie werden feststellen, dass die Grundfunktion erfüllt ist. Allerdings kommt es meist zu einem unschönen Nebeneffekt. Genau an der Grenze zwischen An und Aus blinken die LEDs unkontrolliert. Vor allem bei Kunstlicht schwankt die Helligkeit in schneller Folge um einen gewissen Mittelwert. Dieses Flackern wird zwar vom Programm korrekt ausgewertet, das Ergebnis ist aber nicht so, wie man es von einem Dämmerungsschalter erwartet. Einen verbesserten Dämmerungsschalter zeigt das Kapitel 6.1.
Meist verwendet man Zahlen, die mehrere Bits enthalten. Für manche Aufgaben ist as aber sinnvoller, mit Einzelbits zu arbeiten. Das trifft z.B. auf solche Aufgaben zu, bei denen eine einzelne Eingangsleitung ausgewertet werden soll. Das folgende Programm liest den Zustand der Leitung Din.2, also den Eingang E3. Der Lesebefehl 67 in Zeile 00 liefert entweder den Wert 0 oder den Wert 1 in A. Damit wird die LED am Ausgang A1 ein- oder ausgeschaltet. Alle anderen LEDs bleiben aus.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
6 |
7 |
A = Din.2 (E3) |
01 |
5 |
4 |
Port = A |
02 |
2 |
1 |
2 ms |
03 |
3 |
3 |
Springe - 3 |
67 54 21 33
Listing 5.4: Einzelbit-Abfrage
Abb. 5.1 Abfrage von E3
Testen Sie das Programm mit einem Kontakt oder Schalter zwischen E3 und GND. Im Ruhezustand ist die LED an A1 an. Bei geschlossenem Kontakt an E3 geht sie aus. Ändern Sie das Programm so, dass es auf einen anderen Eingang reagiert. Die folgende Lösung gilt für E1: 65 54 21 33
Auch Ausgänge können als Einzelbits gesteuert werden. Das folgende Programm steuert den Ausgang Port.2 = A3 an. Der Befehl 57 schaltet den Ausgang A3 immer dann an, wenn das unterste Bit im Akku Eins ist. Das gilt für die Zahlenwerte 1, 3, 5 usw., also bei ungeraden Zahlen. Das Programm zählt den Inhalt des Akkus laufend hoch. Die LED am Ausgang A3 blinkt mit einer Frequenz von einem Hertz.
Abb. 5.2: Ausgabe an A3
Adresse |
Befehl |
Daten |
Kommentar |
00 |
7 |
1 |
A = A + 1 |
01 |
5 |
7 |
Port.2 = A.0 |
02 |
2 |
8 |
500 ms |
03 |
3 |
3 |
Springe - 3 |
71 57 28 33
Listing 5.5: Blinker an A3
Ein Eingangs-Bit kann mit dem Umweg über den Akku auf ein Ausgangsbit kopiert werden. Das folgende Programm invertiert den Bit-Zustand durch Invertieren des Akkus. Der Ausgang A4 geht deshalb an, wenn der Eingang E3 an GND gelegt wird.
Abb. 5.3: Invertierter Ausgang
Adresse |
Befehl |
Daten |
Kommentar |
00 |
6 |
7 |
A = Din.2 |
01 |
7 |
A |
A = NOT A |
02 |
5 |
8 |
Port.3 = A.0 |
03 |
3 |
3 |
Springe - 3 |
67 7A 58 33
Listing 5.6: Einzelbit invertieren und kopieren
Eine weitere Art der Einzelbitverarbeitung gibt es im Zusammenhang mit den Skip-Befehlen. In Abhängigkeit vom Zustand eines einzelnen Portbits wird eine Adresse übersprungen. Vergleichbare Befehle wurden bereits zur Tastenabfrage eingesetzt. Hier werden die Ports E3 und E4 abgefragt. Wenn sie sich im Ruhezustand 1 befinden, wird der jeweilige Ausgabe-Befehl übersprungen, der Ausgangszustand ändert sich also nicht. Zieht man jedoch einen dieser Eingänge gegen GND, dann wird ein bestimmter Ausgangszustand erzwungen. Für den Ausgang A1 bedeutet das z.B., dass er mit E4 zurückgesetzt (Reset, R) und mit E3 gesetzt (Set, S) werden kann. Daraus ergibt sich die Funktion eines RS-Flipflops bzw. eines Umschalters.
Abb. 5.4: Umschalter mit zwei Ausgängen
Adresse |
Befehl |
Daten |
Kommentar |
00 |
C |
6 |
Skip if Din.2=1 |
01 |
1 |
1 |
Port = 1 |
02 |
C |
7 |
Skip if Din.3=1 |
03 |
1 |
8 |
Port = 8 |
04 |
3 |
4 |
Adresse = 0 |
C6 11 C7 18 34
Listing 5.7: Ein RS-Flipflop
Zwei binäre Zustände lassen sich zu einem neuen Zustand verknüpfen. Ein Beispiel ist die UND-Funktion: Wenn Bit1 den Zustand 1 hat UND Bit 2 den Zustand 1 hat, wird der Ausgangszustand ebenfalls 1. Auch Binärzahlen mit mehren Bit lassen sich auf diesen Weise verknüpfen. Die Verknüpfung „10 AND 3 = 2“ wird verständlich, wenn man sie in Binärzahlen schreibt:
1010 AND
0011 =
0010
Das folgende Programm verknüpft die Eingangszustände mit der konstanten Zahl 3. Die AND-Funktion bewirkt dabei praktisch, dass die beiden unteren Bits maskiert, also herausgefiltert werden. Im Ruhezustand hat der Eingangsport den Zustand 1111. Die UND-Verknüpfung mit 0011 liefert dann den Zustand 0011 an den LEDs. Legt man jedoch einen der Eingänge E1 oder E2 an GND, wird der 0-Zustand auch an den Ausgängen sichtbar. Änderungen an E3 und E4 haben keine Auswirkungen.
Abb. 5.6: Je vier Eingänge und Ausgänge
Adresse |
Befehl |
Daten |
Kommentar |
00 |
6 |
4 |
A = Din |
01 |
5 |
1 |
B = A |
02 |
4 |
3 |
A = 3 |
03 |
7 |
7 |
A= A And B |
04 |
5 |
4 |
Port = A |
05 |
3 |
5 |
Springe - 5 |
64 51 43 77 54 35
Listing 5.8: Anwendung der AND-Funktion
Ändern Sie das Programm, und testen Sie auch andere logische Funktionen. Die OR-Funktion (78) kann verwendet werden, um bestimmte Eingangszustände grundsätzlich auf 1 zu setzen: 64 51 43 78 54 35
1010 OR
0011 =
1011
Mit der XOR-Funktion (Exklusiv-Oder, 79) kann man einzelne Bits invertieren: 64 51 43 79 54 35
1010 XOR
0011 =
1001
Wenn Teile eines Programms mehrfach verwendet werden sollen, schreibt man sie in ein Unterprogramm. Damit spart man oft Speicherplatz, manchmal aber auch viel Tipparbeit. Das folgende Beispiel demonstriert die Verwendung eines Unterprogramms, das an zwei Stellen im Hauptprogramm aufgerufen wird. Das Unterprogramm enthält in diesem Fall nur eine Anweisung (A = A - 1) und den Rücksprungbefehl. Deshalb spart man hier keinen Speicherplatz, sondern das Beispiel dient nur zur Demonstration des CALL-Befehls und des RET-Befehls.
Hauptprogramm:
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
0 |
AdrHi=0 |
01 |
D |
8 |
Call 08 |
02 |
5 |
4 |
Ausgabe |
03 |
2 |
9 |
Warte 1 s |
04 |
D |
8 |
Call 08 |
05 |
5 |
4 |
Ausgabe |
06 |
2 |
8 |
Warte 0,5 s |
07 |
3 |
7 |
Springe - 7 |
Unterprogramm:
Adresse |
Befehl |
Daten |
Kommentar |
08 |
7 |
2 |
A = A - 1 |
09 |
E |
0 |
Ret |
80 D8 54 29 D8 54 28 37 72 E0
Listing 5.9: Unterprogramm-Aufrufe
Das Ergebnis des Programms ist ein absteigender Binärzähler mit ungleichen Zeitverzögerungen. Testen Sie auch einmal andere Befehle im Unterprogramm.
Unter den im Auslieferungszustand vorhandenen Beispielprogrammen gibt es mehrere nützliche Unterprogramme für die allgemeine Verwendung. Sie sind im Anhang komplett aufgelistet. Für den eigenen Einsatz muss nur die Einsprungadresse bekannt sein:
50: Unterprogramm: Ton lang
52: Unterprogramm: Ton kurz
53: Unterprogramm: Ton beliebig, Länge in A
60: Unterprogramm: Warte auf Tastendruck an S1
68: Unterprogramm: Warte auf Tastendruck an S2
70: Unterprogramm: Zahleneingabe mit S1 und S2
Das Unterprogramm ab der Adresse 60 soll nun verwendet werden, um einen Zähler aufzubauen, der über die Taste S1 gesteuert wird. Der Zählerstand beginnt mit Null. Das Hauptprogramm ist relativ kurz, weil die komplexe Aufgabe der Tastenabfrage in das Unterprogramm ausgelagert wurde.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
4 |
0 |
A = 0 |
01 |
5 |
4 |
Ausgabe |
02 |
7 |
1 |
A = A + 1 |
03 |
8 |
6 |
Seite 6 |
04 |
D |
0 |
Call 60, Taste S1 |
05 |
3 |
4 |
Springe - 4 |
40 54 71 86 D0 34
Listing 5.10: Über S1 gesteuerter Zähler
Testen Sie das Programm. Wenn Sie zehnmal auf S1 drücken, sollte das Ergebnis 1010 sein. Ändern Sie das Programm so ab, dass das Unterprogramm ab Adresse 68 verwendet wird. Nun reagiert der Zähler auf S2.
Zahlreiche Programmbeispiele aus den vorangegangenen Kapiteln eigenen sich bereits für den praktischen Einsatz. Dieses Kapitel zeigt weitere mehr oder weniger komplexe Anwendungen des TPS-Controllers. Die Anwendungen lassen sich leicht abwandeln und für konkrete Steuerungsaufgaben anpassen.
Ein Dämmerungsschalter mit einem Lichtsensor wie in Abb. 2.7 soll das Licht einschalten, wenn die Umgebungshelligkeit unter einen bestimmten Grenzwert fällt. Wenn es heller wird, soll umgekehrt das Licht wieder ausgeschaltet werden. Es sollte sichergestellt werden, dass das Licht auf der Grenze zwischen hell und dunkel nicht flackert. Das gelingt mit einer Hysterese, also einem gewissen Abstand der Einschalt- und Ausschalt-Helligkeit. Das hier vorgestellte Programm arbeitet nach den folgenden Regeln:
Wenn die Spannung an AD1 nicht größer als 5 ist, wird ausgeschaltet.
Wenn die Spannung an AD1 nicht kleiner als 9 ist, wird eingeschaltet.
Damit hat man einen mittleren Bereich, in dem keine Änderung des Ausgangszustands eintreten kann. Diese Lücke verhindert ein Flackern der LEDs.
0...5: LEDs aus
6...8: LEDs unverändert
9...15: LEDs an
Adresse |
Befehl |
Daten |
Kommentar |
00 |
1 |
0 |
LEDs 0000 |
01 |
4 |
5 |
A = 5 |
02 |
5 |
1 |
B = A |
03 |
6 |
9 |
A = AD1 |
04 |
C |
1 |
Skip if A>B |
05 |
1 |
0 |
LEDs 0000 |
06 |
4 |
9 |
A = 9 |
07 |
5 |
1 |
B = A |
08 |
6 |
9 |
A = AD1 |
09 |
C |
2 |
Skip if A<B |
0A |
1 |
F |
LEDs 1111 |
0B |
3 |
A |
Springe - 10 |
10 45 51 69 C1 10 49 51 69 C2 1F 3A
Listing 6.1: Dämmerungsschalter mit Hysterese
Ein einfacher Thermostat z.B. in einem Bügeleisen arbeitet als Zweipunktregler. Dabei gibt es zwei Temperaturen, bei denen das Heizelement ein- bzw. ausgeschaltet wird. Zwischen beiden Punkten gibt es eine Hysterese. Man stellt z.B. eine Temperatur von 80 Grad ein und erhält einen tatsächlichen Temperaturverlauf, der zwischen 78 °C und 82 °C schwankt.
Ein solcher Zweipunktregler soll hier in einem Modell nachgebildet werden. Statt der Temperatur wird die Spannung an einem Kondensator geregelt. Über einen Widerstand wird der Kondensator immer gerade entweder geladen oder entladen. Das Programm regelt die Spannung am analogen Eingang AD2 durch Ein- und Ausschalten der Ladespannung an A4 so nach, dass sie der Spannung am analogen Eingang AD1 entspricht. An AD2 soll ein Lichtsensor angeschlossen werden. Genauso könnte aber auch ein Poti oder eine andere Spannungsquelle angeschlossen sein. An AD1 liegt damit die Sollspannung. Sie wird mit der Istspannung an AD2 verglichen. Aus dem Ergebnis des Vergleichs ergibt sich dann, ob der Kondensator geladen (Ausgang 1000) oder entladen (Ausgang 0000) werden muss.
Abb. 6.1: Regelkreis an AD2
Abb. 6.2: Spannungsnachführung
Der Regelvorgang erfordert eine möglichst kleine Hysterese. Ohne besondere Maßnahmen ergibt sich eine Hysterese von einer Stufe des AD-Wandlers, also etwa 0,3 V. Im Betrieb sieht man ein schnelles Flackern der LED an A4. Die korrekte Funktion des Reglers kann auch mit einem Voltmeter oder einem Oszilloskop überprüft werden. Jede Änderung der Lichtverhältnisse ändert die Sollspannung am LDR und damit mit einer gewissen Verzögerung auch die Istspannung am Elko.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
6 |
9 |
A = AD1 |
01 |
5 |
1 |
B = A |
02 |
8 |
0 |
AdrHi = 0 |
03 |
6 |
A |
A=AD2 |
04 |
C |
1 |
Skip if A>B |
05 |
9 |
8 |
Adr 08 |
06 |
1 |
0 |
0000 |
07 |
3 |
7 |
Springe - 7 |
08 |
1 |
8 |
1000 |
09 |
3 |
9 |
Springe - 9 |
69 51 80 6A C1 98 10 37 18 39
Listing 6.2: Nachführung der Spannung
Das Ziel dieses Programmbeispiels ist eine steuerbare LED-Lampe. Die Helligkeit einer LED am PWM-Ausgang soll über Tasten einstellbar sein. Man kann dabei jeweils kurz auf eine Taste drücken um die nächste Helligkeitsstufe zu erreichen, oder man übt einen Dauerdruck aus, wobei die Helligkeit sich kontinuierlich verändert.
Im Kern des Programms kommen die schon bekannten Skip-Befehle zum Einsatz. Wenn die jeweilige Taste nicht gedrückt ist, wird der zugehörige Befehl zum Erhöhen oder Verkleinern des Akku-Inhalts übersprungen. Die Schwierigkeit besteht aber darin, dass normalerweise dabei auch ein Überlauf von 15 auf 0 oder von 0 auf 15 auftreten kann. Es erfordert etwas mehr Aufwand dieses Überlaufen zu verhindern. Dazu muss nämlich jeweils abgefragt werden, ob das untere Ende (0) oder das obere Ende (15) bereits erreicht ist. Da bei einem Vergleich grundsätzlich der Akku beteiligt ist, muss dessen Inhalt jeweils zwischengespeichert werden. Dazu wird die Variable C eingesetzt.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
0 |
AdrHi = 0 |
01 |
5 |
9 |
PWM = A |
02 |
2 |
7 |
200 ms |
03 |
5 |
2 |
C = A |
04 |
4 |
F |
A = 15 |
05 |
5 |
1 |
B = A |
06 |
6 |
2 |
A = C |
07 |
C |
2 |
Skip if A<B |
08 |
9 |
B |
Springe 0B |
09 |
C |
F |
Skip if S2=1 |
0A |
7 |
1 |
A = A + 1 |
0B |
5 |
2 |
C = A |
0C |
4 |
0 |
A = 0 |
0D |
5 |
1 |
B = A |
0E |
6 |
2 |
A = C |
0F |
C |
1 |
Skip if A>B |
10 |
9 |
0 |
Springe 00 |
11 |
C |
E |
skip if S1 = 1 |
12 |
7 |
2 |
A = A - 1 |
15 |
9 |
0 |
Springe 00 |
80 59 27 52 4F 51 62 C2 9B CF 71 52 40 51 62 C1 90 CE 72 90
Listing 6.3: Helligkeitssteuerung
Für ein Morseprogramm braucht man zunächst einmal eine passende Tonausgabe. Die Frequenz des PWM-Ausgangs ist dafür zu hoch. Also muss ein eigenes Programm entwickelt werden. Es soll Töne gleicher Frequenz, aber unterschiedlicher Tonlänge erzeugen.
Ein Unterprogramm für die Tonerzeugung befindet sich unter den Beispielprogrammen ab Adresse 50. Ein Aufruf bei Adresse 50 und erzeugt dabei den längeren Ton. Die Tonlänge wird bei einem Aufruf ab Adresse 53 durch die D-Zählschleife festgelegt und ist mit einem Wert von 15 maximal. Ein Einsprung bei Adresse 52 würde entsprechend einen kurzen Ton erzeugen.
Das folgende Programm entspricht weitgehend dem Unterprogramm ab Adresse 50 mit dem Unterschied, dass hier am Ende kein Rücksprung, sondern eine Endlosschleife steht. Nach einem Reset wird ein einzelner Ton maximaler Länge erzeugt. Testen Sie verschiedene Einstellungen der Wartebefehle. Das Programm bildet einen Kompromiss zwischen langer Tondauer und guter Hörbarkeit über einen Piezo-Schallwandler. Das Tonsignal erscheint am Ausgang A4.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
0 |
Seite 0 >lang |
01 |
4 |
F |
A = 15 |
02 |
9 |
4 |
Adr 04 |
03 |
4 |
5 |
A = 5 >kurz |
04 |
5 |
3 |
D = A >vari |
05 |
1 |
8 |
Dout 8 |
06 |
1 |
0 |
Dout 0 |
07 |
2 |
1 |
2 ms |
08 |
1 |
8 |
Dout 8 |
09 |
1 |
0 |
Dout 0 |
0A |
2 |
1 |
2 ms |
0B |
1 |
8 |
Dout 8 |
0C |
1 |
0 |
Dout 0 |
0D |
2 |
0 |
1 ms |
0E |
B |
5 |
D-mal 05 |
0F |
3 |
0 |
Ende |
80 4F 94 45 53 18 10 21 18 10 21 18 10 20 B5 30
Listing 6.4: Tonausgabe
Abb. 6.3 Anschluss des Schallwandlers
Abb. 6.4 Tonausgabe über A4
Das fertige Unterprogramm ab Adresse 50 kommt ohne den Seiten-Befehl aus, weil der Befehl 85 (Seite 5) ja schon vor dem Aufruf verwendet werden muss. Gleichzeitig wird in diesem Unterprogramm der Ausgang A1 für die Dauer des Tons eingeschaltet. Damit hat man die Möglichkeit, einen externen Tongenerator oder einen CW-Sender zu tasten. Ein langer Ton wird mit einem Unterprogrammaufrufe der Adresse 50 erzeugt, ein kurzer mit der Adresse 52.
Das folgende Morseprogramm erzeugt die beiden Zeichen B und K (die Initialen des Autors). Ein kurzes Programm wie dieses kann als eine Art akustische Visitenkarte verstanden werden. Ändern Sie das Programm so ab, dass Ihre eigenen Initialen gemorst werden.
Morsen: BK
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
5 |
AdrHi=5 |
01 |
D |
0 |
Call 50, lang |
02 |
2 |
6 |
100 ms |
03 |
D |
2 |
Call 52, kurz |
04 |
2 |
6 |
100 ms |
05 |
D |
2 |
Call 52, kurz |
06 |
2 |
6 |
100 ms |
07 |
D |
2 |
Call 52, kurz |
08 |
2 |
6 |
100 ms |
09 |
2 |
7 |
200 ms |
0A |
D |
0 |
Call 50, lang |
0B |
2 |
6 |
100 ms |
0C |
D |
2 |
Call 52, kurz |
0D |
2 |
6 |
100 ms |
0E |
D |
0 |
Call 50, lang |
0F |
3 |
0 |
Ende |
85 D0 26 D2 26 D2 26 D2 26 27 D0 26 D2 26 D0 30
Listing 6.5: Morseausgabe
Das folgende Programm verwendet zwei Tasten für eine einfache Stoppuhr. Die Zeitauflösung beträgt in diesem Fall eine Sekunde. Eine Zeitmessung wird mit S1 gestartet und mit S2 gestoppt. Der Stopp-Tastendruck muss länger als eine Sekunde dauern, um wirksam zu werden, weil das Programm einen Wartebefehl für eine Sekunde enthält. Das Messergebnis bleibt in der LED-Anzeige stehen. Mit einem zweiten Tastendruck auf S2 löscht man die Anzeige und bereitet die Stoppuhr auf eine neue Messung vor.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
6 |
Seite 6 “Stoppuhr Start/Stop” |
01 |
D |
0 |
Aufruf “Warte S1” |
02 |
4 |
0 |
A = 0 |
03 |
7 |
1 |
A = A + 1 |
04 |
5 |
4 |
Port = A |
05 |
2 |
9 |
Warte 1 s |
06 |
C |
D |
S2 = 0? |
07 |
3 |
4 |
Springe - 4 |
08 |
D |
8 |
Aufruf “Warte S2” |
09 |
4 |
0 |
A = 0 |
0A |
5 |
4 |
Port = A |
0B |
3 |
B |
Springe - 11 |
86 D0 40 71 54 29 CD 34 D8 40 54 3B
Listing 6.6: Stoppuhr
Testen Sie das Programm auch mit andern Zeiteinheiten, indem Sie den Wartebefehl in Adresse 05 ändern.
Ein fast gleiches Stoppuhr-Programm ist ab Adresse 40 als fertiges Beispielprogramm gespeichert. Das komplette Listing befindet sich im Anhang. Dort ist ein Wartebefehl für 5 ms eingesetzt. Die effektive Auflösung beträgt etwa 10 ms. Schreiben Sie ein kurzes Hauptprogramm mit einem Sprung auf die Adresse 40, um das Programm zu testen. Das Programm lässt sich auch als Reaktionstester einsetzen.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
4 |
Seite 4 |
01 |
9 |
0 |
Sprung nach 40 |
84 90
Listing 6.7: Start des Stoppuhr-Demoprogramms
Das hier vorgestellte Zahlenschloss soll den PWM-Ausgang einschalten, wenn der Benutzer die korrekte Zahlenfolge eingegeben hat. Die Zahleneingabe soll exakt nach dem Muster des Programmierens über die Tasten S1 und S2 ablaufen. Das folgende Programm demonstriert die Eingabe einer einzelnen Zahl über die Taste S1. Wie beim Programmiervorgang führt der erste Tastendruck zum Ergebnis 0000. Jeder folgende Druck auf S1 erhöht die Ausgabe um 1. Durch einen Druck auf S2 wird die Eingabe beendet. In diesem Fall endet das Programm in einer Endlosschleife.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
C |
C |
S1 = 0? |
01 |
3 |
1 |
Springe - 1 |
02 |
4 |
0 |
A = 0 |
03 |
5 |
4 |
Dout = A |
04 |
2 |
3 |
10 ms |
05 |
C |
E |
S1 = 1? |
06 |
3 |
2 |
Adr 04 |
07 |
C |
F |
S2 = 1? |
08 |
3 |
0 |
Ende |
09 |
C |
C |
S1 = 0? |
0A |
3 |
3 |
Adr 07 |
0B |
7 |
1 |
A = A + 1 |
0C |
2 |
3 |
10 ms |
0D |
C |
C |
S1 = 1? |
0E |
3 |
1 |
Adr 0D |
0F |
3 |
C |
Adr 03 |
CC 31 40 54 23 CE 32 CF 30 CC 33 71 23 CC 31 3C
Listing 6.8: Eingabe einer Zahl
Die Zahleneingabe steht auch als fertiges Unterprogramm ab Adresse 70 zur Verfügung. Statt der Endlosschleife in Zeile 08 gibt es hier einen RET-Befehl. Das Unterprogramm wird mit dem Ergebnis der Zahleneingabe in A verlassen.
Das folgende Zahlenschloss ruft die Zahleneingabe dreimal auf und vergleicht die Ergebnisse mit vordefinierten Zahlen. In diesem Beispiel lautet die korrekte Eingabe 3, 5, 2. Danach wird der PWM-Ausgang mit dem Wert 15 voll aufgesteuert. Jede Fehleingabe führt dagegen in eine Endlosschleife, die nur durch einen Reset wieder verlassen werden kann.
Der PWM-Ausgang wird in diesem Beispiel wie ein normaler Digitalport behandelt. Das ist erforderlich, weil alle vier Ausgänge A1 bis A4 für die Zahleneingabe benötigt werden. Nach jeder vollständigen Eingabe werden die vier LEDs gelöscht, um einem zufälligen Beobachter möglichst wenig Hinweise auf die geheime Zahlenkombination zu geben.
Adresse |
Befehl |
Daten |
Kommentar |
00 |
8 |
7 |
Page 7 |
01 |
4 |
3 |
A = 3 |
02 |
5 |
1 |
B = A |
03 |
D |
0 |
call 70 |
04 |
C |
3 |
Skip if A=B |
05 |
3 |
0 |
Ende |
06 |
1 |
0 |
LEDs aus |
07 |
4 |
5 |
A = 5 |
08 |
5 |
1 |
B = A |
09 |
D |
0 |
call 70 |
0A |
C |
3 |
skip if A=B |
0B |
3 |
0 |
Ende |
0C |
1 |
0 |
LEDs aus |
0D |
4 |
2 |
A = 2 |
0E |
5 |
1 |
B = A |
0F |
D |
0 |
call 70 |
10 |
C |
3 |
Skip if A=B |
11 |
3 |
0 |
Ende |
12 |
1 |
0 |
LEDs aus |
13 |
4 |
F |
A = 15 |
14 |
5 |
9 |
PWM=A |
15 |
3 |
0 |
Ende |
87 43 51 D0 C3 30 10 45 51 D0 C3 30 10 42 51 D0 C3 30 10 4F 59 30
Listing 6.9: Das Zahlenschloss
Listing der Beispielprogramme
Adresse |
Befehl |
Daten |
Kommentar |
00 |
6 |
4 |
A = Din |
01 |
5 |
1 |
B = A |
02 |
4 |
E |
A = 1110 |
03 |
8 |
0 |
Seite 0 |
04 |
C |
3 |
A = B? |
05 |
9 |
8 |
Springe 08 |
06 |
8 |
2 |
Seite 2 |
07 |
9 |
5 |
Springe 25, “Hochzählen” |
08 |
4 |
D |
A = 1101 |
09 |
8 |
0 |
Seite 0 |
0A |
C |
3 |
A =B ? |
0B |
9 |
E |
Springe 0E |
0C |
8 |
2 |
Seite 2 |
0D |
9 |
A |
Springe 2A, “AD/PWM” |
0E |
4 |
B |
A = 1011 |
0F |
8 |
1 |
Seite 1 |
64 51 4E 80 C3 98 82 95 4D 80 C3 9E 82 9A 4B 81
Seite 0: Auswahl und Start der Beispielprogramme
Adresse |
Befehl |
Daten |
Kommentar |
10 |
C |
3 |
A = B? |
11 |
9 |
4 |
Springe 14 |
12 |
8 |
3 |
Seite 3 |
13 |
9 |
0 |
Springe 30, “Zufall” |
14 |
4 |
7 |
A = 0111 |
15 |
8 |
1 |
Seite 1 |
16 |
C |
3 |
A =B? |
17 |
9 |
A |
Springe 1A |
18 |
8 |
3 |
Seite 3 |
19 |
9 |
4 |
Springe 34, “Stoppuhr S1” |
1A |
4 |
3 |
A = 0011 |
1B |
8 |
2 |
Seite 2 |
1C |
C |
3 |
A =B? |
1D |
9 |
0 |
Springe 20 “Wechselblinker” |
1E |
8 |
4 |
Seite 4 |
1F |
9 |
0 |
Springe 40 “Stoppuhr S1/S2” |
C3 94 83 90 47 81 C3 9A 83 94 43 82 C3 90 84 90
Seite 1: Auswahl und Start der Beispielprogramme
Adresse |
Befehl |
Daten |
Kommentar |
20 |
1 |
1 |
0001 “Wechselblinker” |
21 |
2 |
8 |
Warte 500 ms |
22 |
1 |
8 |
1000 |
23 |
2 |
8 |
Warte 500 ms |
24 |
3 |
4 |
Springe - 4 |
25 |
7 |
1 |
A = A + 1 “Hochzählen” |
26 |
5 |
4 |
Port = A |
27 |
5 |
9 |
PWM = A |
28 |
2 |
6 |
Warte 100 ms |
29 |
3 |
4 |
Springe - 4 |
2A |
6 |
9 |
A = AD1 “AD/PWM” |
2B |
5 |
4 |
Port = A |
2C |
5 |
9 |
PWM = A |
2D |
2 |
6 |
Warte 100 ms |
2E |
3 |
4 |
Springe - 4 |
2F |
F |
F |
- |
11 28 18 28 34 71 54 59 26 34 69 54 59 26 34 FF
Seite 2: Beispielprogramme: Wechselblinker, Hochzählen, AD/PWM
Adresse |
Befehl |
Daten |
Kommentar |
30 |
5 |
4 |
Port = A “Zufall” |
31 |
C |
E |
S1 = 1? |
32 |
7 |
1 |
A = A + 1 |
33 |
3 |
3 |
Springe - 3 |
34 |
2 |
2 |
Warte 5 ms “Stoppuhr S1” |
35 |
C |
C |
S1 = 0? |
36 |
3 |
2 |
Springe - 2 |
37 |
4 |
0 |
A = 0 |
38 |
2 |
2 |
Warte 5 ms |
39 |
7 |
1 |
A = A + 1 |
3A |
5 |
4 |
Port = A |
2B |
C |
E |
S1 = 1? |
3C |
3 |
4 |
Springe - 4 |
3D |
3 |
9 |
Springe - 9 |
3E |
F |
F |
- |
3F |
F |
F |
- |
54 CE 71 33 22 CC 32 40 22 71 54 CE 34 39 FF FF
Seite 3: Beispielprogramme: Zufall, Stoppuhr S1
Adresse |
Befehl |
Daten |
Kommentar |
40 |
8 |
6 |
Seite 6 “Stoppuhr Start/Stop” |
41 |
D |
0 |
Aufruf “Warte S1” |
42 |
4 |
0 |
A = 0 |
43 |
7 |
1 |
A = A + 1 |
44 |
5 |
4 |
Port = A |
45 |
2 |
3 |
Warte 10 ms |
46 |
C |
D |
S2 = 0? |
47 |
3 |
4 |
Springe - 4 |
48 |
D |
8 |
Aufruf “Warte S2” |
49 |
4 |
0 |
A = 0 |
4A |
5 |
4 |
Port = A |
4B |
3 |
B |
Springe - 11 |
4C |
F |
F |
- |
4D |
F |
F |
- |
4E |
F |
F |
- |
4F |
F |
F |
- |
86 D0 40 71 54 23 CD 34 D8 40 54 3B FF FF FF FF
Seite 4: Beispielprogramm Stoppuhr Start/Stop
Adresse |
Befehl |
Daten |
Kommentar |
50 |
4 |
F |
A=15 “Ton lang” |
51 |
9 |
3 |
Adr 03 |
52 |
4 |
5 |
A=5 “Ton kurz” |
53 |
5 |
3 |
D=A “Ton variabel” |
54 |
1 |
9 |
A4 = 1 |
55 |
1 |
1 |
A4 = 0 |
56 |
2 |
1 |
2 ms |
57 |
1 |
9 |
A4 = 1 |
58 |
1 |
1 |
A4 = 0 |
59 |
2 |
1 |
2 ms |
5A |
1 |
9 |
A4 = 1 |
5B |
1 |
1 |
A4 = 0 |
5C |
2 |
0 |
1 ms |
5D |
B |
4 |
Dmal 04 |
5E |
1 |
0 |
Dout 0 |
5F |
E |
0 |
Return |
4F 93 45 53 19 11 21 19 11 21 19 11 20 B4 10 E0
Seite 5: Unterprogramm Tonausgabe
Adresse |
Befehl |
Daten |
Kommentar |
60 |
2 |
3 |
Warte 10 ms “Warte S1” |
61 |
C |
E |
S1 = 1? |
62 |
3 |
2 |
Springe - 2 |
63 |
2 |
3 |
Warte 10 ms |
64 |
C |
C |
S1 = 0? |
65 |
3 |
1 |
Springe - 1 |
66 |
E |
0 |
Return |
67 |
F |
F |
- |
68 |
2 |
3 |
Warte 10 ms “Warte S2” |
69 |
C |
F |
S2 = 1? |
6A |
3 |
2 |
Springe - 2 |
6B |
2 |
3 |
Warte 10 ms |
6C |
C |
D |
S2 = 0? |
6D |
3 |
1 |
Springe - 1 |
6E |
E |
0 |
Return |
6F |
F |
F |
- |
23 CE 32 23 CC 31 E0 FF 23 CF 32 23 CD 31 E0 FF
Seite 6: Unterprogramme Warte S1 und Warte S2
Adresse |
Befehl |
Daten |
Kommentar |
70 |
C |
C |
S1 = 0? „Tasteneingabe“ |
71 |
3 |
1 |
Springe - 1 |
72 |
4 |
0 |
A = 0 |
73 |
5 |
4 |
Port = A |
74 |
2 |
3 |
Warte 10 ms |
75 |
C |
E |
S1 = 1? |
76 |
3 |
2 |
Springe - 2 |
77 |
C |
F |
S2 = 1? |
78 |
E |
0 |
Return |
79 |
C |
C |
S1 = 0? |
7A |
3 |
3 |
Springe - 3 |
7B |
7 |
1 |
A = A + 1 |
7C |
2 |
3 |
Warte 10 ms |
7D |
C |
C |
S1 = 1? |
7E |
3 |
1 |
Springe - 1 |
7F |
3 |
C |
Springe - 12 |
CC 31 40 54 23 CE 32 CF E0 CC 33 71 23 CC 31 3C
Seite 7: Unterprogramm Tasteneingabe
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
A |
B |
C |
D |
E |
|
Port= |
Wait |
Jump - |
A= |
... =A |
A= ... |
A= ... |
Page |
Jump |
C* |
D* |
Skip if ... |
Call |
Ret |
0 |
0 |
1 ms |
0 |
0 |
|
|
|
0 |
0 |
0 |
0 |
|
0 |
|
1 |
1 |
2 ms |
1 |
1 |
B=A |
A= B |
A=A+1 |
1 |
1 |
1 |
1 |
A>B |
1 |
|
2 |
2 |
5 ms |
2 |
2 |
C=A |
A=C |
A=A–1 |
2 |
2 |
2 |
2 |
A<B |
2 |
|
3 |
3 |
10 |
3 |
3 |
D=A |
A=D |
A=A+B |
3 |
3 |
3 |
3 |
A=B |
3 |
|
4 |
4 |
20 |
4 |
4 |
Dout=A |
A=Din |
A=A–B |
4 |
4 |
4 |
4 |
Din.0=1 |
4 |
|
5 |
5 |
50 |
5 |
5 |
Dout.0=A.0 |
A=Din.0 |
A= A*B |
5 |
5 |
5 |
5 |
Din.1=1 |
5 |
|
6 |
6 |
100 |
6 |
6 |
Dout.1=A.0 |
A=Din.1 |
A=A/B |
6 |
6 |
6 |
6 |
Din.2=1 |
6 |
|
7 |
7 |
200 |
7 |
7 |
Dout.2=A.0 |
A=Din.2 |
A=A And B |
7 |
7 |
7 |
7 |
Din.3=1 |
7 |
|
8 |
8 |
500 |
8 |
8 |
Dout.3= A.0 |
A=Din.3 |
A=A Or B |
|
8 |
8 |
8 |
Din.0=0 |
8 |
|
9 |
9 |
1 s |
9 |
9 |
PWM=A |
A=AD1 |
A= A Xor B |
|
9 |
9 |
9 |
Din.1=0 |
9 |
|
A |
10 |
2 s |
10 |
10 |
|
A =AD2 |
A=Not A |
|
A |
A |
A |
Din.2=0 |
A |
|
B |
11 |
5 s |
11 |
11 |
|
|
|
|
B |
B |
B |
Din.3=0 |
B |
|
C |
12 |
10 s |
12 |
12 |
|
|
|
|
C |
C |
C |
S1=0 |
C |
|
D |
13 |
20 s |
13 |
13 |
|
|
|
|
D |
D |
D |
S2=0 |
D |
|
E |
14 |
30 s |
14 |
14 |
|
|
|
|
E |
E |
E |
S1=1 |
E |
|
F |
15 |
60 s |
15 |
15 |
|
|
|
|
F |
F |
F |
S2=1 |
F |
|
Die Befehlstabelle
Schaltplan der TPS-Platine
Das Platinenlayout
1 |
S2 |
S1 |
2 |
3 |
Reset |
PWM |
4 |
5 |
A1 |
A2 |
6 |
7 |
A3 |
A4 |
8 |
9 |
GND |
VCC |
10 |
Pfostenstecker SV1
1 |
S2 |
S1 |
2 |
3 |
AD1 |
AD2 |
4 |
5 |
E1 |
E2 |
6 |
7 |
E3 |
E4 |
8 |
9 |
GND |
VCC |
10 |
Pfostenstecker SV2
Die Firma AK Modul-Bus bietet Zusatzplatinen zum Anschluss an die Erweiterungsstecker SV1 und SV2 am TPS-Controller an, die alternativ auch an das ES-M32 und das STK500 passen. Es handelt sich um ein Eingangsmodul mit Optokopplern, einen Leistunsgreiber mit ULN2803 und ein Relaismodul mit vier Umschalt-Relais. Damit lässt sich die TPS für zahlreiche Steuerungsaufgaben einsetzen, bei denen höhere Leistungen oder höhere Spannungen gefragt sind.
Übersicht: www.ak-modul-bus.de/stat/entwicklungssysteme.html