Microcontrollerprogrammierung in Assembler
1. Einleitung
1.1 Mikrocontroller oder Mikrorechner?
Ein Mikrocontroller ist ein Prozessor, bei dem im Unterschied zu PC-Prozessoren (Mikrorechnern) Speicher, wichtige Baugruppen wie Zeitgeber, digitale sowie analoge
Ein- und Ausgabegeräte, auf einem einzigen Chip integriert sind, so dass eine Mikrocontroller-Lösung oft mit einigen wenigen externen Bauteilen auskommt.
Ein PC-Prozessor verfügt nicht über eigene Eingabe- und Ausgabekomponenten, sondern über eine Verbindung zu einem externen Systembus, an dem die Ein und
Ausgabegeräte zum Beispiel als Steckkarten angeschlossen sind. In immer mehr Geräten des Alltags werden die Aufgaben von analogen Schaltungen durch
Mikrocontroller realisiert. Damit lassen sich vor allem die Produktionskosten der Hardware drastisch senken. Prinzipiell kann die Struktur und Arbeitsweise von
Mikrorechnern und Mikrocontrollern mit der von-Neumann-Architektur erklärt werden.
1.2 von-Neumann-Architektur (ausgewählte Aspekte):
- Ein Rechner besteht aus einer Zentraleinheit mit Rechenwerk und Steuerwerk, Eingabegeräten, Ausgabe- geräten und einem Arbeitsspeicher
- Die intern verwendete Signalmenge ist binär codiert (Digitalrechner)
- Der Rechner verarbeitet Worte fester Länge (Verarbeitungsbreite, Bussystem, Register, Speicher)
- Die Programmbefehle werden sequenziell in der Reihenfolge ihrer Speicherung abgearbeitet.
Befehlszyklus:
- POWER-ON oder RESET
- lade Befehlszeiger mit fester Startadresse (z. B.: OxOO)
- lese Befehl (von Adresse im Befehlszeiger)
- decodiere Befehl (Steuerwerk)
- führe Befehl aus (Rechenwerk)
- erhöhe den Befehlszeiger um 1, weiter mit 3.
- Der Rechner arbeitet taktgesteuert;
- Die sequenzielle Verarbeitung von Befehlen kann durch Sprunganweisung geändert werden;
- Befehlszeiger = Sprungadresse, Sprung mit oder ohne Bedingung, Unterprogrammaufruf mit Speicherung der Rücksprungadresse.
Prozessoren werden als erstes an der Verarbeitungsbreite der internen Architektur unterschieden: 8 Bit, 16 Bit, 32 Bit, 64 Bit usw. Diese Bit-Zahl kann man als die
Länge der Datenworte interpretieren, die der Controller/Prozessor in einem Befehl verarbeiten kann. Die größte in 8 Bit (=1 Byte) darstellbare Zahl ist die 255. Somit
kann ein 8-Bit-Mikrocontroller z. B. in einem einfachen Additionsbefehl nur Zahlen von 0 bis 255 verarbeiten und das Ergebnis kann ebenfalls nicht größer als 255
sein, sonst liegt ein Ergebnis-Überlauf vor. Zur Bearbeitung von größeren Zahlen werden dann mehrere Befehle hintereinander benötigt, was bei diesem Prozessor
natürlich länger dauert.
Ein Prozessor benötigt eine meist extern eingespeiste Taktfrequenz. Dieses Taktsignal gibt dem Prozessor vor, wann der nächste Befehlsschritt ausgeführt werden
soll. Da die Baugruppen innerhalb des Prozessors weder unendlich schnell noch gleich schnell arbeiten, ist dieses Synchronisationssignal für die Zusammenarbeit
von Steuerwerk, Rechenwerk, Ein- und Ausgabegeräten notwendig. Die maximale Frequenz, mit der ein Prozessor betrieben werden kann, reicht heute von 1 MHz bis hin zu über 3 GHz.
Bei Mikrocontrollern sind im Moment Taktfrequenzen von 1 bis 300 MHz üblich. Diese Taktfrequenz sagt jedoch noch nichts über die tatsächliche
Geschwindigkeit eines Prozessors aus. Es ist auch entscheidend, ob für den oben beschriebenen Befehlszyklus viele, wenig oder gar nur ein Taktzyklus benötigt wird.
Bei vielen Prozessoren wird die Frequenz intern geteilt, ein mit 24 MHz getakteter Mikrocontroller der Intel Reihe 8051 arbeitet eigentlich nur mit 2 MHz, da der externe
Takt durch 12 geteilt wird. Benötigt dieser dann für einen Befehl durchschnittlich 2 Taktzyklen, so bleiben "nur" noch 1 Mio. Befehle pro Sekunde übrig
(1 MIPS, Million Instructions per Second). Dieser Sachverhalt trifft besonders auf Prozessoren zu, die eine CISC-Architektur besitzen (Complex Instruction Set
Computer). Betrachten wir dazu im Gegensatz eine RISC-Architektur (Reduced Instruction Set Computer), finden wir hier kaum interne Taktteilungen und für die
Ausführung eines Befehls wird oft nur ein Taktzyklus benötigt. Ein moderner RISC-Mikrocontroller, der ungeteilt mit 8 MHz arbeitet und für viele Befehle nur einen
Prozessorzyklus braucht, schafft gegenüber dem mit 24 MHz getakteten CISC Controller fast 8 Mio. Befehle pro Sekunde (8 MIPS). Ein RISC-Prozessor hat dafür
einen geringeren Befehlssatz. Komplexe Befehle wie eine Division, müssen deshalb algorithmisch umgesetzt werden.
1.3 Wozu ist ein Mikrocontroller gut?
Welche Aufgaben Mikrocontroller haben und warum sie eine zunehmende Bedeutung erlangen, soll folgender Einsatzfall verdeutlichen. Uns allen sind Detektoren
unterschiedlichster Art bekannt. Am auffälligsten sind die Portalmetalldetektoren in Flughäfen oder wichtigen öffentlichen Gebäuden, aber auch der stationäre Blitzer
um die Ecke verfügt als Sensor über einen Metalldetektor in der Fahrbahn. Ein anderer Anwendungsfall ist zum Beispiel die Lebensmittelindustrie. Es ist sehr
wichtig für den Hersteller von Backmischungen, dass keine Nägel, Schrauben, Metallsplitter oder ähnliches während des Produktionsprozesses in das Nahrungsmittel
gelangt. Auf der Verpackungsstrecke werden alle Packungen, in denen der Metalldetektor Metallteile ortet, automatisch ausgesondert. Metalldetektoren werden
in großen Stückzahlen für unterschiedlichste Anwendungsfälle benötigt. Das folgende Schema zeigt die Funktionseinheiten eines Metalldetektors nach dem Pulsinduktionsverfahren (PI).

Abbildung: Metalldetektor nach dem Pulsinduktionsverfahren (PI)
Der klassische Aufbau eines solchen Detektors als diskrete analoge Schaltung erfordert trotz Verwendung integrierter Schaltungen einen bestimmten, kaum weiter
reduzierbaren Materialaufwand an aktiven und passiven Bauelementen. Die Materialkosten für diesen konkreten Metalldetektor belaufen sich auf ca. 25 €.

