Start AVR-KursStartseiteserielles ISP-Interface

10. Zeitschleifen und Unterprogramme


Im Kapitel 9 wurde Testprogramme vorgestellt, die neben ein paar unbedeutenden Schaltaufgaben in der Hauptsache nicht anderes getan haben als zu warten - bis eine bestimmte Zeit vorüber war.

Dieses Warten kann durch Zeitschleifen realisiert werden, oder wesentlich effektiver was die Prozessorleistung angeht durch Multitasking, doch dazu kommen wir in Kapitel 12.

Die kleinste messbare Zeitbasis bei einem Prozessor ist die Taktperiodendauer. Bei unserem Experimentierboard mit dem Tiny 2313 und dem 8 MHz-quarz ist das 8.000.000 Teil einer Sekunde 1/8.000.000 = 0,125 µs. Alle Zeiten, die mit diesem Controller erfasst, gemessen oder vorgegeben werden sind Vielfache dieser Zeitbasis. Für menschliches Ermessen ist das natürlich eine sehr kurze Zeit, weshalb man einen Bedarf für die Darstellung wesentlich längerer Zeiträume hat. Um diese zu realisieren kann man den Prozessor einfach nur zählen lassen, bis ein bestimmter eindeutig zuordenbarer Zeitzählerzustand erreicht ist. Man nutzt aus, dass die Anzahl von Takten zur Abarbeitung eines bestimmten Befehls bekannt und aus dem Datenblatt auf den Seiten 217/ 218 in der letzten Spalte (Clocks) entnehmbar ist. Analysieren wir ein Beispiel.

Analyse:

Zeit vergeht, indem wir vom Prozessor einfach Befehle ausführen lassen. Man könnte diese einfach aneinander reihen, was aber sehr ineffektiv und im Fall von auch nur einer Sekunde Wartedauer nicht machbar ist, denn von den 8.000.000 Befehlen passen höchstens 2048 in den Flashspeicher des Prozessors.

Entwurf:

Der Programmablaufplan zeigt genau was geschehen soll. Das Register 16 wird mit dem konstanten Wert 10 geladen. Gleich danach wird damit begonnen den Wert in R16 herunterzuzählen. Jedes mal wird nach dem Verringern geprüft ob R16 bereits den Stand 0 erreicht hat. Ist das nicht der Fall, wird die Marke loop: angesprungen und das Herunterzählen wiederholt. Das Ganze so lange, bis R16 den Wert 0 enthält.

 

Implementierung: Wir übersetzen den Programmablaufplan in ein Assemblerprogramm, wir codieren die Sequenz

start:, loop: und fertig: sind sogenannte Labels, Sprungmarken, die durch Sprung- oder Verzweigungsbefehle angesprungen werden können. Man kann sie auch gut mit den Sprungzielen in HTML-Texten vergleichen. Nur dass im ersten Fall der Sprung programmgesteuert ausgeführt wird und im Fall der HTML-Seite das auslösende Ereignis ein Mausklick war. Die Labels start: und fertig: sind optional, loop: dagegen muss zum Erreichen des Programmziels verwendet werden, das wird aus dem Ablaufplan klar. Wir betrachten das gleiche Programm, jetzt aber mit Taktzählung.

Die folgende Tabelle zeigt die Taktanzahl pro Schleifendurchlauf und die erreichte Gesamtanzahl von Takten

Bis auf den letzten Schleifendurchlauf sind es jeweils 3 Takte, einer entfällt auf das Herunterzählen von R16 und jeweils zwei auf das Vergleichen und den Sprung. Beim letzten Durchlauf findet kein Sprung statt, deshalb werden nur zwei Takte angesetzt. Insgesamt sind es also (10 - 1) mal 3 Takte + 1 Takt Vorlauf + 2 Takte letzter Schleifendurchlauf = 9 * 3 +1+2 = 30 Takte. Hierbei ist die Zeit 30 * 0,125 µs = 3,75 µs vergangen.

Fragen - Aufgaben:

1. Durch welche Änderung im Programm kann die Zeitdauer für das Warten auf genau 4,000 µs gebracht werden? (Lösung)

2. Welche Zeit vergeht, wenn man in die Schleife zwei NOP-Befehle (No Operation) einbaut, die genau nichts tun aber zur Abarbeitung auch 1 Takt benötigen? (Lösung)

3. Mit welchem Wert ist R16 anfangs zu laden, damit bei 4 NOP-Befehlen im Schleifenkörper genau 1000 µs als Pausenlänge herauskommen? (Lösung)

4. Erstelle eine Formel, die für eine Quarzfrequenz von 8,0000 MHz und eine fest angegebene Zeitverzögerung den Startwert für R16 zu berechnen erlaubt. Gehe von 2 NOP-Befehlen im Schleifenkörper aus. (Lösung)

Soviel schon vorab, das Problem der Aufgabe 3 ist nur zu lösen, wenn man die Schleife mit einem geeigneten Startwert in R16 mehrmals durchlaufen lässt. Das führt zu zu folgendem Lösungsansatz für die Überbrückung längerer Zeiträume.

Eine Schleife von der Natur der Aufgabe 4 bringt bei einem Anfangswert von 80 für R16 eine Gesamtverzögerung von 400 Takten welche bei 8,000 MHz einer Zeit von 50 µs entsprechen. Betrachtet man diese Schleife quasi als Sammelbefehl (Macro) der 400 Takte beansprucht, dann kann man dieses Macro in eine weitere Schleife verpacken und mit einem eigenen Startwert versehen (R17 := 100). Diese zweite Schleife wird nun insgeasmt 100 mal durchlaufen. Es ergeben sich folgende Taktzahlen.

Innere Schleife: 400 Takte

