Inhalte der Vorlesung Mikrocomputertechnik - Elektrotechnik

Inhalte der Vorlesung Mikrocomputertechnik - Elektrotechnik Inhalte der Vorlesung Mikrocomputertechnik - Elektrotechnik

elektrotechnik.fh.gelsenkirchen.de
von elektrotechnik.fh.gelsenkirchen.de Mehr von diesem Publisher
18.11.2012 Aufrufe

Inhalte der Vorlesung Mikrocomputertechnik Prof. Dr. R. Arnold ausgegeben am 12.4.2007 3 Mikrocontroller der AVR-Serie von Atmel In diesem Abschnitt wird speziell auf die noch recht junge und inzwischen weit verbreitete AVR-Controllerfamilie von der Firma Atmel eingegangen. An diesem Controller soll exemplarisch die Benutzung und die Programmierung von Mikrocontrollern geübt werden. In manchen Fällen werden Bezüge zu anderen Controllerfamilien hergestellt. Konkrete Angaben, die Controllerdetails beschreiben beziehen sich, wenn nichts anderes gesagt wird, auf den Controller ATtiny2313 der AVR-Familie. Er ist klein genug, um den Überblick der zu behalten und großgenug, um die erforderlichen Resourcen zur Verfügung zu stellen. In den folgenden Abschnitten beziehe ich mich mehrfach auf das Datenblatt (datasheet) und den Befehlssatz (instruction set) des Controllers. Beides wird von der Firma Atmel im Internet kostenfrei zur Verfügung gestellt und kann unter folgenden Adressen heruntergeladen werden: 1. Datenblatt des ATtiny2313 AVR Mikrocontrollers: 2. Befehlssatz der AVR Controllerfamilie: 3.1 Überblick über Rechenwerk und Befehlssatz 3.1.1 Das Rechenwerk des Controllers Der Controller besitzt eine Harvard Struktur, hat also getrennte Daten- und Programmspeicher. Der Controllerkern besitzt (s.a. Datenblatt Seite 9 bis 13) 1. 3 controllerinterne Register mit genau festgelegten Funktionen, nämlich das Statusregister SREG (8-Bit), den Programmcounter PC (16-Bit) und den Stackpointer SP (16-Bit), 2. 32 GPR-Register zur freien Verwendung (GPR, general purpose register). Einige dieser 32 GPR- Register haben genau de…nierte Sonderfunktionen und 3. ein Rechenwerk (ALU, arithmetic logic unit) mit einer zweistu…gen Pipeline.

<strong>Inhalte</strong> <strong>der</strong> <strong>Vorlesung</strong> <strong>Mikrocomputertechnik</strong><br />

Prof. Dr. R. Arnold<br />

ausgegeben am 12.4.2007<br />

3 Mikrocontroller <strong>der</strong> AVR-Serie von Atmel<br />

In diesem Abschnitt wird speziell auf die noch recht junge und inzwischen weit verbreitete AVR-Controllerfamilie<br />

von <strong>der</strong> Firma Atmel eingegangen. An diesem Controller soll exemplarisch die Benutzung und die Programmierung<br />

von Mikrocontrollern geübt werden. In manchen Fällen werden Bezüge zu an<strong>der</strong>en Controllerfamilien<br />

hergestellt. Konkrete Angaben, die Controllerdetails beschreiben beziehen sich, wenn<br />

nichts an<strong>der</strong>es gesagt wird, auf den Controller ATtiny2313 <strong>der</strong> AVR-Familie. Er ist klein genug, um den<br />

Überblick <strong>der</strong> zu behalten und großgenug, um die erfor<strong>der</strong>lichen Resourcen zur Verfügung zu stellen. In<br />

den folgenden Abschnitten beziehe ich mich mehrfach auf das Datenblatt (datasheet) und den Befehlssatz<br />

(instruction set) des Controllers. Beides wird von <strong>der</strong> Firma Atmel im Internet kostenfrei zur Verfügung<br />

gestellt und kann unter folgenden Adressen heruntergeladen werden:<br />

1. Datenblatt des ATtiny2313 AVR Mikrocontrollers:<br />

2. Befehlssatz <strong>der</strong> AVR Controllerfamilie:<br />

3.1 Überblick über Rechenwerk und Befehlssatz<br />