Abbildung: vollst. Aufbau analoger Metalldetektor
Einen nicht unerheblichen Teil dieser diskreten Schaltung macht die Realisierung des "Timings", also der Steuerung der verschiedenen Komponenten für den Detektor
aus. Der folgende Detektor hat das gleiche Arbeitsprinzip und die gleiche Leistungsfähigkeit wie der oben gezeigte Detektor. Der Materialaufwand ist jedoch
um ein vielfaches geringer (Materialkosten ca. 8 €). Dies wurde erreicht, indem die Steuerung des Detektors von einem Mikrocontroller und der entsprechenden Software darauf übernommen wurde.

Abbildung: vollst. Aufbau Metalldetektor mit Microcontroller

Abbildung: Funktionsverlagerung von der Hardware zur Software
Die zuvor diskret mit analogen Bauelementen realisierten Funktionen des Detektors werden in der mikrocontrollerbasierenden Lösung in die Software verlagert.
Damit reduziert sich die Anzahl der aktiven und passiven analogen Bauelemente.
Die Komplexität und Größe der Leiterplatte konnte reduziert werden. In der Gesamtheit konnten die Kosten für die Herstellung eines Detektors auf ein Drittel reduziert
werden. Die wirtschaftliche Bedeutung der Reduzierung der Stückkosten, in diesem Fall um 60%, braucht man nicht weiter zu betonen. Aber selbst wenn
die Kostenreduzierung durch den Mikrocontrollereinsatz pro System nur einige Cent beträgt, liegt der Kostenreduzierungseffekt in der Massenfertigung schnell bei Millionen Euro.
Ganz klar, die Softwarelösung für den Tongenerator lässt sich auf jedes einzelne System kopieren und verursacht keine Beschaffungskosten mehr. Die diskrete Lösung
benötigt eine integrierte Schaltung (IC), 3 Widerstände und einen Kondensator mehr und diese müssen für jedes zu produzierende Gerät neu beschafft werden.
Und das ist noch nicht alles. Die Mikrocontrollerlösung könnte sogar beliebige Melodien abspielen, die der Hersteller im Internet zum Herunterladen anbieten
kann. Solche zusätzlichen Eigenschaften werden von den Anwendern der Lösungen gern angenommen, wie der aktuelle Trend bei Klingeltönen und Handylogos
zeigt. Es werden nicht nur Kosten, Platz und Gewicht gespart, sondern zusätzliche Möglichkeiten eröffnet. Daher auch der ungebrochene Trend, selbst einfache Geräte
wie eine Kaffeemaschine mit einem Mikrocontroller auszustatten.
Hier ein paar Beispiele, für welche Aufgaben Mikrocontroller verwendet werden können: Roboter, CD-, MP3- und DVD-Player, Temperaturregler, Füllstandsregler,
Motorsteuerungen, Signaldecoder für Satellitenempfang, Fernbedienung, Alarmanlagen, Schaltuhren, Ladegeräte, Waschmaschinen, Geschirrspüler, Fernseher,
Radio, Wecker/Uhr, Messwerterfassung (z. B. Drehzahlmessung im Auto), intelligente Geräte in der Auto- matisierungstechnik, intelligente Sensoren, intelligente
Aktaren z. B. die Airbags im PKW, Handy, alle Formen von Heimelektronik, Geräte der Medizintechnik, Spielzeug u.v.m. .
Anforderungen und Möglichkeiten von Mikrocontrollerlösungen:
- programmierbar (Update, Optimierung, Wartung)
- flexible Schnittstellen (vielfältig, integriert, standardisiert)
- Selbstdiagnose, Fehlerkorrektur, Debuginterface
- Echtzeitfähigkeit (schnelle Reaktionszeiten)
- Timer, Interruptfähigkeit
- deterministisch (bestimmbares, berechenbares Verhalten)
- geringe Kosten, geringer Leistungsverbrauch
Die Anwendungsgebiete von Mikrocontrollern sind schier unendlich. In allen Bereichen unseres Lebens lassen sich heute "versteckte" Mikrocontroller finden.
1.4 Welchen Mikrocontroller verwenden?
Mikrocontroller werden von unterschiedlichen Firmen angeboten. Weit verbreitete Mikrocontroller sind die der Intel-Reihe 8051, der Zilog-Reihe Z80, Z86, die PICController
der Firma Microsystems und die AVR-Controller der Firma Atmel. Die AVR-Reihen von Atmel haben eine innovative RISC-Architektur, die schnell und
einfach zu erlernen ist. Sie sind inzwischen sehr weit verbreitet. Sie sind elektrisch robust und bis zu 10.000-mal programmierbar. Da die AVR-Prozessoren zu den
modernsten Controllern am Markt gehören und enorme Zuwachsraten aufweisen, sollen sich alle Ausführungen und die Experimentierhardware auf diese Controller
beziehen. Prinzipiell lassen sich jedoch alle Aussagen auf alle anderen Mikrocontroller übertragen.
Ein pikanter Hintergrund ist, dass der AVR-Kern eine Entwicklung von zwei Studenten der Universität Trontheim in Norwegen ist. Atmel kaufte die Lizenz und
entwickelte dieses innovative Konzept weiter. Hartnäckig hält sich das Gerücht, dass die Abkürzung "AVR" etwas mit den Vornamen der beiden inzwischen nicht
mehr Studenten Alf Egil Bogen und Vegard Wollan zu tun hat, die diesen RISC-Prozessor entwickelt haben.
1.5 Welche Programmiersprache benutzen?
Assembler ist für den Einstieg in die Programmierung von Mikrocontrollern zwar recht schwierig, aber am besten geeignet. Da Assemblerprogramme auf Maschinencodeebene
angesiedelt sind, lernt man den Aufbau und Funktionsweise eines Prozessors richtig kennen und kann ihn dadurch optimal ausnutzen. Zudem stößt
man bei jedem Compiler irgendwann einmal auf Problemstellungen, die sich nur durch das Verwenden von Assemblercode lösen lassen. Die zunehmende Leistungsfähigkeit
und immer mehr Speicher auf den Mikrocontrollern erlauben inzwischen auch die Anwendung von höheren Programmiersprachen. Die Sprachen
C/C++ bieten sich auf Grund ihrer Effizienz und Hardwarenähe für die Programmierung von komplexen Mikrocontrollerlösungen an.
Der AVR Assembler wird Ihnen Schritt für Schritt und verständlich vermittelt. Mit den so erworbenen Kenntnissen ist die Programmierung von AVR-Controllern mit
jeder anderen Sprache noch effizienter. Die Auseinandersetzung mit den Maschinenbefehlen und der Programmierung in Assembler führt zum besseren Verständnis
des Aufbaus und der Arbeitsweise des Prozessors/Mikrocontrollers.

