Pfad:
Home =>
AVR-deutsch =>
Programmiertechniken => Struktur
(This page in English:
)
Struktur von AVR-Assembler-Programmen
In diesem Abschnitt werden die Strukturen vorgestellt, die für Assembler-Programme
typisch sind und sich immer wieder wiederholen. Dazu gehören
Kommentare, die Angaben im Kopf des Programmes,
der Code zu Beginn des eigentlichen Programmes und der
Aufbau von Programmen.
Das wichtigste an Assemblerprogrammen sind die Kommentare. Ohne Kommentierung des
geschriebenen Codes blickt man schon nach wenigen Tagen oft nicht mehr durch, wofür
das Programm gut war oder was an dieser Stelle des Programmes eigentlich warum getan wird.
Man kann natürlich auch ohne Kommentare Programme schreiben, vor allem wenn man sie
vor anderen und vor sich geheim halten will.
Ein Kommentar beginnt mit einem Semikolon. Alles, was danach in dieser Zeile folgt, wird
vom Übersetzungsprogramm, dem Assembler, einfach ignoriert. Wenn man mehrere Zeilen
lange Kommentare schreiben möchte, muss man eben jede weitere Zeile mit einem
Semikolon beginnen. So sieht dann z.B. der Anfang eines Assemblerprogrammes z.B. so aus:
;
; Klick.asm, Programm zum Ein- und Ausschalten eines Relais alle zwei Sekunden
; Geschrieben von G.Schmidt, letzte Änderung am 6.10.2001
;
Kommentieren kann und soll man aber auch einzelne Abschnitte eines Programmes, wie z.B.
eine abgeschlossene Routine oder eine Tabelle. Randbedingungen wie z.B. die dabei
verwendeten Register, ihre erwarteten Inhalte oder das Ergebnis nach der Bearbeitung
des Teilabschnittes erleichtern das spätere Aufsuchen von Fehlern und vereinfachen
nachträgliche Änderungen.
Man kann aber auch einzelne Zeilen mit Befehlen kommentieren, indem man den Rest der
Zeile mit einem Semikolon vor dem Assembler abschirmt und dahinter alles mögliche
anmerkt:
LDI R16,0x0A ; Hier wird was geladen
MOV R17,R16 ; und woanders hinkopiert
Zum Seitenanfang
Den Sinn und Zweck des Programmes, sein Autor, der Revisionsstand und andere Kommentare
haben wir schon als Bestandteil des Kopfes identifiziert. Weitere Angaben, die hier hin
gehören, sind der Prozessortyp, für den die Software geschrieben ist, die
wichtigsten Konstanten (zur übersichtlichen Änderung) und die Festlegung von
errinnerungsfördernden Registernamen.
Der Prozessortyp hat dabei eine besondere Bedeutung. Programme laufen nicht ohne
Änderungen auf jedem Prozessortyp. Nicht alle Prozessoren haben den gleichen
Befehlssatz, jeder Typ hat seine typische Menge an EEPROM und SRAM, usw. Alle diese
Besonderheiten werden in einer besonderen Kopfdatei (header file) festgelegt, die in den
Code importiert wird. Diese Dateien heissen je nach Typ z.B. 2323def.inc, 8515def.inc,
etc. und werden vom Hersteller zur Verfügung gestellt. Es ist guter Stil, mit
dieser Datei sofort nach dem Kommentar im Kopf zu beginnen. Sie wird
folgendermaßen eingelesen:
.NOLIST ; Damit wird das Auflisten der Datei abgestellt
.INCLUDE "C:\avrtools\appnotes\8515def.inc" ; Import der Datei
.LIST ; Auflisten wieder anschalten
Der Pfad, an dem sich die Header-Datei befindet, kann natürlich weggelassen werden,
wenn sie sich im gleichen Verzeichnis wie die Assemblerdatei befindet. Andernfalls ist der
Pfad entsprechend den eigenen Verhältnissen anzupassen.
Das Auflisten der Datei beim Übersetzen kann nervig sein, weil solche Header-Dateien
sehr lang sind, beim Auflisten des übersetzten Codes (entstehende .lst-Datei)
entsprechend lange Listen von meist uninteressanten (weil trivialen) Informationen
produzieren. Das Abschalten vor dem Einlesen der Header-Datei spart jede Menge Papier beim
Ausdrucken der List-Datei.
Es lohnt sich, einen kurzen Blick in die Include-Datei zu werfen. Zu Beginn der Datei wird
mit
.DEVICE AT90S8515 ; Festlegung des Zieldevices
der Zielchip definiert. Das wiederum bewirkt, dass Befehle, die auf dem Zielchip nicht definiert
sind, vom Assembler mit einer Fehlermeldung zurückgewiesen werden. Die Device-Anweisung an
den Assembler braucht also beim Einlesen der Header-Datei nicht noch einmal in den Quellcode
eingegeben werden (ergäbe eine Fehlermeldung).
Hier sind z.B. auch die Register XH, XL, YH, YL, ZH und ZL definiert, die beim byteweisen
Zugriff auf die Doppelregister X, Y und Z benötigt werden. Ferner sind darin alle
Port-Speicherstellen definiert, z.B. erfolgt hier die Übersetzung von PORTB in hex 18.
Schließlich sind hier auch alle Port-Bits mit denjenigen Namen registriert, die im
Datenblatt des jeweiligen Chips verwendet werden. So wird hier z.B. das Portbit 3 beim Einlesen
von Port B als PINB3 übersetzt, exakt so wie es auch im Datenblatt heißt.
Mit anderen Worten: vergisst man die Einbindung der Include-Datei des Chips zu Beginn des
Programmes, dann hagelt es Fehlermeldungen, weil der Assembler nur Bahnhof versteht. Die
resultierenden Fehlermeldungen sind nicht immer sehr aussagekräftig, weil fehlende
Labels und Konstanten vom ATMEL-Assembler
nicht mit einer Fehlermeldung quittiert werden. Stattdessen nimmt der Assembler einfach an, die
fehlende Konstante sei Null und übersetzt einfach weiter. Man kann sich leicht vorstellen,
welches Chaos dabei herauskommt. Der arglose Programmierer denkt: alles in Ordnung. In Wirklichkeit
wird ein ziemlicher Käse im Chip ausgeführt.
In den Kopf des Programmes gehören insbesondere auch die Register-Definitionen, also z.B.
.DEF mpr = R16 ; Das Register R16 mit einem Namen belegen
Das hat den Vorteil, dass man eine vollständige Liste der Register erhält und sofort
sehen kann, welche Register verwendet werden und welche noch frei sind. Das Umbenennen vermeidet
nicht nur Verwendungskonflikte, die Namen sind auch aussagekräftiger.
Ferner gehört in den Kopf die Definition von Konstanten, die den gesamten Programmablauf
beeinflussen können. So eine Konstante wäre z.B. die Oszillatorfrequenz des Chips,
wenn im Programm später die serielle Schnittstelle verwendet werden soll. Mit
.EQU fq = 4000000 ; Quarzfrequenz festlegen
zu Beginn der Assemblerdatei sieht man sofort, für welchen Takt das Programm geschrieben ist.
Beim Umschreiben auf eine andere Frequenz muss nur diese Zahl geändert werden und man braucht
nicht den gesamten Quelltext nach dem Auftauchen von 4000000 zu durchsuchen.
Zum Seitenanfang
Nach dem Kopf sollte der Programmcode beginnen. Am Beginn jedes Codes stehen die Reset- und
Interrupt-Vektoren (zur Funktion siehe Sprung). Da diese
relative Sprünge enthalten müssen, folgen darauf am besten die Interrupt-Service-Routinen.
Danach ist ein guter Platz für abgeschlossene Unterprogramme. Danach sollte das Hauptprogramm
stehen.
Das Hauptprogramm beginnt mit immer mit dem Einstellen der Register-Startwerte, dem Initialisieren
des Stackpointers und der verwendeten Hardware. Danach geht es programmspezifisch weiter.
Zum Seitenanfang
Der beschriebene Standardaufbau ist in der Vorlage
enthalten, die auch als .asm-Version im Quellverzeichnis vorliegt.
Zum Seitenanfang
©2002 by http://www.avr-asm-tutorial.net