Start AVR-KursStartseiteserielles ISP-Interface

11. Unterprogramme


Der Name sagt es schon, Unterprogramme ( Subroutinen, subroutines, Proceduren, (Funktionen)) sind Programmteile, die einem Hauptprogramm untergeordnet sind. Das hat Konsequenzen. Proceduren sind nicht selbständig lauffähig, sie können nur von einem Hauptprogramm (main program = main) aufgerufen werden. Sie können dafür aber beliebig oft von verschiedener Stelle im Hauptprogramm aufgerufen werden. Das spart Programmspeicherplatz. Man kann auch Daten an Unterprogramme übergeben. Die übergebenen Daten nennt man dann Parameter (die Betonung liegt auf dem zweiten a). Wenn Proceduren nicht nur Parameter in Empfang nehmen sondern auch Werte an das Haupt- oder ganz allgemein an das aufrufende Programm zurückgeben nennt man die Proceduren Funktionen und die Rückgabewerte Funktionswerte. Ja es stimmt schon, auch Proceduren dürfen ihrerseits andere Unterprogramme aufrufen. Das geht fast beliebig oft.

Der Stackbereich

Der SRAM (Schreib-Lese-Speicher, wahlfreier Speicherbereich, Random Access Memory) bedient zweierlei Bedarf. Der Benutzerbereich beginnt bei der Spaiecheradresse 0x60 und endet theoretisch bei 0xDF. Gleichzeitig wird der SRAM vom sogenannten Stack benutzt, das ist ein Bereich, den die CPU benutzen kann, um sich dort zwischenzeitlich Dinge merken zu können. Dieser Stackbereich wächst von oben (0xDF) nach unten (Richtung 0x60), weshalb er oft auch mit Kellerspeicher überstetzt wird. Das kommt rein vom Verhalten her der Sache näher wie der deutsche Begriff Stapel. Wenn man etwas auf den Stapel legt, wird dieser ja schließlich höher und nicht niedriger. Aber egal, der Stack wird von der CPU über einen eigenen Mechanismus verwaltet, auf den der Benutzer nur bedingt Einfluss hat. Ein spezielles IO-Register, genannt SPL (Stack Pointer Low = Stack Speicherzeiger = SFR 0x3D) zeigt stets auf die Adresse der nächsten freien Speicheradresse. Zum Programmstart muss der Inhalt des SPL-Registers vom Programmierer gesetzt werden, dann übernimmt die Verwaltung die CPU. Wichtig ist noch, dass die Daten, die zuletzt auf den Stack gelegt werden, egal von wem, auch als erste wieder abgeholt werden müssen. Wer das nicht beachtet, erzeugt ein heilloses Chaos und die CPU versinkt im Nirwana.

Verwendung des Stackspeichers

Der Stack wird meistens in Verbindung mit Unterprogrammen eingesetzt. Der Aufruf von Unterprogrammen funktioniert über diese Methode, denn der Prozessor muss ja nach Abarbeitung des Unterprogramms wieder zu seinem Ausgangspunkt zurückfinden. Aber auch der Benutzer kann den Stack nutzen, um z. B. dort den Inhalt von Registern abzulegen bevor der Prozess des Unterprogramms beginnt, und sie nach Abarbeitung der Procedur wieder zu restaurieren, kurz bevor die Kontrolle wieder an das Hauptprogramm übergeben wird.

Wie funktionieren Unterprogramme?

Wir starten ein Hauptprogramm. Der Programmzähler, ein Registerpaar in dem stets die Adresse des gerade abgearbeiteten Befehls steht, wird auf 0x0000 gestetz. Mit jedem behandelten Befehl wird der Programmzähler in der Regel um eins erhöht. Das geht so lange bis in diesem Beispiel der Programmzähler (pc = program counter) auf der Nummer des Proceduraufrufs "Rufe sub1 auf" steht. Der Proceduraufruf bewirkt nun folgendes:

1. Der aktuelle Stand des pc wird um eins von 0x0135 auf 0x0136 erhöht.

2. Der 2-Bytewert des pc wird in der Reihenfolge Lowbyte - Highbyte auf dem Stack abgelegt. Das Lowbyte 0x36 wird an die erste freie Stelle (0xDF) geschoben, dann wird SPL um eins verringert (nächste freie Stelle im Stack). Das Highbyte 0x01 wird in die Speicherstelle 0xDE geschoben und der SPL-wert wieder um 1 verringert (nächste freie Stelle 0xDD).

3. Der pc wird auf die erste Adresse des Unterprogramms sub1 gesetzt und die CPU beginnt ihre Arbeit mit dem ersten Befehl der Procedur.

4. Das Ende der Procedur ist erreicht, der Processor erkennt das am letzten Befehl des Unterprogramms, der RET (RETurn from subroutine) lauten muss.

5. Der RET-Befehl bewirkt das Auslesen der Rücksprungadresse vom Stack in den pc. Zuerst wird der SPL um ens verringert, dann das aktuelle Byte gelesen und als Highbyte in den pc geschrieben. SPL wieder um eins verringern, Byte lesen und als Lowbyte in den pc schreiben. Die zuletzt gelesene Speicherstelle ist die nächste freie Speicherstelle, somit zeigt der SPL weiterhin auf diese Adresse.

6. Der Programmablauf wird an der Stelle fortgesetzt, die auf den Unterprogrammaufruf folgt.

Der Programmierer muss soweit den Überblick bewahren, dass er abschätzen kann, ob der Stack und der normale User-SRAM sich irgenwann überdecken könnten. Dass auch dieser Fall Chaos erzeugen wird dürfte jedem klar sein. Schwierig wird es bei Controllern der Tinyserie, die keinen SRAM-Bereich haben. Diese Bausteine besitzen nur einen SRAM, der ausschließlich von Unterprogrammen in 3 Ebenen genutzt werden kann.

Zeitschleifen mit Unterprogrammen

Wie schon angedeutet kann man Zeitschleifen auch als Unterprogramme schreiben und von verschiedenen Stellen des Hauptprogramms aus aufrufen. Das Beispiel demonstriert den Aufruf der Routine, die 5 ms wartet.

Wir modifizieren das Ganze nun so, dass eine Wartezeit von 1 Sekunde herauskommt. Nicht dargestellte Programmteile wurden nicht modifiziert. Lediglich um den Proceduraufruf "rcall wait5ms" wurde ein weitere Schleife konstruiert, die 200 mal durchlaufen wird. 200 mal 5 ms ergibt 1 Sekunde.

Zum Schluss soll noch gezeigt werden, wie man einen Parameter an eine Procedur übergibt. Anstatt das Register R17 im Unterprogramm mit einem Wert (100) zu belegen, kann das auch vom Hauptprogramm auf gemacht werden. Der Befehl ldi r17, 20 belegt vor jedem Proceduraufruf das Register R17 mit dem Wert 20. Wird jetzt die Procedur wait_xms aufgerufen, dann beginnt der Countdouwn nicht bei 100 sondern bei 20. Das Unterprogramm wartet jetzt also nicht mehr 1 Sekunde sondern nur 0,2 Sekunden. So kann man in gewissen Grenzen von verschiedenen Stallen aus in einer Auflösung von 5 ms unterschiedliche Wartezeiten einstellen. Und das alles erfolgt sehr platzsparend und flexibel dank des Unterprogramms wait_xms.

 

 


Start AVR-KursAn den Seitenbeginnnicht verfügbar