Abbildung: AVR- Assemlerprogramm
2. Grundlagen zu Mikrocontrollern
In diesem Kapitel soll nochmals kurz auf ausgewählte Aspekte der Hardware und Software eingegangen werden. Das myAVR Board wird als Referenzhardware vorgestellt.
2.1 Hardwaregrundlagen
Mikrocontroller gehören zu der Klasse der frei programmierbaren Universalprozessoren. Programmierbare Prozessoren gibt es in unterschiedlichen Ausprägungen
und Einsatzfeldern. Im Folgenden eine Auswahl von verschiedenen Prozessorklassen:
Mikroprozessor: Ein "herkömmlicher" Prozessor, wie er auch in PCs zu finden ist. Die Verbindung mit der Außenwelt erfolgt ausschließlich über weitere Bausteine
in einem Bussystem. Fokus: allgemeine Aufgaben, Leistung, Flexibilität, Standardhardware, Standardsoftware.
Mikrocontroller: Ein Mikrocontroller beinhaltet in einem Chip bereits alle Komponenten, die ihn zu einem funktionsfähigen 1-Chip-IJRechner machen. Er
besitzt also neben einem Prozessor auch Speicher, diverse Schnittstellencontroller, Timer und einen Interruptcontroller. Er kann über digitale und analoge
Ein- und Ausgabeleitungen Mess- und Steueraufgaben ausführen. Fokus: Spezialisierung auf konkrete Aufgaben, Platzbedarf, Energieverbrauch.
Signalprozessor: Digitaler Signalprozessor (DSP), Mixed-Signal-Controller. Darunter versteht man Mikrocontroller, die sowohl digitale als auch analoge
Signale sehr schnell verarbeiten können. Fokus: Spezialisierung auf Signalverarbeitung (Audio, Video, Datenübertragung), Geschwindigkeit, Platzbedarf, Energieverbrauch.
Embedded Prozessor: Embedded System: Mikrocontroller oder DSP werden häufig als eingebettete Systeme verwendet. Das sind Systeme, in denen die
Steuereinheit im Zielsystem integriert ist. Ein Beispiel wäre ein Mobiltelefon, hier ist der steuernde Controller im Gerät selbst integriert.

Abbildung: Prinzipschaltbild Mikrocontroller
2.1.1 Prozessorkern (Zentraleinheit)
Die Zentraleinheit setzt sich zusammen aus dem Steuerwerk und dem Rechenwerk. Im Steuerwerk befindet sich der Befehlsdecoder. Dieser "erkennt" alle Befehle,
die die Zentraleinheit ausführen kann, verteilt die Aufgaben und synchronisiert die einzelnen Elemente der Zentraleinheit sowie die der Ein- und Ausgabeeinheiten.
Das Rechenwerk, die Arithmetic Logic Unit (ALU), führt alle logischen und mathematischen Operationen durch. Für diese Berechnungen sind die Operationen Addition
und Subtraktion zuständig. Das Rechenwerk liefert als Ergebnis der ausgeführten Operationen die sogenannten Flags (Ereignisspeicher), die nach einem
bestimmten Zustand einer Funktion oder einer Berechnung gesetzt oder zurückgesetzt werden. Diese werden dann als Bedingungen für den Algorithmus benutzt.
Die komplette Zentraleinheit wird in der Fachsprache als Mikroprozessor bezeichnet. Wenn nun alle drei Baugruppen, die Zentraleinheit, der Zentralspeicher und
entsprechende Peripheriebausteine, in einem Gehäuse integriert sind, bezeichnet man diesen Prozessor als Mikrocontroller, Ein-Chip-Mikrorechner oder Embedded Computer.

Abbildung: Integration aller Baugruppen auf eiem Chip
Die Integration auf einem Chip hat offensichtlich einen enormen Vorteil in Bezug auf den Platzbedarf. Stellen Sie sich vor, Ihr Handy würde auf einem PC-Mainboard
mit den entsprechenden Komponenten basieren. Den hohen Integrationsgrad erkauft man sich aber mit einer viel geringeren Gesamtleistung. Vor allem
die Geschwindigkeit und die Speicherkapazität sind wesentlich geringer als bei PC-Systemen. Wo man beim PC auf 512 MB oder 1 GB Arbeitsspeicher zurückgreifen
kann, haben Mikrocontroller zum Beispiel 128 Byte oder 512 Byte Arbeitsspeicher. Ein 8 MHz getakteter Mikrocontroller erscheint zuerst viel langsamer als
ein mit 3000 MHz arbeitende PC. Betrachtet man aber das Einsatzfeld und die konkreten Aufgaben der Mikrocontroller, reichen oft auch schon 1 MHz aus.
Ein
immer wieder zu lösendes Problem der vorgestellten Mikrocontrollerlösungen ist es, das mit 3,6 MHz getaktete System per Wartefunktionen zu bremsen. Unterprogramme
und Funktionen wie wait und delay spielen für viele Programme von Mikrocontrollern eine wichtige Rolle. Die Entwicklung bei den Mikrocontrollern
geht aber genauso wie bei allen anderen Rechnern zu immer höherer Geschwindigkeit und mehr Speicherkapazität.
2.1.2 Peripherie-Bausteine
Digitale Ein-/Ausgabe-Bausteine
Die wichtigsten Ein-/Ausgabegeräte sind digitale Ein- und Ausgabebausteine. Diese werden als Ports bezeichnet und können digitale Signale (HI/LO, 1/0, 5/0 V)
ausgeben oder einlesen. Ein Port besteht meist aus mehreren Lines (Leitungen,Bits). Typisch sind 4, 6 oder 8 Lines je Port. Damit können EIN/AUS-Zustände,
Schaltvorgänge, Impulse oder Frequenzen erzeugt bzw. gelesen werden. Die Leitungen sind als Pins des Controllers nach außen geführt.
Um analoge Messwerte erfassen zu können, also beliebige Spannungswerte zum Beispiel zwischen 0 und 5 V, benötigt man spezielle Bausteine. Typisch sind hier
der Comparator und der Analog-Digital-Wandler (A/D-Wandler, engl.: ADC Analog-Digital-Converter).
Comparator
Ein Comparator kann zwei "beliebige" Spannungen miteinander vergleichen und anzeigen, ob eine Eingabespannung größer oder kleiner als eine vorgegebene
Referenzspannung (Schwellwert) ist. Comparatoren sind sehr genau und schnell.
A/D-Wandler
Ein A/D-Wandler kann einen "beliebigen" analogen Spannungswert in einen Zahlenwert umwandeln. Der Wert wird als ganzzahlige Zahl dem Prozessor zur weiteren
Verarbeitung bereitgestellt. Die Genauigkeit (Resolution) der Umwandlung des analogen Wertes in einen digitalen Wert entspricht der Anzahl der Bit-Stellen des
vom A/D-Wandler gelieferten Digitalwertes. Typisch sind Auflösungen von 4, 6, 8, 10, 12, 16 Bit. A/D-Wandler benötigen für die Konvertierung (Conversion) des
Analogwertes eine von Fall zu Fall unterschiedliche Zeit (Conversion Time).
D/A-Wandler
Wenn beliebige (analoge) Spannungen ausgegeben werden sollen, kann dies über einen Digital-Analog-Wandler (D/A-Wandler) erfolgen, der aus einer digitalen
Zahl des Mikrocontrollers eine entsprechende Ausgangsspannung erzeugt. Es ist aber auch möglich, mit einfachen passiven Bauelementen (Kondensator, Widerstand)
aus einer Frequenz unterschiedliche Spannungswerte zu erzeugen.
Timer-Baustein
Viele Aufgaben, die durch Mikrocontroller zu erfüllen sind, erfordern eine zeitabhängige Steuerung. Aber auch umfangreiche Zählvorgänge oder die Verarbeitung
von Frequenzen erfordern einen Timer/Counter-Baustein. Für die Messung von Uhrzeit und Tagesdatum gibt es Echtzeit-Uhren-Bausteine (Real Time Clock,RTC).
Sender/Empfänger-Baustein
Zur Übertragung von größeren Datenmengen an andere Systeme oder Bausteine werden spezielle Schnittstellenbausteine eingesetzt, die entsprechende Standardübertragungsprotokolle
unterstützen. Aufgrund der unterschiedlichen Einsatzfelder ergibt sich die Notwendigkeit zweier unterschiedlicher Schnittstellenarten. Typische
Schnittstellenbausteine sind UART (Universal, Asynchron, Receiver, Transmitter, für RS232 oder USB), SPI (Serial Prozessor Interface für externe Speicher und Programmierung), 12C-BUS oder CAN-BUS.
Interruptcontroller-Baustein
Um kurze Reaktionszeiten des Mikrocontrollers bei Veränderungen an Ein-/Ausgängen oder internen Bausteinen zu erhalten, gibt es eine Unterbrechungslogik
(Interruptcontroller) für die laufenden Programme. Diese überwacht ständig alle Interruptquellen, unterbricht das aktuelle Programm, wenn von irgendeiner Quelle
ein Interrupt ausgelöst wird und startet eine zugehörige Interruptserviceroutine (ISR). Ist die Abarbeitung dieser Routine beendet, kehrt die CPU wieder zum ursprünglichen Programm zurück.
Watchdog-Timer-Baustein
Der Watchdog-Timer (Wachhund) ist ein interner Zähler, der an einem bestimmten Punkt im Programm auf das maximale Zeitintervall zurückgesetzt wird um das
Programm komplett durchlaufen zu können. Wenn jetzt das Programm einen Fehler hat (z. B.: nicht vorgesehene Unendlichschleife) und den Watchdog-Timer nicht
mehr zurücksetzen kann, wird der Controller automatisch neu gestartet (Watchdog-Timer-Reset).
2.1.3 Speicherarten und Speicherarchitektur
In einem Mikrocontroller-System gibt es verschiedene Arten von Speichereinheiten. Im Gegensatz zur von-Neumann-Architektur, die einen Arbeitsspeicher für
Programme und Daten gleichzeitig vorsieht, verfügen Mikrocontroller meist über eine Harvard-Architektur. Diese sieht getrennte Speicher für Programmcode und für Daten vor.