3.1.1 Das Rechenwerk des Controllers<br />

Der Controller besitzt eine Harvard Struktur, hat also getrennte Daten- und Programmspeicher. Der<br />

Controllerkern besitzt (s.a. Datenblatt Seite 9 bis 13)<br />

1. 3 controllerinterne Register mit genau festgelegten Funktionen, nämlich das Statusregister SREG<br />

(8-Bit), den Programmcounter PC (16-Bit) und den Stackpointer SP (16-Bit),<br />

2. 32 GPR-Register zur freien Verwendung (GPR, general purpose register). Einige dieser 32 GPR-<br />

Register haben genau de…nierte Son<strong>der</strong>funktionen und<br />

3. ein Rechenwerk (ALU, arithmetic logic unit) mit einer zweistu…gen Pipeline.


3.1.2 Der Befehlssatz des Controllers<br />

Es handelt sich um eine optimierten RISC-Befehlssatz (s.a. Datenblatt Seite 217 bis 218 und die<br />

Dokumentation des AVR-Befehlssatzes) mit folgenden Eigenschaften:<br />

1. strenge Trennung zwischen Rechenbefehlen (arithmetic and logic instruction) und Ein-<br />

Ausgagebefehlen (data transfer instruction). Gerechnet kann grundsätzlich nur in den CPUinternen<br />

32 Bit Registern. Externe Speicherinhalte müssen zuerst durch Ladebefehle (load instruction)<br />

in die Register transferiert werden, um diese zu bearbeiten. Nach<strong>der</strong> Bearbeitung<br />

kann das Ergebnis wie<strong>der</strong> durch Speicherbefehle (store instruction) von den Registern in die<br />

externen Speicher zurückgeschrieben werden.<br />

2. vielfältige Sprungbefehle (branch instruction)<br />

3. Befehle für den bitweisen Zugri¤ und zum Testen einzelner Bits (bit and bit-test<br />

instruction)<br />

4. Befehle zur Steuerung <strong>der</strong> CPU (MPU control instruction)<br />

3.1.3 Programmspeicher des Controllers<br />

Wie wir schon wissen, besitzen die Controller <strong>der</strong> AVR-Serie getrennte Programm- und Datenspeicher<br />

(Harvard Architektur). Da das Programm während des Programmablaufs nicht geän<strong>der</strong>t wird, ist <strong>der</strong><br />

Programmspeicher als ROM-Speicher zu betrachten, <strong>der</strong> einmal programmiert wird und dann die programmierten<br />

Befehle abarbeitet. Zudem ist es vorteilhaft, wenn das einmal eingeschriebene Programm<br />

beim Ausfall <strong>der</strong> Betriebsspannung erhalten bleibt (nicht ‡üchtiger Speicher) Deshalb ist <strong>der</strong> Programmspeicher<br />

als EEProm (elektrisch programmierbares EProm) aufgebaut, <strong>der</strong>, einmal programmiert, die


Daten nahezu unbegrenzte Zeit hält. Da sich während des Programmablaufs wie ein ROM-Speicher verhält,<br />

gibt es keine Möglichkeit und damit auch keine Maschinenbefehle, um per Programm, Daten in<br />

den Programmspeicher zu schreiben. Allerdings kann jede einzelne Speicherstelle (16-Bit Zugri¤) des<br />

Programmspeichers durch den Assemblerbefehl LPM (Load Program Memory) ausgelesen werden, so<br />

dass konstante Zahlenwerte und Zeichenketten im Programmspeicher abgelegt werden können.<br />

AVR-Controller werden mit den unterschiedlichste Programmspeichertiefe geliefert. Der Controller, <strong>der</strong><br />

im Praktikum verwendet wird (ATtiny2313) hat eine Programmspeichertiefe von 1024 (wird oft auch als<br />

1kBit bezeichnet) und eine Speicherbreite von 16 Bit. Die niedrigste Adresse und damit <strong>der</strong> Startpunkt<br />

eines jeden Programms beim Einschalten und nach einem Reset ist 0x00 (0 dezimal)und die größte<br />

Adresse ist 0x3FF (1023 dezimal). Die folgende Abbildung zeigt den Aufbau des Programmspeichers:<br />

