Pfad: Home => AVR-deutsch => Programmiertechniken => Struktur

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.

Kommentare

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

Angaben im Kopf des Programmes

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

Angaben zum Programmbeginn

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

Strukturierung von Programmen

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