Abbildung: getrennter Speicher eines Mikrocontrollers
RAM-Speicher, SRAM-Speicher
RAM-Speicher (Random Access Memory) bzw. SRAM-Speicher (Static Random Access Memory) können vom Prozessor beschrieben, wieder gelesen und gelöscht
werden. Daher sind sie als Datenspeicher in einem Mikrocontroller-System geeignet. Jedoch verlieren die RAM-Bausteine ihren Inhalt, wenn die Betriebsspannung
abgeschaltet wird. RAM Speicher sind sehr schnell.
Register
Das sind Speicherzellen, die direkt mit dem Prozessorkern verbunden sind. Sie sind die Operanden und Ergebnisspeicher für die Maschinenbefehle. Bei Mikrocontrollern
sind die Register oft ein spezieller Bereich im SRAM, dieser wird als Registerfile bezeichnet. Register haben eigene Bezeichner, das können Buchstaben
(A, B, C, AX, BX, CX, ... X, Y, Z) sein oder die Register sind durchnummeriert (R1, R2, R3, R4, R5, ..,).
ROM-Speicher
In die ROM-Bausteine (Read Only Memory) können die gewünschten Speicherinhalte fest eingebrannt werden. War das Programm fehlerhaft, kann man diesen
Baustein jedoch nicht mehr verwenden, da seine Informationen nicht mehr gelöscht werden können.
EPROM-Speicher
In die EPROM-Bausteine (Erasable Programmable Read Only Memory) können die gewünschten Speicherinhalte fest eingebrannt werden. Im Unterschied zu einem
ROM lassen diese sich jedoch mit UV-Licht wieder löschen.
EEPROM-Speicher
Die EEPROM-Speicher (Electrically Erasable Programmable Read Only Memory) beinhalten sowohl Eigenschaften der EPROM- als auch RAM-Bausteine. Sie können
direkt vom Prozessor beliebig beschrieben, gelesen und gelöscht werden. Sie verlieren jedoch nicht ihren Inhalt, wenn die Betriebsspannung ausgeschaltet wird.
Deshalb sind sie besonders gut zur Ablage von Daten des Mikrocontroller-Systems geeignet, die bei Störung der Betriebsspannungsversorgung nicht verloren
gehen dürfen. EEPROM-Speicher sind im Vergleich zu RAM bzw. SRAM Speichern langsam.
FLASH-Speicher
FLASH-Bausteine sind besonders schnelle EEPROMs und stehen für blitzschnelle Umprogrammierung. Unterschiede gegenüber herkömmlichen EEPROMs sind
zum Beispiel, dass das Speichern im FLASH nur blockweise und nicht byteweise erfolgen kann und dass die Lebensdauer mit 1.000 bis 10.000 Schreibzyklen geringer
sein kann als bei EEPROMs, die heute 100.000 Schreibzyklen garantieren können. Mit diesem Speicher ist es möglich, den Controller im Zielsystem zu programmieren.
Dafür stehen spezielle, meist serielle, Schnittstellen zur Verfügung.
2.1.4 Prozessoren
CISC-Prozessoren
Ein CISC-Prozessor (Complex Instruction Set Computer) verfügt über einen großen,komplexen Satz an Befehlen. Jeder Befehl ist ein eigenes Mikroprogramm,
das eine Reihe von Aktionen auslöst. Dadurch wird die Programmierung komfortabler. Der größte Nachteil ist, dass die CISC-Prozessoren in der Regel vier bis
zehn Takte benötigen, bis ein Befehl komplett ausgeführt ist.
RISC-Prozessoren
Ende der siebziger Jahre stellten die US-Universitäten Berkeley und Stanford fest, dass in rund 80 Prozent aller Anwendungen lediglich 20 Prozent der möglichen
Befehle verwendet werden. Dabei ist auffällig, dass die einfachsten Befehle am häufigsten verwendet werden. Aus dieser Erkenntnis heraus wurden Prozessoren
gebaut, die einen eingeschränkten Befehlssatz haben. Dadurch waren die Prozessoren in der Lage, relativ schnell zu arbeiten. Man bezeichnet diese Prozessoren
als RISC-Prozessoren (Reduced Instruction Set Computer).
Diese erzielen vor allem dann beachtliche Leistungen bei den Anwendungen, wenn für die Rechnerarchitektur optimierte Übersetzer (Compiler) vorliegen. Ein
optimierender Compiler versucht in mehreren Phasen den Maschinencode so umzustellen, dass seine Ausführungen auf der Architektur möglichst schnell erfolgen
können.
Durch den geringeren Befehlssatz der RISC-Prozessoren ist auch ihre Herstellung einfacher und günstiger als bei CISC-Prozessoren. Diese Punkte führen
dazu, dass alle Befehle eines Programms in einem einzigen Maschinenzyklus abgearbeitet werden können. Heutzutage gibt es kaum mehr Prozessoren, die keine
RISC-Elemente beinhalten.