3.1.4 Der erweiterte Datenspeicher<br />

Unter den Begri¤ des Datenspeichers werden 3 verschiedene Speicherbereiche, nämlich die Register (Bestandteil<br />

<strong>der</strong> CPU), <strong>der</strong> I/O-Bereich und <strong>der</strong> SRAM-Bereich (Datenspeicher im engeren Sinne), zusammengefaßt<br />

und durchgängig, beginnend mit 0x00 bis 0xDF adressiert. Obwohl die Register physikalisch<br />

<strong>der</strong> CPU zugeordnet sind, werden sie in die durchgängige Adressierung des erweiterten Datenspeichers mit<br />

einbezogen, was gewisse Vorteile für den Anwerden bringt aber zunächst etwas undurchsichtig erscheint.<br />

Die Register haben nach dieser Adressierungsweise die Adressen von 0x00 bis 0x1F (32 Speicherplätze)<br />

im erweiterten Datenspeicherbereich. Danach sind im Adressbereich 0x20 bis 0x5F (64 Speicherplätze)<br />

die I/O spezi…schen Register und dann, nämlich im Adressbereich 0x60 bis 0xDF (128 Speicherplätze),<br />

<strong>der</strong> eigentliche interne SRAM-Datenspeicher angeordnet. Situationen wie hier, dass Speicherbereiche<br />

zusammenhängend erscheinen, aber physikalisch nicht zusammenhängend aufgebaut sind, …ndet man bei<br />

Prozessoren und Controllern nicht selten; man bezeichnet dies auch als Memory mapping. Man kann<br />

das sehr gut mit dem Telefonnetz einer Firma vergleichen. Die einzelnen Telefonnummern erscheinen<br />

für jemand, <strong>der</strong> die von außen anruft, geordnet, obwohl benachbarte Telefonnummern nicht unbedingt<br />

benachbarten Zimmern zugeordet sein müssen. Zwischen <strong>der</strong> Reihenfolge <strong>der</strong> Telefonnummer (Nummer<br />

<strong>der</strong> Speicherstelle) und <strong>der</strong> physikalischen Lage des Zimmers (<strong>der</strong> Speicherstelle selbst) muss kein<br />

Zusammanhang bestehen. Durch dieses Beispiel wird verständlich, dass CPU-Register durchaus in den<br />

Adressbereich des Datenspeichers einbezogen werden können, physikalisch dagegen ganz wo an<strong>der</strong>s, nämlich<br />

in <strong>der</strong> CPU, liegen. Für den Programmierer ist es aber duchaus von Vorteil, wenn alle verfügbaren


Speicher und damit auch die CPU-Register in einer einheitlichen konsistenten Weise adressierbar sind.<br />

In <strong>der</strong> folgenden Abbildung ist <strong>der</strong> gesamte erweiterte Datenspeicherbereich mit seinem Adressraum<br />

dargestellt.<br />

Die Adressierung des gesamten Datenspeichers ist linear von 0x00 bis 0xDF. Alle Speicher- und Ladebefehle<br />

(ST-, LD- Befehle) benutzen diese durchgängige Adressierung des Datenspeichers. Die I/O Befehle<br />

IN und OUT dagegen benutzen die in <strong>der</strong>Abbildung angegebene zusätzliche Adressierung des I/O-<br />

Speicherbereichs, die von 0x00 bis 0x3F läuft. Auf den Adressbereich 0x00 bis 0x1F des I/O Speichers<br />

kann durch die bit-adressierbaren Befehle SBI, CBI, SBIS und SBIC zugegri¤en werden.<br />

3.2 Funktion <strong>der</strong> einzelnen Register<br />

In diesem Abschnitt sehen wir uns die einzelnen Register genauer an. Dies ist wichtig, um die Funktion <strong>der</strong><br />

Register und damit des gesamten Controllers besser zu verstehen. Das Verständnis <strong>der</strong> Registerfunktionen<br />

ist zur Programmierung unbedingte Voraussetzung. Zunächst eine gra…sche Übersicht <strong>der</strong> Register.


Wie man sieht sind die Register nicht gleichwertig. Eine Reihe von Befehlen, darunter praktisch alle<br />

unmittelbar (immediate) adressierten, darf nur zusammen mit den Registern r15 bis r31 verwendet werden.<br />