Gesamtverzögerung: (wir rechnen wie oben)

(100 - 1) * (400 + 1 + 2) + 1 + 400 + 1 + 1 = 99 * 403 + 403 = 100 * 403 = 40300 (Takte)

Das entspricht einer Zeitverzögerung von 40300 * 0,125 µs = 5,038 ms

 

Aufgabe 5:

Kann man durch geschickte Wahl der Startwerte und evtl. eine Veränderung / Verschiebung der NOP-Befehle im folgenden Programmlisting erreichen, dass die Zeitverzögerung genau 5,000ms ergibt? (Lösung)

Aufgabe 6.

Ergänze das Programm so, dass sich eine Verzögerung von möglichst genau einer Sekunde ergibt. (Lösung)

So, und weil ihr alle recht artig wart, gibt's zum Abschluss noch ein Bonbon. Es kann ja nun sein, dass man solche Verzögerungen an mehreren Stellen im Programm benötigt und vielleicht auch mit unterschiedlichen Zeiten. Das Problem ist dann platzsparend mit Hilfe von Unterprogrammen hinzubekommen.


Start AVR-KursAn den Seitenbeginnnicht verfügbar

 


Lösungen:

1. Obiges Programmbeispiel ergibt 3,73 µs Delay, fehlen 0,250 µs auf die geforderten 4,000 µs. 0,250 µs entsprechen bei 8,0000 MHz zwei Takten. Also ergänzen wird z. B. nach der Marke fertig: zwei Ladebefehle

...
fertig:
ldi R16, 0
ldi R16, 0

oder man verwendet wie in Aufgabe 2 zwei NOP-Befehle, die keinerlei auswirkung auf das Programmgeschehen haben außer dass für jeden die Zeitdauer von einem Takt vergeht.

...
fertig:
NOP
NOP


2. So sieht das Programm aus:

Und das ist das ist die Calc-Tabelle dazu

Rechnung: (10 - 1) * 5 + 1 + 4 = 45 * +1 + 4 = 50 (Takte)
Zeitdauer = Delay = 50 * 0,125 µs = 6,25 µs


3. Wir machen es erst einmal wieder mit zehn Schleifendurchläufen insgesamt:

Taktanzahl: (10 -1) * (1+4+2) +1 +(1+4+1) = 9 * 7 + 1 + 6 = 70
Zeit: t = 70 * 0,125 µs = 8,750 µs

Und jetzt von Hinten:

t = 1000 µs; dafür braucht man 1000µs : (0,125 µs/Takt) = 8000 Takte
Statt 10 setzen wir n in den Term für die Taktanzahl ein

(n-1) * (1 + 4 + 2) + 1 + ( 1 + 4 + 1) = 8000

(n-1)*7 + 7 = 8000

(n-1)*7 = 7993

n-1 = 1141,86 gerundet 1142

n = 1143

Es wären 1143 Schleifendurchläufe nötig. Das ist aber mit einem Register nicht machbar, weil man maximal den Wert 255 darin unterbringen kann. Abhilfe: man müsste die Schleife 9 mal aufrufen und das Register R16 jedes Mal mit dem Zahlenwert 127 = 0x7F vorbelegen. Warum ist das ein Ausweg?


4. Es sei t die gewünschte Zeit in µs. Dann ist A die Anzahl von dafür nötigen Takten.

A = t : (0,125 µs/Takt)

Mit n als Vorbelegung für R16 (in der Schleife 1 Runterzählen + 2 NOP + 2 Vergleich und Sprung)

(n - 1) * (1 + 2 + 2) + 1 + (1 + 2 + 1) = t : (0,125 µs/Takt)

(n - 1) * 5 + 5 = t : (0,125 µs/Takt)

n * 5 = t : (0,125 µs/Takt)

n = (t : (0,125 µs/Takt)) : 5

Für 50 µs Delay:

n = (50 µs : 0,125 µs/Takt) : 5 = 80

Wenn die Schleife mit 2 NOPs insgesamt 80 mal durchlaufen wird, ist die Verzögerungszeit 50 µs.

Diese Schleife verzögert den Programmlauf um 50 µs:


5. Wir müssen versuchen die 300 Takte Überhang zu beseitigen, die durch die zwei Befehle in der aüßeren Schleife entstehen.

Erster Ansatz: Wir zählen in der äußeren Schleife nur bis 99 statt bis 100. Das spart 403 Takte ein, aber jetzt haben wir 103 Takte zu wenig. Wir fügen gleich nach dem Befehl zur Verringerung von R17 einen NOP-Befehl ein, 100 mal ausgeführt wird und damit fehlen uns nur noch 3 Takte, die wir nach der Marke fertig: als 3 NOP-Befehle einfügen.

Zweiter Ansatz: Ich entferne aus der inneren Schleife einen NOP-Befehl, lasse die Schleife aber dafür 99 mal durchlaufen und füge den NOP-Befehl so wie eben gleich nach dem Befehl zur Verringerung von R17 ein. Wer nachrechnet kommt ganau auf 40000 Takte, was einer Zeit von 5000µs = 5,000ms entspricht.

Überprüfe die beiden Ansätze mit Hilfe des Simulators von ATMEL AVR Studio. Gib dazu das Programm von Aufgabe 5 ein und führe dann die Änderungen durch.


6. Die bisherigen beiden Schleife werden in eine dritte verpackt, die 200 mal durchlaufen muss. Das ergibt dann 200 * 5 ms = 1000 ms = 1s. Stimmt natürlich wieder nicht ganz exakt, weil 200 µs zu viel sind, was aber lediglich 200µs vo 1000000µs ausmacht, das sind grade mal 0,2 Promille Abweichung. Wenn die Anwendung nicht gerade als Uhr laufen soll, pfeiff drauf.