Abbildung: Zeitverhalten versch. Mikrokontrollertypen
2.1.5 Signale am AVR
Digitale Signale am AVR
Die digitalen Signale (0/1), welche durch den AVR-Mikrocontroller als Eingabe oder Ausgabe verarbeitet werden können, sind Spannungen zwischen 0 V (Masse,
Low, logische 0) und typisch 5 V (Versorgungsspannung, High, logische 1).
Die logische 1 (High) entspricht immer der Versorgungsspannung. Je nach Controllertyp können Spannungen zwischen 2,3 V und 6 V als Betriebsspannung dienen.
Die CMOS Eingänge und Ausgänge des AVR sind TTL kompatibel. Eine einzelne Ausgabeleitung kann je nach Controllertyp mit 3 mA bis 10 mA high-aktiv
belastet werden und mit bis zu 20 mA low-aktiv.

Abbildung: Pegel 5V Logik
Analoge Signale am AVR
Die analogen Signale, die durch den Comparator und Analog/Digital-Wandler des AVR verarbeitet werden können, sind beliebige Spannungen zwischen 0 V und
der Betriebsspannung (typisch 5 V) des Controllers.
2.2 Experimentierhardware myAVR Board
AVR RISC-Mikrocontroller
Die kleinen und preiswerten AVR-Prozessoren gehören zu den derzeit modernsten Universal-Mikrocontrollern. Das Design wurde an der Universität für Technologie
in Trondheim/Norwegen entwickelt und von der Firma Atmel erworben. Der AVR-Kern ist außergewöhnlich klein und enthält nur rund 4000 Gates. Atmel bietet
zwei AVR-Serien an: tinyAVR (tiny=winzig) und megaAVR. Die Serie AVR (AT90x) ist auf die Tiny- und Mega-Serie aufgeteilt. Die Produktion der AT90x-Baureihe
läuft nach und nach aus.
AVR Prozessoren sind hervorragend geeignet für Schaltungen, die früher auf Prozessoren wie dem Motorola 6805, dem Intel 8051, MSP 430 oder dem PIC von
Microchip beruhten. Der AVR ist ein RISC-Prozessor. Die verschiedenen Serien unterscheiden sich in der Grundarchitektur sowie Art und Weise der Programmierung
nicht. Die Unterschiede liegen insbesondere in der Ausstattung mit Peripherie und Speicher.
Das myAVR Board verwendet Controller der Mega-Serie im 28 PIN DIP-Gehäuse.

Abbildung: AVM-Mikrokontroller der Tiny-Serie

Abbildung: AVM-Mikrokontroller der Mega-Serie
Beschreibung der Experimentier-Hardware
Alle folgenden Kapitel werden Beispiele und Übungsaufgaben enthalten, die mit der Entwicklungsumgebung SiSy AVR bzw. myAVR Workpad und dem myAVR
Board nachvollziehbar sind. Das myAVR Board verfügt über einen RISC AVRMikrocontroller (ATmega8) der Firma ATMEL. Auf dem
Board befindet sich ein USB Interface.

Abbildung: Das myAVM-Board
Der auf dem Board vorgesehene Controller gehört zur Reihe megaAVR und verfügt bereits über alle wesentlichen Baugruppen. Der weitere Umfang an Ausstattung
der noch "größeren" AVR ist zumeist auf die Speichergröße und die Anzahl der 1/0-Ports bezogen.

Abbildung: Aufbau des AVR ATmega8 von Amtel
3. Programmierung von Mikrocontrollern
3.1 Programmiersprachen, Programmiergeräte, Schnittstellen
Für die Programmierung von Mikrocontrollern stehen unterschiedliche Entwick- lungsumgebungen für verschiedene
Sprachen zur Verfügung. Diese weisen eine Reihe gemeinsamer Merkmale auf. Der wichtigste Aspekt, der hier angesprochen
werden muss, ist, dass im Gegensatz zur Programmierung eines PC-Programms das fertige Programm
nicht auf der Entwicklungsplattform, also unserem PC-Arbeitsplatz gestartet, ausgeführt und getestet werden kann.
Für das Ausführen der entwickelten Controllersoftware ist es notwendig, das ausführbare Programm in geeigneter Weise
auf den Controller und diesen in das Zielsystem zu bringen.
Neben dem üblichen Übersetzungslauf des Quellcodes ist ein weiterer Arbeitsschritt notwendig. Dabei wird das übersetzte
Controllerprogramm in den Programmspeicher (FLASH) des Mikrocontrollers übertragen. Dieser Vorgang
wird "Programmieren" oder "Brennen" genannt und erfordert eine spezielle Schnittstelle für das Programmieren des Controllers.
Diese zusätzliche Hardware wird "Programmer" genannt.
Eine Ausnahme bilden Simulatoren der Zielhardware. Bei diesen ist es möglich, ohne den Brennvorgang, das fertige Programm auf den PC zu testen.
|
 |
Die am weitesten verbreiteten Sprachen für die Programmierung von AVR-Mikrocontrollern sind:
- Assembler
- C/C++
- BASIC (BASCOM)
Eine Entwicklungsumgebung enthält typischerweise folgende Komponenten:
- Quellcode-Editor
- Übersetzungsprogramm (Assembler, Compiler)
- Programmier- /Brenn-Programm
- Testwerkzeuge (Terminal, Simulator, Debugger)
Folgende Dateitypen finden Verwendung bei der Programmierung von Mikrocontrollern:
*.ASM, *.S, *.C, *.CC, *.BAS
Quellcode, wird im Editor erstellt und übersetzt (Compiler, Assembler) zu ...
*.0, *.OBJ
Objektdateien, entstehen beim Übersetzen, werden zu ausführbaren Dateien gebunden (Linker) ...
*.HEX, *.BIN
Binärdatein, entstehen beim Linken, werden beim Brennen in den Programmspeicher des Controllers übertragen.
Die folgenden Abbildung zeigt die allgemeine Grundstruktur eines Mikrocontrollerprogramms in Assembler:

Abbildung: AVR Assemlerprogramm
Für das Brennen des fertigen Mikrocontrollerprogramms (*.HEX oder *.BIN) gibt es grundsätzlich zwei Möglichkeiten:
Zum einen kann man ein Programmiergerät verwenden, in das man den Chip einsetzt und programmiert. Dazu muss das Programmiergerät zum Beispiel
über die serielle Schnittstelle oder USB an den PC angeschlossen werden.
Der Mikrocontroller ist aus dem Zielsystem zu entfernen und auf den entsprechenden
Sockel des Programmiergerätes zu stecken. Dann kann das Programm in den FLASH-Speicher des Controllers übertragen werden. War dieser Vorgang
erfolgreich, kann der Controller aus dem Programmiergerät entnommen und wieder in das Zielsystem eingebaut werden.
Ein häufig verwendetes Programmiergerät ist das STK500 von Atmel.
Abbildung: Programmiergerät STK500 von Amtel
Eine elegante Lösung für die Programmierung des Mikrocontrollers ist das sogenannte "In System Programming" (ISP). Dabei muss der Controller nicht aus
dem Zielsystem ausgebaut werden, sondern kann direkt im System programmiert werden. Dafür muss das Zielsystem eine ISP-Schnittstelle bereitstellen.
Mit einer recht einfachen Hardware, dem sogenannten ISP-Programmer, der an den LPT-Port, die COM-Schnittstelle oder den USB-Port angeschlossen
wird, kann aus der Entwicklungsumgebung heraus das Programm direkt in das Zielsystem übertragen werden. Mögliche Schnittstellen für diese Art der Programmierung
sind ISP, JTAG und I2C.
Abbildung: ISP-Anschlüsse, ISP Standards Amtel 10 pol., Amtel 6 pol., TwinAVR
Dieser ISP-Anschluss am Zielgerät muss an den pe des Entwicklers oder Servicetechnikers mit einem der besagten ISP-Programmer angeschlossen werden. Im
Folgenden sehen Sie Beispiele für die Schaltung unterschiedlicher Programmer. Auf dem myAVR Board ist ein SP12 kompatibler Programmer voll integriert (USB).
3.2 Mikrocontroller-Entwicklungsumgebung SiSy AVR
Schauen wir uns als nächstes kurz in der Entwicklungsumgebung SiSy AVR um.
SiSy AVR ist ein allgemeines Entwicklungswerkzeug, mit dem man von der Konzeption eines Systems, bis zur Realisierung die verschiedensten Arbeitsschritte
unterstützen kann. Für die Entwicklung von Mikrocontrollerlösungen bietet sich die einfache Programmierung an.
Abbildung: Bildschirmaufbau SiSy AVR
Beim Kompilieren, Linken und Brennen des Schnellstart-Beispiels öffnete sich ein Ausgabefenster und zeigte Protokollausgaben der Aktionen an. Wenn die Hardware
ordnungsgemäß angeschlossen, von der Software erkannt und das Programm erfolgreich auf den Programmspeicher des Mikrocontrollers übertragen
wurde, muss die letzte Ausschrift folgenden Inhalt haben:
Abbildung: Ausgabefenster mit Brennprotokoll
3.3 Schnellstart mit SiSy AVR (Systemtest)
Voraussetzungen:
Für die Bearbeitung der folgenden Aufgaben benötigen Sie die aufgeführte Software und Hardware.
Software:
• SiSy AVR ab Version 2.17
Hardware:
• Ein bestücktes myAVR Board
• USB-Kabel A-B
• 9 V Batterie / 9 V Netzteil bei Bedarf (z. B.: autonomer Einsatz)
Zielstellung:
Der Schnelleinstieg zur Mikrocontroller-Programmierung soll Ihnen helfen, das Add-On AVR kennen zu lernen und erste Schritte in der hardwarenahen Programmierung
mit SiSy AVR zu gehen. Die Funktion des nachfolgenden Programms ist es, bei Programmstart alle optischen Ausgabegeräte (LED) auf dem
myAVR Board zum Leuchten zu bringen.
Ein neues Projekt anlegen
- Starten Sie SiSy AVR und wählen Sie Assistent öffnen.
- wählen Sie den Menüpunkt Neues Projekt anlegen
- vergeben Sie den Projektnamen "Alle_lichter_an" und bestätigen Sie mit OK.
- wählen Sie das Vorgehensmodell "Programmierung" und laden Sie keine Diagrammvorlage.
 |
Erstellen Sie ein Programm für den AVR Mikrocontroller, in dem Sie per
Drag & Drop aus der Objektbibliothek ein "kleines Programm" in das Diagrammfenster
ziehen. In dem aufgeblendeten Dialogfenster vergeben Sie
den Namen "Alle_lichter_an". Der Datei- und Programmname wird dabei
automatisch vergeben. Wählen Sie die Sprache "AVR Assembler".
Über die Registerkarte "Programmgerüst" können Sie die Vorlage "Grundgerüst"
für ein AVR Assemblerprogramm laden.
|

Abbildung: Grundgerüst für AVR-Assemblerprogramm
Quelleode in Assembler erstellen
Die Ausgabegeräte LED sollen vom Prozessorport D gesteuert werden. Die Realisierung erfolgt über Bits im Register R16.
Geben Sie folgenden Quelleode ein bzw. ergänzen Sie die Programmvorlage.

Abbildung: Quelltextänderungen
Übersetzen und binden
Der eingegebene Quellcode muss nun in Maschinencode für den AVR-Prozessor übersetzt werden.
Wählen Sie dazu die Schaltflächen "Compilieren" und "Linken".
Bei fehlerfreier Übersetzung liegt das Programm als "Alle_Lichter_An.hex" vor und kann auf den FLASH-Programmspeicher des Prozessors gebrannt werden.
Hardware anschließen und brennen
Das myAVR Board verfügt über eine ISP (In System Programming) Schnittstelle. Der Prozessor muss also nicht für die Programmierung aus dem System entfernt
werden, um ihn in einem gesonderten Programmiergerät zu brennen, sondern kann im myAVR Board direkt programmiert werden. Dazu schließen Sie das Programmierkabel
an den USB-Port Ihres Rechners an.
Zum Brennen wählen Sie die Schaltfläche "Brennen". Bei erfolgreichem Brennvorgang erhalten Sie im Ausgabefenster folgende Meldung:
Abbildung: Brennprotokoll
Mikrocontrollerlösung testen
Um das Programm zu testen ist es nötig, den Port D mit den Ausgabegeräten LED
- Wenn vorhanden, ziehen Sie die Batterie bzw. das Netzteil und das Programmierkabel ab.
- Verbinden Sie die LEDs mit dem Prozessorport D ent- sprechend dem folgenden Schema.
- Nutzen Sie die Patchkabel!
- Prüfen Sie die Verbindungen und schließen Sie die Batterie an und nehmen Sie die Mikrocontrollerlösung in Betrieb.
- Es sind jetzt alle LEDs an.
- Gratulation! Das ist Ihre erste Mikrocontrollerlösung mit dem myAVR Board.
|
 |