Dies liegt daran, dass für das unmittelbare Argument bereits 8 Bit benötigt werden und deshalb<br />

für die Adressierung des Registers ein Bit gespart wird. Die mit X-, Y-, und Z- bezeichneten Register<br />

werden auch als Indexregister bezeichnet. Sie werden vor allem von den Lade- und Speicherbefehlen<br />

zur indirekten Adressierung benutzt. So nutzt z.B. <strong>der</strong> LPM Befehl das Z-Register, um das Datum im<br />

Programmspeicher zu adressieren, um es in das Register r0 zu laden; so kommt <strong>der</strong> LPM-Befehl ganz<br />

ohne Argumente aus.<br />

3.2.1 Das Program-Counter Register (PC-Register)<br />

Die Befehle eines Controllers werden sequentiell (d.h. einer nach dem an<strong>der</strong>en, fortlaufend, nacheinan<strong>der</strong>)<br />

abgearbeitet. Die Maschine mußdeshalb zu jedem Zeitpunkt wissen, welcher Befehl als nächster<br />

abgearbeitet werden soll. Diese Information steht im PC-Register. Das PC-Register enthält eine Adresse,<br />

die auf den nächsten Maschinenbefehl zeigt, <strong>der</strong> verarbeitet werden soll.


Haben wir ein einfaches Programm, das keinerlei Verzweigungen enthält, so enthält das PC-Register<br />

die physikalisch nächste Adresse des Programmspeichers, d.h. das PC-Register zeigt auf den nächsten<br />

Speicherplatz des Programmspeichers.<br />

Enthält das Programm Verzweigungen in Form von Sprungbefehlen, Unterprogrammaufrufen o<strong>der</strong> Interruptverzweigungen,<br />

so zeigt das PC-Register auf die nächste abzuarbeitende Speicherposition, die nicht<br />

mit <strong>der</strong> physikalisch nächsten Speicherzelle des Programmspeichers übereinstimmen muss. Liegt eine<br />

Programmverzweigung vor, so lassen sich zwei Arten von Verzweigungen unterscheiden.<br />

1. bedingte o<strong>der</strong> unbedingte Sprungbefehle, die die Abarbeitung des Programms in jedem Fall (unbedingt)<br />

o<strong>der</strong> abhängig von einer Bedingung (bedingt) verzweigen. In diesem Fall zeigt das PC-Register<br />

auf den nächsten Befehl nach <strong>der</strong> Verzweigung, d.h. nach dem Sprung. Das Programm läuft dann<br />

einfach nach <strong>der</strong> Verzweigung weiter.<br />

2. Unterprogrammaufrufe (subroutine calls) o<strong>der</strong> Programmunterbrechungen (interrupt calls) unterbrechen<br />

den momentanen Programmablauf, indem sie das Programm vorübergehend in einen an<strong>der</strong>en<br />

Speicherbereich verzweigen, dort ein an<strong>der</strong>es Programm abarbeiten, um dann wie<strong>der</strong> in den<br />

ursprünglichen Speicherbereich zurückzukehren. Um sicherzustellen, dass das PC-Register nach<br />

<strong>der</strong> Rückkehr aus <strong>der</strong> verzweigten Routine die Adresse des nächsten Befehl des ursprünglichen<br />

Programms enthält, muss diese Adresse vorübergehend gespeichert werden.


Durch die Zwischenspeicherung <strong>der</strong> Rücksprungadresse ist sichergestellt, dass das Programm die korrekte<br />

Rücksprungadresse wie<strong>der</strong>…ndet. Als Rücksprungregister wird i.d.R. kein separates Register<br />

verwendet, son<strong>der</strong>n die Rücksprungadresse wird in einem reservierten Bereich des Arbeitsspeichers<br />

abgelegt. Diesen sogenannten STACK-Speicher werden wir noch besprechen. Der STACK-Speicher<br />

hat die angenehme Eigenschaft, dass nicht nur eine Rücksprungadresse zwischengespeichert werden<br />

kann, son<strong>der</strong>n, je nach Größe, beliebig viele. Dies ist wichtig, um innerhalb eines Unterprogramms<br />

weitere verschachtelte Unterprogramme aufrufen zu können.<br />

Durch das eben dargestellte Verfahren ist zwar sichergestellt, dass die korrekte Rücksprungadresse wie<strong>der</strong>gefunden<br />

wird aber es ist noch nicht sichergestellt, dass das Programm nach dem Rücksprung korrekt<br />

abgearbeitet wird. Dies soll an einem folgenden Assembler-Programmbeispiel klar gemacht werden.<br />

abc:<br />

ldi r4, 0x03 ; Lade 3 in Register 4<br />

call abc ; verzweige nach abc<br />

andi r4, 0xff ; UND-Verknuepfung: r4 = r4 AND 0xff<br />

ldi r4, 0x07 ; innerhalb <strong>der</strong> Subroutine wird das Register r4 benutzt!!!<br />

ret ; Ruecksprung<br />

Das vorstehende Programm wird ohne Probleme nach dem Subroutine Call die korrekte Rücksprungadresse<br />

…nden. Aber trotzdem wird es nicht das erwartete Ergebnis liefern, denn wir erwarten nach dem<br />

andi-Befehl r4 = 0x03 aber tatsächlich ist r4 = 0x07. Das liegt daran, dass das Register r4 innerhalb <strong>der</strong><br />

Subroutine verän<strong>der</strong>t wurde.<br />

Bei Subroutine Calls und beson<strong>der</strong>s bei Interrupt Calls mußvermieden werden, dass Registervariablen<br />

nicht unbeabsichtigt verän<strong>der</strong>t werden. Dies geschieht i.d.R. dadurch, dass die entsprechenden Register<br />

während des Subroutine Calls zwischengespeichert und vor dem Rücksprung wie<strong>der</strong> restauriert werden.<br />

Während <strong>der</strong> Controller bei Calls das PC-Register automatisch verwaltet, müssen die Register praktisch<br />

immer vom Assembler-Programmierer selbst verwaltet werden, was oft zu unerwarteten Fehlern führt.<br />

Neben den eben besprochenen Registern ist die Zwischenspeicherung (Rettung!) des Statusregistern von<br />

entscheiden<strong>der</strong> Bedeutung.


3.2.2 Das Statusregister (SREG)<br />

Wozu ein Statusregister? Oft ist es notwendig, zwischen den einzelnen Maschinenbefehlen Information<br />

auszutauschen, indem ein o<strong>der</strong> einige wenige Bit an den nächsten Befehl übergeben werden. Hierzu dient<br />

das Statusregister. Es ist gewissermaßen eine private Zwischenablage <strong>der</strong> CPU für wichtige Informationen<br />

von bereits abgearbeiteten Befehlen an noch bzuarbeitende Befehle. Ein Beispiel soll dies verdeutlichen.<br />

Beispiel: Ein Programm soll verzweigt werden, wenn das Ergebnis des vorhergehenden Maschinenbefehls<br />

gleich Null war.<br />

Diese bedingte Verzweigung ist nur möglich, wenn dem nächsten Maschinenbefehl mitgeteilt wird, ob das<br />

Ergebnis des vorherigen Befehls Null o<strong>der</strong> nicht Null war. Der Vorgängerbefehl muss also die Möglichkeit<br />

haben, dem nachfolgenden Befehl mitzuteilen, ob sein Ergebnis Null war o<strong>der</strong> nicht. Hierzu bedarf es<br />

einer Zwischenspeicherung von Information. In diesem Fall genügt bereits ein einziges Bit, das sogenannte<br />

Z-Flag. Dieses Z-Flag benötigt einen geeigneten Speicherplatz. Zusammen mit an<strong>der</strong>en Flags wird es im<br />

Statusregister gespeichert, so dass nachfolgende Befehle darauf zugreifen können.<br />

Wie das Beispiel zeigt, enthält das Statusregister kleinste Informationsmengen, die an nachfolgende<br />

Maschinenbefehle weitergegeben werden können. Es bedarf keiner weiteren Erläuterung, dass jede Verfälschung<br />

des Statusregisters - z.B. innerhalb einer Subroutine - zu einem fehlerhaften Programmablauf<br />

führt. Deshalb muss sichergestellt werden, dass das Statusregister nicht unbeabsichtigt verän<strong>der</strong>t wird.<br />