4. Mikrorechnerprogrammierung in Assembler
4.1 Einführung in den AVR Assembler
Was ist ein Assembler?
Letztlich ist es egal, welche Programmiersprache man verwendet. Ein Mikroprozessor oder auch Mikrocontroller verarbeitet intern immer Maschinenbefehle im
Binärformat. Ein solcher Maschinenbefehl ist zum Beispiel:
1001 0101 00001000
Dieses Zahlenformat ist recht schwer lesbar. Dafür steht dem hardwarenahen Programmierer eine etwas freundlichere Darstellung zur Verfügung, welche je ein
Halbbyte als ein Zeichen darstellt. Ein Halbbyte umfasst 4 Bit und kann somit 16 verschieden Werte (0 ...15) enthalten. Diese werden mit den Zahlen 0-9 und den
Buchstaben A-F kodiert. Befehle in Hexadezimaldarstellung sind schon besser vom Programmierer zu erkennen.
Der Hexdump Ox9508 wird vom erfahrenen
AVR-Programmierer recht schnell als der Rücksprungbefehl aus einem Unterprogramm identifiziert, da dieser häufig verwendet wird.
Trotzdem sind die ca. 130
Maschinenbefehle eines AVR-Mikrocontrollers als Hexcodes immer noch schwer auswendig zu lernen. Dafür wurde eine besser lesbare Darstellungsform für jeden
Maschinenbefehl entwickelt, die aus einer Abkürzung auf die Bedeutung des Befehls schließen lässt. So wird der Rücksprungbefehl mit dem Kürzel RET dargestellt
und entspricht dem binären Maschinenbefehl 1001 0101 0000 1000.
Die Schreibweise, in der genau ein Maschinenbefehl mit genau einer symbolischen
Darstellung abgebildet wird, nennt man Mnemonik.
Es handelt sich dabei nicht um eine Programmiersprache im eigentlichen Sinne bei der die Sprachelemente nach
einer vorgegebenen Syntax (Grammatik) in beliebigen Kombinationen verwendet werden können, welche dann von einem Compiler aufgelöst werden.
Das Übersetzungsprogramm
für diese Maschinenprogramme ist ein Assembler. Dieser setzt lediglich einen bekannten Maschinenbefehl nach dem anderen in das entsprechende
Binärformat um und berechnet die konkreten Adressen für Sprungbefehle und Speicherzugriffe.
Ein Assemblerprogramm wird mit einem Texteditor geschrieben und muss in einfachem ASCII-Format vorliegen. In der Regel wird der Quellcode in mehreren
Spalten organisiert. Das dient der Übersichtlichkeit, ist aber nicht zwingend notwendig. Die Spalten werden einfach durch das Einfügen von Tabulatoren oder eine
Folge von Leerzeichen erzeugt (white space).
Die erste Spalte enthält Bezeichner für Adressen, die zum Beispiel bei Sprunganweisungen genutzt werden. Man bezeichnet diese als Marken, Sprungmarken
oder auch Label. Eine Marke sollte ab Spalte 1 geschrieben werden und muss immer mit einem Buchstaben beginnen und einem Doppelpunkt enden.
Vergleichen Sie dazu im folgenden Quellcode die Marke mainloop:.
Die zweite Spalte enthält die Maschinenbefehle, gefolgt von den Operanden. Die Operanden können in einer eigenen Spalte stehen und stehen immer in
der Reihenfolge Ziel, Quelle der Operation. Das heißt also, dass immer dann, wenn die Operation ein Ergebnis liefert, dieses im ersten Operanden vorliegt.
Der Transportbefehl ldi (load immediately) ist eine Wertzuweisung einer Konstante an ein Register. Vergleichen Sie den Befehl ldi r16 , 128 im
folgenden Quelltext. Dieser entspricht der Wertzuweisung r16=128.
Kommentare haben ein vorangestellten Semikolon gekennzeichnet
und enden immer am Zeilenende.

Im AVR-Assembler können Zahlen in verschiedenen Formaten dargestellt werden. Dezimalzahlen werden ohne weitere Kennzeichnung geschrieben. Binär und Hexadezimalzahlen
erhalten einen entsprechenden Präfix Ob oder Ox.
Beachten Sie, dass die führende Null nicht zum Wert gerechnet wird, sondern zum Präfix gehört !

In anderen Systemen werden Hexadezimalzahlen oft mit einem $-Zeichen gekennzeichnet.
In manchen Darstellungen findet sich diese Schreibweise auch in diesem Buch. Dabei handelt es sich meist um Abbildungen aus den Datenblättern von Atmel.
Was ist ein Register?
Register sind besondere Speicherzellen, in unserem Fall mit je 8 Bit. Man kann in einem solchen 8-Bit-Register Zahlen von 0 bis 255 (Ganzzahl ohne Vorzeichen),
von -128 bis +127 (Ganzzahl mit Vorzeichen-Bit 7), ein Acht-Bit-ASCII-Zeichen wie z. B. 'A' oder auch acht einzelne Bits speichern. Das Besondere an diesen Registern
(im Gegensatz zu anderen Speichern) ist, dass nur diese direkt in Maschinenbefehlen angesprochen werden können. Sie sind direkt an das Rechenwerk
angeschlossen und können sowohl Quelle von Daten, als auch Ziel des Ergebnisses von Operationen sein. Register sind die schnellsten Speicherplätze, die dem
Programmierer zur Verfügung stehen.
Die Register stellen also die Variablen dar, mit denen ein Assemblerprogramm in
erster Instanz arbeitet. Ein AVR-Mikrocontroller besitzt 32 allgemeine Register. Sie werden mit R0 bis R31 bezeichnet. Beachten Sie, dass nicht alle Register uneingeschränkt
verwendet werden können. Nur die Register R16 bis R31 lassen sich zum Beispiel mit einem konstanten Wert direkt laden, die Register RO bis R15
nicht.
Diese Register benutzt man für spezielle Aufgaben. Als allgemeine Arbeitsregister (Variablen) dienen die Register R16 bis R31.
Zeiger-Register
Eine wichtige Sonderrolle spielen die Registerpaare R26+R27, R28+R29 und R30+R31. Diese werden zu den 16-Bit-Adressregistern X, Y und Z zusammengefasst.
Sie werden bei Adressierungen für den internen SRAM benötigt.
Was ist ein Port?
Port ist die allgemeine Bezeichnung für Eingabe- und Ausgabegeräte, speziell sind damit die digitalen Ein- und Ausgänge gemeint. Aber auch die Steuerregister
für die unterschiedlichsten Aufgaben sind bei AVR-Mikrocontrollern als I/O-Ports realisiert und werden somit auch wie diese angesprochen. Im Umkehrschluss sind
die Ein- und Ausgänge beim AVR als Register realisiert. Daraus ergibt sich eine einheitliche Programmierung aller Steueraufgaben intern und extern.
Ports haben eine feste Adresse, über die sie angesprochen werden können. Die Adressen sind für alle AVR-Typen einheitlich festgelegt. So befindet sich der Ausgabeport
der Parallelschnittstelle B bei allen Prozessoren der AVR-Familie an der Portadresse Ox18.
Ports werden üblicherweise über Alias-Namen angesprochen. Diese sind in der Datei "avr.h" festgelegt. Die I/O-Adresse Ox18 besitzt demzufolge den Alias-
Namen PORTB. Der Bezeichner PORTB wird in den Befehlen wie die entsprechende Adresse gehandhabt.
Die folgende Liste zeigt eine Auswahl der I/O-Register:
Statusregister / Flagregister |
SREG |
Ox3F |
Stackpointer |
SP |
Ox3D |
General Control Register |
MCUCR |
Ox34 |
General Interrupt Control Register |
GICR(GIMSK) |
Ox3B |
Generallnterrupt Flag Register |
GIFR |
Ox3A |
Timer Interrupt Mask Register |
TIMSK |
Ox39 |
Timer Interrupt Flag Register |
TIFR |
Ox38 |
Timer / Counter 0 Control Register |
TCCRO |
Ox33 |
Timer / Counter 0 |
TCNTO |
Ox32 |
Watchdog-Timer Control Register |
WDTCR |
Ox21 |
Port B |
PORTB |
Ox18 |
Data Direction Register Port B |
DDRB |
Ox17 |
Input Register Port B |
PINB |
Ox16 |
UART Data Register |
UDR |
OxOC |
UART Status Register |
USR |
OxOB |
UART7 Control Register |
UCR |
OxOA |
UART Baud Rate Register |
UBRR |
Ox09 |
Analog Comparator Control |
ACSR |
Ox08 |
4.2 Grundaufbau eines AVR-Assembler Programms
Aus dem bisher Besprochenen ergibt sich zum AVR-Mikrocontroller folgendes Bild:
Auf einem Chip sind neben dem Prozessor auch alle notwendigen Peripheriebausteine integriert. Der Speicher, der dem AVR-Mikrocontroller zur Verfügung steht,
ist in der folgenden Abbildung dargestellt.
Beachte: Je nach Controllertyp können sich die Registerbezeichnungen unterscheiden.
Zum Beispiel ist das Steueregister General Interrupt Control Register GICR des ATmega8 gleichbedeutend mit dem General Interrupt Mask Register
GIMSK des ATtiny2313. Wenn hier Register besprochen werden, die in unterschiedlichen Controllern nicht gleich bezeichnet sind, steht die alternative
Bezeichnung in Klammern dahinter.
 Abbildung: Speicher des AVR - Mikrocontrollers