Im folgenden ist das AVR-Statusregister dargestellt.<br />

Die genaue Bedeutung <strong>der</strong> einzelnen Status Bit wird in dieser <strong>Vorlesung</strong> bei Bedarf besprochen. Die<br />

genaue Bedeutung kann im Datenblatt des Prozessors, Seite 11, nachgelesen werden. In <strong>der</strong> Befehlsliste<br />

(Instruction Set) <strong>der</strong> AVR-Serie kann für jeden einzelnen Befehl nachgelesen werden wie dieser die einzelnen<br />

Statusbits verän<strong>der</strong>t und damit nachfolgende Befehle beein‡ussen kann.<br />

3.2.3 Das Stackpointer-Register (SP - Register)<br />

Wie wir weiter oben gesehen haben, gibt es beim Ablauf eines Programms organisationsbedingt eine ganze<br />

Menge zwischenzuspeichern. Diese Zwischenspeicherung hat oft nichts mit <strong>der</strong> Funktion des Programmes<br />

zu tun, son<strong>der</strong>n nur damit den korrekten Programmablauf zu gewährleisten. Der STACK-Speicher übernimmt<br />

in <strong>der</strong> Regel vor allem diese Aufgabe. Im STACK werden Rücksprungadressen, Registerinhalte,<br />

das Statusregister usw. bei Bedarf vorübergehend abgelegt und zu einem späteren Zeitpunkt wie<strong>der</strong>


zurückgespeichert. Daneben übernimmt <strong>der</strong> STACK auch die Aufgabe, Variablen- o<strong>der</strong> Adressenwerte<br />

beim Aufruf von Unterprogrammen zu übergeben.<br />

Wie ist ein STACK-Speicher organisiert? Das Wort STACK kommt aus dem englischen und bedeutet<br />

soviel wie Stapel o<strong>der</strong> Haufen und genauso ist ein STACK-Speicher organisiert. Will man z.B. das 11.<br />

Blatt eines Stapels von Blättern lesen, so müssen die oberen 10 Blätter erst einmal entfernt werden. Auf<br />

<strong>der</strong> an<strong>der</strong>en Seite können beliebig viele neue Blätter auf den Stapel gelegt werden. Die Tatsache, dass<br />

das zuletzt hingelegte Blatt zuerst wie<strong>der</strong> weggenommen werden muss, um an die darunterliegenden zu<br />

kommen, gab dem STACK-Speicher auch den Namen Last-in First-out (LiFo-Speicher). Bei Prozessoren<br />

und Controllern werden die Speicher i.d.R. nicht von unten nach oben, son<strong>der</strong>n von oben nach unten<br />

befüllt. Das ist etwa so, als würde <strong>der</strong> Papierstapel an <strong>der</strong> Decke hängen und ein neues Blatt wie von<br />

einem Magneten an <strong>der</strong> Stapelober‡äche festgehalten.<br />

Welche Aufgabe hat nun <strong>der</strong> STACK-Pointer? Der STACK-Pointer (Zeiger) verwaltet den STACK-<br />

Speicher, indem er immer auf das Datum zeigt, das beim nächsten STACK-Speicherzugri¤ zur Verfügung<br />

gestellt wird. Werden neue Daten auf dem STACK abgelegt, so „wächst” <strong>der</strong> STACK nach unten und<br />

vergrößert sich, werden Daten entnommen, so wird <strong>der</strong> STACK kleiner. Die maximale Anzahl von Daten<br />

ist durch die Länge des STACK-Pointers begrenzt. Der ATtiny2313 hat einen 8-Bit STACK-Pointer. Die<br />

Lage des STACK-Pointers in SRAM-Speicherbereich wird noch erläutert.<br />

Der STACK-Poiner muss in einem Programm festgelegt werden, bevor eine Subroutine o<strong>der</strong> ein Interrupt<br />

ausgeführt wird. Es gibt nur wenige Befehle, die den STACK-Pointer unmittelbar bein‡ussen, diese sind:<br />

PUSH, POP, RET, RETI, CALL, RCALL, ICALL. Man kann ein Programm mit sehr großem<br />

Erfolg zum Absturz bringen, wenn man unkontrolliert o<strong>der</strong> mutwillig den STACK-Pointer verän<strong>der</strong>t.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!