Die Programme werden im AVR immer im FLASH-Speicher ab Adresse OxOOOO abgelegt. Diese Adresse wird automatisch beim Start (POWER ON) oder beim
RESET des Controllers angesprungen. Es ist also die Startadresse für jedes AVRProgramm, egal in welcher Sprache es geschrieben wird.
Nach dem Start soll ein Controller, entsprechend seiner Aufgabe, Initialisierungsaufgaben durchführen und dann solange, bis er abgeschaltet wird, die
Eingabegeräte überwachen (Eingabe), Ereignisse und Daten auswerten (Verarbeitung) und entsprechend reagieren bzw. agieren (Ausgabe). Wir halten also fest,
dass beim Start oder Neustart (RESET) des Controllers, die Abarbeitung ab der Startadresse OxOOOO beginnt und nach einer Initalisierung des Systems in einer
Unendlichschleife die Hauptaufgabe (Eingabe -> Verarbeitung -> Ausgabe) des Controllers ausgeführt wird. Damit ist die Grundstruktur einer Mikrocontrolleranwendung umrissen.

Für die effektive Arbeit des Controllers stehen Möglichkeiten zur Verfügung, schnell auf bestimmte Ereignisse zu reagieren. Dafür sind, je nach Controllertyp,
eine unterschiedliche Anzahl von programmierbaren Interruptquellen verfügbar.
Diese sind in der Lage, auf Ereignisse außerhalb oder innerhalb des Mikrocontrollers in der Form zu reagieren, dass die laufende Programmabarbeitung automatisch
kurz unterbrochen wird, um spezielle Unterprogramme zur Ereignisauswertung aufzurufen und danach die aktuelle Verarbeitung fortzusetzen. Dieser Mechanismus
wird Interrupt oder auch Unterbrechungsanforderung genannt. Für jedes auszuwertende Ereignis werden eine Einsprungadresse (Vektor) und eine
Serviceroutine programmiert. Daraus ergibt sich folgendes typisches Bild im Programmspeicher.

Der Aufbau aller AVR-Mikrocontrollerprogramme ist letztlich immer gleich. Daraus lässt sich die folgende Grundstruktur eines AVR-Assemblerprogramms ableiten:
Der Programmkopf
Dieser dient der Dokumentation. Besonders wichtig ist die Beschreibung der Funktion
und der Schaltung. Jedes Mikrocontrollerprogramm macht nur im Zusammenhang mit der dafür vorgesehenen Schaltung des Controllers Sinn.

Einsprungpunkt und Interruptvektoren
Die sogenannte Interruptvektortabelle ist ein Element, welches in allen interruptfähigen Systemen realisiert werden muss (auch im PC). Bei AVR-Mikrocontrollern
ist diese Tabelle fest ab Adresse OxOOOO mit einer vorgegebenen Größe (abhängig vom Controllertyp) vorgesehen. Jede Position in dieser Tabelle ist ein
fester Ansprungpunkt des Controllers für ein bestimmtes Ereignis. Die erste Adresse ist zum Beispiel der Vektor für das Ereignis POWER-ON-RESET.
Die Interruptvektortabelle muss immer vollständig realisiert sein. Nicht belegte Interrupts sind mit dem Maschinenbefehl RETI (return from interrupt) zu versehen.
Das bewirkt, dass selbst wenn ein nicht vorgesehener Interrupt ausgelöst wurde, das System dann ordnungsgemäß nichts tut, denn jeder Interrupt muss immer mit
RETI beendet werden, damit die normale Programmabarbeitung fortgesetzt wird.
Vergleichen Sie dazu die folgende Darstellung. Nur der erste Vektor ist belegt und führt einen Sprung zum Hauptprogramm aus. Die anderen Vektoren sind als
Platzhalter notwendig. In Hochsprachen wie C/C++ oder BASIC wird die Interruptvektortabelle vom Compiler automatisch generiert.

Initialisierungssequenz
Nach dem Einschalten oder dem Neustart (RESET) des Systems sind immer die entsprechenden Initialisierungsschritte für die konkrete Lösung auszuführen. Bis
auf wenige AVR-Controller der Tiny-Serie, die über keinen SRAM verfügen, ist die minimale Initialisierungsaufgabe, den Stack (Stapelspeicher) zu initialisieren. Der
Stack wird vom Prozessorkern benötigt, um die Rücksprungadressen für Unterprogramme und Interruptroutinen zu speichern, sowie Registerinhalte zwischen zu
speichern.
Der Stack arbeitet nach dem UFO-Prinzip (last in first out). Das Register SP (Ox3D) ist der Stackpointer und zeigt auf die letzte (aktuelle) Adresse im Stapelspeicher.
Wird ein Wert auf den Stack gelegt (z. B.: Befehle call f push), verringert sich der Stackpointer entsprechend. Wird ein Wert vom Stack abgeholt (z.
B.: Befehle ret f pop), wird die Adresse im Stackpointer erhöht. Der Stack wächst also bildlich gesprochen rückwärts bzw. von oben nach unten. Deshalb
liegt die Startadresse des Stack nicht am Beginn des SRAM, sondern an dessen Ende. Der Stapelspeicher wächst dann sozusagen vom Ende des SRAM in Richtung
Anfang des SRAM. Das Ende des SRAM ist die Adresse des letzen Bytes und abhängig vom Controllertyp. Beim ATmega8 ist es zum Beispiel die 1024
(1 kByte SRAM), beim ATtiny26 die 128 (128 Byte SRAM). Für diese Werte ist ein Alias-Name definiert: RAMEND.

Hauptschleife (das Betriebssystem)
Die Verarbeitungs- bzw. Steueraufgabe soll vom Mikrocontroller solange ausgeführt werden, bis er abgeschaltet wird. Das geschieht durch wiederholtes Durchlaufen
der vorgegebenen Verarbeitungsschritte. Verallgemeinert bestehen die Verarbeitungsschritte aus drei Elementen: Eingabe, Verarbeitung, Ausgabe. Da es
nicht wirklich eine Endbedingung für diesen Zyklus gibt, wird diese Hauptschleife (rnainloop) ohne Abbruchbedingung formuliert.

Unterprogramme und Interruptserviceroutinen
Für die Wahrung der Übersichtlichkeit und für Aufgaben, die mehrfach benötigt werden, wie zum Beispiel eine Warteroutine, benutzt man die Unterprogrammtechnik.
Interruptroutinen sind ebenfalls Unterprogramme. Diese werden in unserem Fall am Ende angefügt.

|