29.01.2013 Aufrufe

Assembler-Direktiven - Netzmafia

Assembler-Direktiven - Netzmafia

Assembler-Direktiven - Netzmafia

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

Mikrocomputertechnik


Mikrocomputertechnik<br />

Table of Contents<br />

Mikrocomputertechnik................................................................................................................1<br />

Mikrocomputertechnik..........................................................................................................................1<br />

Inhalt............................................................................................................................................1<br />

1 Einführung.........................................................................................................................1<br />

2 Hardware von Mikrocomputern.........................................................................................1<br />

3 Programmierung des Mikroprozessors 68HC11................................................................1<br />

4 Prozessor des Systems 68HC11.........................................................................................1<br />

5 Peripherie des Systems 68HC11........................................................................................2<br />

6 Ausblick: andere Controller...............................................................................................2<br />

Anhang..................................................................................................................................2<br />

Jack Kilby: der Vater des Mikrochips..................................................................................3<br />

Mikrocomputertechnik..........................................................................................................4<br />

Prolog.......................................................................................................................................................6<br />

1 Einführung...........................................................................................................................................7<br />

1.1 Von-Neumann-Architektur....................................................................................................8<br />

Vorteile der v. Neumann-Architektur:................................................................................11<br />

1.2 Befehlszyklus......................................................................................................................11<br />

Ablauf des Befehlszyklus...................................................................................................13<br />

1.2 Erhöhung der Leistungsfähigkeit........................................................................................14<br />

Vermeiden oder Mildern des v. Neumann-Flaschenhalses.................................................14<br />

1.4 Die Harvard-Architektur.....................................................................................................16<br />

RISC "Reduced Instruction Set Computer"........................................................................16<br />

1.5 Begriffe................................................................................................................................16<br />

Mikrocomputer:..................................................................................................................16<br />

1.6 Entwicklung.........................................................................................................................17<br />

Mikrocomputer als Ersatz festverdrahteter Logik..............................................................18<br />

Einsatzbeispiele:.................................................................................................................19<br />

Mikrocomputer als Universalrechner.................................................................................19<br />

1.7 Embedded Systems..............................................................................................................22<br />

Design von Embedded Systems..........................................................................................22<br />

Mikrocomputertechnik........................................................................................................23<br />

2 Hardware von Mikrocomputern......................................................................................................23<br />

2.1 Struktur eines Mikrocomputers...........................................................................................23<br />

Prinzipieller Aufbau............................................................................................................23<br />

Der System-Bus..................................................................................................................24<br />

Bus-Treiber.........................................................................................................................25<br />

Systembeispiel....................................................................................................................25<br />

2.2 Mikroprozessor....................................................................................................................26<br />

Versorgung und Steuerung.................................................................................................26<br />

Steuerungs-Signale.............................................................................................................28<br />

2.3 Arbeitsspeicher....................................................................................................................28<br />

Speicher-Bausteine.............................................................................................................29<br />

Zusammenschalten von Speicherbausteinen.......................................................................30<br />

2.4 Ein-/Ausgabe-Bausteine......................................................................................................30<br />

Struktur von E/A-Bausteinen..............................................................................................33<br />

Steuerung von E/A-Bausteinen...........................................................................................34<br />

Anschluß von E/A-Bausteinen............................................................................................35<br />

Programmgesteuerter E/A-Transfer (Polling).....................................................................36<br />

i


Mikrocomputertechnik<br />

Table of Contents<br />

2 Hardware von Mikrocomputern<br />

Direktspeicherzugriff (DMA = Direct Memory Access)....................................................37<br />

2.5 Timer (Zeitgeber)................................................................................................................38<br />

2.6 Systemkonfigurationen........................................................................................................38<br />

Aufteilung des Adreßraums................................................................................................39<br />

Systembeispiel....................................................................................................................40<br />

Beispiele zur Systemkonfiguration.....................................................................................42<br />

2.7 Programmunterbrechungen.................................................................................................45<br />

Unterbrechungsgesteuerter E/A-Transfer...........................................................................46<br />

Mikrocomputertechnik........................................................................................................47<br />

3. Programmierung des Mikroprozessors 68HC11...........................................................................47<br />

3.1 Überblick.............................................................................................................................47<br />

Programmiermodell............................................................................................................48<br />

Einteilung der Befehle........................................................................................................49<br />

3.2 Adressierungsarten..............................................................................................................50<br />

Konstanten-Adressierung (Immediate Addressing)............................................................50<br />

Absolute Adressierung........................................................................................................51<br />

Implizite Adressierung (Inherent Addressing)....................................................................51<br />

Indizierte Adressierung (Indexed Addressing)...................................................................52<br />

3.3 <strong>Assembler</strong>-Befehlsaufbau....................................................................................................54<br />

1. Quellcode........................................................................................................................55<br />

3.4 Pseudobefehle (<strong>Assembler</strong>-<strong>Direktiven</strong>)...............................................................................56<br />

Speicher-Organisation.........................................................................................................57<br />

Grundsätzlicher Aufbau eines 68HC11-<strong>Assembler</strong>programms..........................................59<br />

3.5 CPU-Befehle........................................................................................................................59<br />

Transport-Befehle...............................................................................................................61<br />

Arithmetische Befehle........................................................................................................64<br />

Logische Befehle................................................................................................................66<br />

Schiebe- und Rotationsbefehle...........................................................................................68<br />

Test- und Statusregisterbefehle...........................................................................................69<br />

Bitorientierte Befehle..........................................................................................................70<br />

Beeinflussung des Systemzustands.....................................................................................70<br />

Sprungbefehle.....................................................................................................................74<br />

Unterprogrammsprünge (jump/branch to subroutine)........................................................76<br />

Programmunterbrechungsbefehle.......................................................................................76<br />

Reine Verzögerungsbefehle................................................................................................76<br />

3.6 Stapelspeicher (Stack).........................................................................................................77<br />

Befehle für den Stack-Zugriff.............................................................................................77<br />

Anwendung des Stack.........................................................................................................78<br />

3.7 Unterprogramme (Subroutines)...........................................................................................79<br />

Unterprogramm-Sprungbefehle..........................................................................................79<br />

Parameter-Übergabe...........................................................................................................81<br />

3.8 Interrupts (Programmunterbrechungen)..............................................................................82<br />

Interruptsystem des 68HC11:.............................................................................................84<br />

Mikrocomputertechnik........................................................................................................85<br />

4. Bausteine des Systems M68HC11...................................................................................................85<br />

4.1 Mikroprozessor 68HC11.....................................................................................................85<br />

Der Prozessor......................................................................................................................86<br />

Die wichtigsten Anschlußpins............................................................................................87<br />

Reset....................................................................................................................................88<br />

ii


Mikrocomputertechnik<br />

Table of Contents<br />

4. Bausteine des Systems M68HC11<br />

Der Bus...............................................................................................................................88<br />

Der Speicher........................................................................................................................89<br />

Asynchrone serielle Schnittstelle........................................................................................89<br />

Timer-System......................................................................................................................90<br />

Digitale Ein- und Ausgänge................................................................................................91<br />

Impulszähler........................................................................................................................91<br />

Analog-Digital-Wandler.....................................................................................................91<br />

Synchrone serielle Peripherieschnittstelle..........................................................................92<br />

4.2 Typische Anwendungsschaltung.........................................................................................93<br />

Stückliste für das Mikrocontroller-Board...........................................................................94<br />

4.3 Praktikumssystem PS11 mit M68HC11A0.........................................................................94<br />

Blockschaltung....................................................................................................................94<br />

Praktikumsrechner mit Experimetierboard.........................................................................95<br />

Der ZWERG11plus.............................................................................................................96<br />

Anschluß des "Zwerg 11" an den PC..................................................................................96<br />

Belegung des Schnittstellenkabels und des Experimentierboards......................................97<br />

Bootloader Firmware for MC68HC11A8 (essentials)........................................................98<br />

Mikrocomputertechnik........................................................................................................99<br />

5. Peripherie des Systems M68HC11..................................................................................................99<br />

5.1 Peripherie-Register............................................................................................................100<br />

5.2 Parallele Schnittstellen......................................................................................................101<br />

Port A................................................................................................................................102<br />

Port B und STRB..............................................................................................................102<br />

Port C und STRA..............................................................................................................103<br />

Port D................................................................................................................................104<br />

Port E................................................................................................................................104<br />

Programmbeispiele...........................................................................................................107<br />

5.3 Serielle Schnittstellen........................................................................................................107<br />

SCI (serial communication interface asynchronous)........................................................110<br />

SPI (serial peripherial interface synchronous)..................................................................110<br />

Programmbeispiele...........................................................................................................114<br />

5.4 Zähler.................................................................................................................................116<br />

Der Timer..........................................................................................................................126<br />

5.5 Geschützte Register...........................................................................................................127<br />

5.6 Interrupts............................................................................................................................128<br />

Auslösen einer Unterbrechung..........................................................................................137<br />

Mikrocomputertechnik......................................................................................................138<br />

6 Ausblick: andere Controller...........................................................................................................138<br />

6.1 Atmel-Mikrocontroller......................................................................................................138<br />

Beispiel: Blockschaltung des ATTtiny.............................................................................142<br />

6.2 PIC-Microcontroller von Microchip..................................................................................143<br />

Beispiel: Blockschaltung und Pins des PIC16F84............................................................147<br />

6.3 MSP-430-Microcontroller von Texas Instruments............................................................147<br />

Blockschema des MSP430................................................................................................149<br />

6.4 8051-Microcontroller........................................................................................................149<br />

Blockschema des 8051......................................................................................................150<br />

Mikrocomputertechnik......................................................................................................151<br />

iii


Mikrocomputertechnik<br />

Table of Contents<br />

7 Anhang..............................................................................................................................................151<br />

7.1 Literatur und Links............................................................................................................151<br />

Literatur.............................................................................................................................152<br />

68HC11 Links...................................................................................................................153<br />

7.2 Tips zur Programmierung..................................................................................................154<br />

Grundlegende Prinzipien:.................................................................................................154<br />

Programm-Dokumentation...............................................................................................155<br />

7.3 ASCII-Tabelle...................................................................................................................155<br />

ASCII Tabelle (sedezimal)...............................................................................................155<br />

7.4 I/O-Register.......................................................................................................................160<br />

7.5 Interrupt-Adressen.............................................................................................................160<br />

7.6 Das Motorola-S-Format.....................................................................................................161<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate......................................................161<br />

Mikrocomputertechnik......................................................................................................162<br />

Programmbeispiel-Sammlung...........................................................................................................162<br />

Den folgenden "Programmschnipseln" fehlt noch das "Drumrum" (Definitionen von<br />

Variablen, Hauptprogramm, usw.). Sie dienen der Illustration verschiedener<br />

Programmiertechniken in <strong>Assembler</strong>.....................................................................................162<br />

Allgemeiner Vorspann für's Praktikum............................................................................170<br />

Nützliche Unterprogramme..............................................................................................175<br />

Komplette Programmbeispiele..........................................................................................184<br />

Mikrocomputertechnik......................................................................................................185<br />

Praktikum Mikrocomputer...............................................................................................................185<br />

Allgemeines.............................................................................................................................185<br />

Installation der IDE-Software...........................................................................................185<br />

Einschalten und Starten.....................................................................................................186<br />

Programm-Namen und Ordner SAVE..............................................................................186<br />

Beenden und Abschalten...................................................................................................186<br />

Bearbeiten eines Quellprogramms....................................................................................187<br />

Übersetzen eines Quellprogramms (source code).............................................................188<br />

Simulieren eines Zielprogramms (object code)................................................................190<br />

Tools → Load in Target.....................................................................................................190<br />

Arbeiten mit der seriellen Schnittstelle.............................................................................190<br />

Hinweise zur Programmerstellung....................................................................................191<br />

Tools → Terminal..............................................................................................................192<br />

Belegung des Experimentier-Boards................................................................................193<br />

Beschaltung der Eingänge des 68HC11............................................................................195<br />

Anhang: Binär zu ASCII-Decodierung (hx4a).................................................................196<br />

Mikrocomputertechnik......................................................................................................197<br />

Praktikum Mikrocomputer...............................................................................................................197<br />

Versuch 1: Parallel-Ports, Unterprogramme, Zeitverzögerungen...........................................198<br />

Versuch 2: Parallel-Ports, 7-Segmentanzeige, Tabellenzugriff..............................................200<br />

Versuch 3: Serielle Schnittstelle, ASCII-Zeichenketten.........................................................202<br />

Versuch 4: Zähler, bedingte Unterbrechungen........................................................................203<br />

Anhang: Binär zu ASCII-Decodierung (hx4a).................................................................title<br />

iv


Inhalt<br />

1 Einführung<br />

1. Von-Neumann-Architektur<br />

2. Verbesserung der Leistungsfähigkeit<br />

3. Befehlszyklus<br />

4. Harvard-Architektur<br />

5. Begriffe<br />

6. Entwicklung<br />

7. Embedded Systems<br />

2 Hardware von Mikrocomputern<br />

1. Struktur eines Mikrocomputers<br />

2. Mikroprozessor<br />

3. Arbeitsspeicher<br />

4. E/A-Bausteine<br />

5. Timer (Zeitgeber)<br />

6. System-Konfiguration<br />

Mikrocomputertechnik<br />

3 Programmierung des Mikroprozessors 68HC11<br />

1. Überblick<br />

2. Adressierungsarten<br />

3. <strong>Assembler</strong>-Befehlsaufbau<br />

4. Pseudobefehle (<strong>Assembler</strong>-<strong>Direktiven</strong>)<br />

5. CPU-Befehle<br />

6. Stapelspeicher (Stack)<br />

7. Unterprogramme (Subroutines)<br />

8. Interrupts (Programmunterbrechungen)<br />

4 Prozessor des Systems 68HC11<br />

1. Mikroprozessor 68HC11<br />

2. Typische Anwendungsschaltung<br />

3. Praktikumssystem PS11 mit M68HC11A0<br />

5 Peripherie des Systems 68HC11<br />

1. Peripherie-Register<br />

2. Parallele Schnittstellen<br />

3. Serielle Schnittstellen<br />

4. Zähler<br />

5. Geschützte Register<br />

6. Interrupts<br />

Mikrocomputertechnik 1


6 Ausblick: andere Controller<br />

1. Atmel AVR<br />

2. Microchip PIC<br />

3. Texas Instruments MSP430<br />

4. Intel 8051<br />

Anhang<br />

1. Literatur<br />

2. Tips zur Programmierung<br />

3. ASCII-Tabelle<br />

4. I/O-Register<br />

5. Interrupt-Adressen<br />

6. Das Motorola S-Format<br />

7. Programmbeispiel-Sammlung<br />

8. 68HC11 Kurz-Befehlstabelle (PDF, 80 KByte)<br />

9. 68HC11 A8 Reference Manual (PDF, 3,8 MByte)<br />

10. 68HC11 Reference Manual (PDF, 7,6 MByte)<br />

11. What's a Microcontroller? (Parallax Inc., 5,15 MByte)<br />

12. Hinweise zur Software-Sammlung<br />

13. Praktikumsanleitung<br />

14. Versuche 1 bis 4<br />

15. Muster-Prüfungsaufgaben<br />

Skript als PDF (aus HTML konvertiert)<br />

Download des gesamten Skripts<br />

Mikrocomputertechnik<br />

Mein besonderer Dank gilt dem Kollegen Prof. Peter Schwalb, der mir viele seiner Grafiken zur<br />

Verfügung gestellt hat.<br />

Jack Kilby: der Vater des Mikrochips<br />

Jack Kilby baute 1958 den ersten integrierten Schaltkreis<br />

zusammen und legte damit die Grundlage für alle modernen<br />

Computerchips. Und das ist nur die bekannteste seiner<br />

Erfindungen.<br />

Der Physik-Nobelpreisträger Jack Kilby starb am 20.6.2005 im Alter von 81 Jahren nach einem<br />

Krebsleiden in Dallas.<br />

Bereits am 12. September 1958 präsentierte der Physiker den ersten Mikrochip in den Labors von<br />

Texas Instruments. Schon der erste Chip war nicht größer als eine Heftklammer. Mit geliehenen<br />

Werkzeugen hatte Kilby den ersten integrierten Schaltkreis konstruiert.<br />

Für Texas Instruments entwickelte Kilby Chipanwendungen für Militär, Industrie und Wirtschaft. Von<br />

1978 bis 1984 war der Amerikaner Professor an der Texas A&M Universität. In den letzten Jahren<br />

6 Ausblick: andere Controller 2


machte Kilby außerdem mit der Entwicklung verbesserter Systeme zur solaren Energiegewinnung von<br />

sich reden.<br />

Kilby besaß 60 Patente und ermöglichte unter anderem die Entwicklung des Taschenrechners und des<br />

Handys. "Es gibt heute praktisch kaum noch einen Bereich des Lebens, der nicht irgendwie durch die<br />

integrierte Halbleiterschaltung beeinflusst wird", sagte Richard Templeton, President von Texas<br />

Instruments.<br />

Im November 1993 erhielt Kilby das japanische Pendant zum Nobelpreis, den Kyoto-Preis. Ein<br />

Mitarbeiter von TI soll über ihn gesagt haben: "Jack hat die angeborene Fähigkeit, Probleme anders zu<br />

sehen, als es die meisten von uns tun. Ich denke, dass der neugierige Geist des Erfinders dahinter<br />

steckt."<br />

Nach der Verleihung des Nobelpreises im Jahr 2000 verbrachte Kilby seine letzten Jahre als Berater<br />

von Texas Instruments und auf Vortragsreisen um die Welt. Kilby hinterlässt zwei Töchter, einen<br />

Schwiegersohn und fünf Enkeltöchter.<br />

Im Jahr 2000 war Kilby zusammen mit dem Deutschen Herbert Kroemer und dem Russen Zhores<br />

Alferov der Physik-Nobelpreis verliehen worden. Kilby wurde für seine bahnbrechenden Arbeiten am<br />

Mikrochip ausgezeichnet. Der Inhaber von 60 Patenten war auch an der Entwicklung des<br />

Taschenrechners und des Thermoprinters beteiligt.<br />

Kilbys erster integrierter Schaltkreis<br />

hatte optisch keine große Ähnlichkeit mit<br />

heutigen Chips<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 07. Okt 2012<br />

Mikrocomputertechnik<br />

In seinem alten Notizbuch befindet sich<br />

das Originaldesign von Kilbys Chip<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Jack Kilby: der Vater des Mikrochips 3


Prolog<br />

In dieser Vorlesung erfahren Sie, wie Computer funktionieren und dass es sich bei einem Computer<br />

lediglich um ein synchrones Schaltwerk oder einen Verbund mehrerer synchroner Schaltwerke<br />

handelt. Die Programmierung erfolgt dabei in einer maschinennahen Sprache, bei der die elementaren<br />

Befehle des Computers lediglich durch mnemotechnische Bezeichnungen etwas verständlicher sind,<br />

als der reine Binärcode. Das Programm zum Übersetzen der sogenannten Mnemonics in den<br />

Binärcode wird "<strong>Assembler</strong>" genannt, weshalb die Programmiersprache in der Regel auch<br />

"assemblersprache" heisst.<br />

Dass die Vorstellungen /uuml;ber Mikrocpmputer, PCs und sogenannte Heimcomputer früher nicht<br />

immer ganz klar waren, beweist das folgende Bild, dass ich samt Bildunterschrift im Internet fand. Es<br />

sollte angeblich aus der Zeitschrift "Popular Electronics" stammen:<br />

Sehr viel sp&aumL;ter entpuppte sich das Bild als Hoax, eine Photomontage. Es handelt sich um das<br />

Photo eines U-Boot-Kontrollstands (Stromversorgung, Dampf etc.) aus einer Ausstellung des<br />

Smithsonian's National Museum of American History, das leicht modifiziert und in ein Graustufenbild<br />

umgewandelt wurde:<br />

Prolog 4


Mikrocomputertechnik<br />

Siehe auch:<br />

http://www.museumofhoaxes.com/hoax/photo_database/image/home_computer_of_the_future/<br />

Auch heute sollten Sie nicht immer alles glauben, was Ihnen über die Leistung und Möglichkeiten von<br />

Computern erzählt wird.<br />

Prolog 5


1 Einführung<br />

Mikro-Computer sind sehr kompakte Computersysteme auf der Basis integrierter Steuer- und<br />

Verarbeitungsbausteine (Mikroprozessoren, Mikrocontroller) und Speicher (VLSI und<br />

ULSI-Bausteine) für allgemeine und spezielle DV-Anwendungen (z. B. Steuerung, Regelung):<br />

• Tisch-/Personal-Computer (PC),<br />

• Einplatinen-Computer (embedded systems),<br />

• Ein-Chip-Computer.<br />

Der folgende Überblick zeigt die Entwicklung des Computers seit Mitte des 20. Jahrhunderts. Mit<br />

Fortschreiten der Integration wurden die Rechner auch immer billiger und kleiner.<br />

Zeitraum Schaltungstechnik Verbreitung Programmierung Geschwindigkeit<br />

1945-1955 Relais, Röhren<br />

wenige<br />

Exemplare<br />

Steckbrett,<br />

Maschinencode<br />

10 3 Op./s<br />

1955-1965 Transistoren, Dioden Hunderte <strong>Assembler</strong>, FORTRAN 10 4 Op./s<br />

1965-1980 Integrierte Schaltungen Tausende<br />

ab 1980<br />

Hoch integrierte<br />

Schaltungen (VLSI)<br />

Millionen<br />

höhere<br />

Programmierspachen<br />

höhere<br />

Programmiersprachen<br />

10 6 Op./s<br />

> 10 7 Op./s<br />

Handelte es sich bei den ersten Systemen noch um nur in wenigen Stückzahlen gefertige Geräte mit<br />

hohen Anschaffungs- und Betriebskosten sowie riesigem Platzbedarf und geringer Zuverlässigkeit, so<br />

beanspruchen die die ab 1955 entwickelten Maschinen ihre Rolle als erste kommerziell erfolgreiche<br />

Systeme.<br />

Die Fortschritte der Fertigungstechnik erlauben eine immer weiter voranschreitende Packungsdichte<br />

der integrierten Schaltungen und verbilligen gleichzeitig deren Herstellung. Mit dem Personal<br />

Computer (PC) und den Heimcomputern (denen nur eine kurze Lebendauer beschieden war) begann<br />

der Einzug der Mikrocomputer und Mikrocontroller in alle Lebensbereiche. Heute enthält<br />

beispielsweise ein Mittelklassse-PKW eine zweistellige Anzahl vom Mikrocontrollern.<br />

Parallel zur Entwicklung der CPU entwickelte sich die Landschaft der zugehörigen Peripherie. Die<br />

erste Rechnergeneration verfügte noch über keine dedizierten Peripheriegeräte. Eingaben wurden<br />

direkt, durch Schalttafeln und Erstellung von Hardwareverbindungen, an der Maschine vorgenommen.<br />

Ausgaben erfolgten über Lampen oder andere Signalgeber. Ab den 1955er Jahren finden sich<br />

zunehmen externe Geräte zur Abwicklung und dauerhaften Speicherung der verarbeiteten Daten und<br />

Programme. Es begann mit Lochstreifen, die später durch Lochkarten abgelöst wurden. Als Ein- und<br />

Ausgabegerät kamen modifizierte Fernschreiber oder entsprechend angepasste elektrische<br />

Schreibmaschinen hinzu. Später wurden sie von Textbildschirmen abgelöst. Bei Embedded Systemen<br />

(Computersysteme, die in Geräten zur Steuerung dienen) gibt es meist keine Peripherie im klassischen<br />

Sinn, sondern dort fungieren Sensoren und Aktoren (Relais, Motoren etc.) als Ein- und Ausgabe.<br />

Wesentliches Element einer Rechnerarchitektur ist der Prozessor (engl. central processing unit, CPU),<br />

der die Hauptteile der Verarbeitung übernimmt. Der stetiger Leistungszuwachs der CPU richtete sich<br />

in der Vergangenheit nach dem Moore'schen Gesetz, das auf Basis empirischer Daten eine<br />

Verdopplung der Transistorenanzahl pro Chip (und damit der Leistungsfähigkeit) alle anderthalb Jahre<br />

voraussagt.<br />

Aktuelle Prozessoren folgen dem folgenden schematischen Aufbau, der die zentralen<br />

Architekturkomponenten Leitwerk, Rechenwerk (arithmetic and logic unit, ALU), Registersatz und<br />

typischerweise den Mikroprogrammspeicher umfaßt.<br />

1 Einführung 6


Mikrocomputertechnik<br />

Diese, nach dem Erfinder als "von-Neumann-Architektur" bezeichnete, Architektur prägt den Aufbau<br />

von Rechenanlagen seit den 1950er Jahren und gilt im Kern bis heute (siehe unten). Einige Engpässe<br />

der von-Neumann-Architektur beruhen auf der Gleichbehandlung von Daten und darauf arbeitenden<br />

Programmen und der sequenziellen Verarbeitung.<br />

Moderne CPU-Architekturen (z. B. Intel Pentium, AMD Athlon und Power PC) verfügen innerhalb<br />

einer CPU über mehrere Rechenwerke, insbesondere solche für Fest- und Gleitkommaoperationen.<br />

Das Leitwerk steuert den gesamten Verarbeitungsfluss. Zur Regelung der Verarbeitung speichert das<br />

Leitwerk prozessorinterne Zustände (Status von Berechnungen und Fehlerindikatoren) in<br />

CPU-internen Speichern, den sog. Registern.<br />

Der Registersatz wird durch eine Reihe von Speicherzellen, die direkt in der CPU untergebracht sind<br />

realisiert. Diese Speicherform stellt die schnellste und gleichzeitig teuerste Form des Speichers dar.<br />

Register besitzen typischerweise eine feste Länge, die mit der verarbeitbaren Wortlänge der CPU<br />

korrespondiert. Häufig werden die zur Verfügung stehenden Register bezüglich ihrer Funktionsweise,<br />

d.h. ihres Einsatzgebietes unterschieden, da oftmals nicht jedes Register für jeden Maschinenbefehl<br />

zur Verfügung steht. Minimalanforderung an einen Registersatz ist die Bereitstellung eines<br />

Befehlszählers (Befehlszeigerregister, engl. Instruction Pointer Register), der die Adresse des<br />

nächsten abzuarbeitenden Befehls enthält.<br />

Darüber hinaus sind Register zur Aufnahme des Rechenergebnisses (Akkumulator) und zur Aufnahme<br />

von Adressen (Stackpointer, Indexregister) sowie ein Status- und Kontrollregister üblich.<br />

1.1 Von-Neumann-Architektur<br />

Im Jahre 1944 legte John von Neumann, ein ehemaliges Mitglied des ENIAC-Projektes, ein<br />

Architektur-Konzept für einen speicherprogrammierten Universalrechner vor. Sein erster Entwurf ist<br />

heute als "von-Neumann-Maschine" oder "von-Neumann-Architektur" bekannt - ein weitsichtiges und<br />

visionäres Konzept, das auch noch aktuellen Computern zugrunde liegt. Eine<br />

Von-Neumann-Maschine weist folgende wichtige Merkmale auf:<br />

1.1 Von-Neumann-Architektur 7


• Steuerwerk, Leitwerk (Befehlsprozessor), das den Programmablauf steuert. Die Befehle<br />

werden interpretiert und deren Ausführung veranlasst, gesteuert und überwacht<br />

(Ablaufsteuerung zur Bearbeitung der Befehle).<br />

• Rechenwerk (Datenprozessor), das die zu bearbeitenden Daten verknüpft und verändert. Dern<br />

Kern bildet die ALU (Arithmetical and Logical Unit) zur Bearbeitung der Daten.<br />

• Speicher, der sowohl Programmbefehle als auch Daten aufnimmt (Hauptspeicher,<br />

Arbeitsspeicher, Main Memory). Die Daten/Befehle liegen binär verschlüsselt, also als<br />

0/1-Folgen vor. Prinzipiell besteht kein Unterschied zwischen Daten und Befehlen.<br />

Unterteilung in Speicherplätze (Speicherzellen, Speicherworte), die über Adressen<br />

angesprochen werden.<br />

• Ein- und Ausgabewerk (E/A-Prozessoren), welche die Schnittstelle zur Außenwelt<br />

(Peripherie) bilden. Zusammen mit den E/A-Geräten besorgen sie die Kommunikation mit der<br />

realen Umwelt.<br />

Leitwerk und Rechenwerk bilden die zentrale Verarbeitungseinheit (CPU, Prozessor).<br />

Die Struktur des Rechners ist unabhängig von dem zu bearbeitenden Problem ( Universalrechner).<br />

Die verschiedenen Aufgaben werden durch entsprechende Programme gelöst. Programme und von<br />

diesen benötigte Daten werden in einem gemeinsamen Speicher abgelegt. Die Speicherplätze sind<br />

gleichlang und werden über Adressen einzeln angesprochen.<br />

Die bedeutendste Neuerung war von Neumanns Idee, Programm und Daten zuerst in den Speicher zu<br />

laden und dann auszuführen. Bis dahin war das Programm noch hardwaremäßig verschaltet oder<br />

wurde über Lochstreifen schrittweise eingelesen und sofort (streng sequentiell) bearbeitet. Nun war es<br />

möglich:<br />

• Sprünge aufgrund logischer Entscheidungen auszuführen<br />

• Programmcode während des Programmablaufes zu modifizieren<br />

Von Neumann erreichte mit seinem Konzept, dass der Rechner selbstständig logische Entscheidungen<br />

treffen kann. Damit ist der Übergang vom starren Programmablauf zur flexiblen Programmsteuerung<br />

vollzogen.<br />

Vorteile der v. Neumann-Architektur:<br />

(Dies ist der Hauptgrund für ihre Langlebigkeit)<br />

Mikrocomputertechnik<br />

• Einfachheit (übersichtlich, minimaler HW-Aufwand)<br />

• maximale Flexibilität (bei genügend elementaren Befehlen)<br />

Vorteile der v. Neumann-Architektur: 8


Nachteile der v. Neumann-Architektur:<br />

• Im Speicher kann man Befehle und Daten nicht unterscheiden.<br />

• nur ein Verbindungsweg zwischen CPU und Speicher (zwischen CPU und Speicher wird<br />

immer nur ein Wort transportiert)<br />

• sequentielle Verarbeitung von Befehl und Datum<br />

Da Daten und Befehle im Speicher gehalten werden, wird die Verbindung und Datenübertragung<br />

zwischen CPU und Speicher bzw. zur Ein-/Ausgabe über den Systembus zum sogenannten<br />

Von-Neumann-Flaschenhals. Jeglicher Datenverkehr von und zur CPU wird über den internen Bus<br />

abgewickelt, dessen Transfergeschwindigkeit langsamer ist, als die Verarbeitungsgeschwindigkeit der<br />

CPU. Dieses Problem versucht man in modernen Prozessoren durch die Verwendung von schnellem<br />

Cache-Speicher, der meist in der CPU integriert ist, abzuschwächen.<br />

Operationsprinzip<br />

Mikrocomputertechnik<br />

Die CPU kann nur elementare, (fest verdrahtete) Befehle verarbeiten ( Maschinenbefehle). Jedes<br />

Programm besteht also aus einer Folge elementarer Befehle. Da im Speicher nicht zwischen Daten<br />

und Befehlen unterschieden wird, muss das Leitwerk entscheiden, ob der Inhalt einer Speicherzelle als<br />

Befehl oder Datum aufzufassen ist. Es gibt somit zwei Zustände des Rechners: Befehl holen<br />

(Interpretieren als Befehl) und Befehl ausführen (Interpretation als Datum). Entsprechend gibt es zwei<br />

Phasen der Programmabarbeitung:<br />

• 1. Phase: Der (durch den sogenannten Befehlszähler) referierte Speicherplatzinhalt wird<br />

geholt und als Befehl interpretiert (Befehlsholphase, instruction fetch)<br />

• 2. Phase: Der Speicherplatzinhalt der durch den Befehl spezifizierten Adresse wird geholt, als<br />

Datum interpretiert und dem Befehl entsprechend verarbeitet (Befehlsausführungsphase,<br />

instruction execution)<br />

Dieses Zweiphasenschema erfordert eine streng sequentielle Ausführung eines Programms, d.h. es<br />

sind zwar Sprünge möglich, jedoch keine parallele Bearbeitung mehrerer Befehle. Ein v.<br />

Neumann-Rechner bearbeitet zu jedem Zeitpunkt immer nur einen Befehl, der immer eine<br />

Datenoperation im Rechenwerk bewirkt.<br />

Komponenten der von-Neumann-Rechnerarchitektur<br />

Vorteile der v. Neumann-Architektur: 9


Mikrocomputertechnik<br />

Die CPU besteht aus Recheneinheit (ALU) und Steuereinheit. Die ALU hat eine feste Wortbreite, z.<br />

B. 8, 16, 32 oder 64 Bit, ihre Aufgabe besteht in der Bearbeitung der Daten, besonders dem Ausführen<br />

von arithmetischen und logischen Operationen.<br />

Zur wichtigsten Aufgabe der Steuereinheit gehört die Koordination der zeitlichen Abläufe im<br />

Rechner. Dazu muss die Steuereinheit die Befehle aus dem Speicher holen, entschlüsseln und deren<br />

Ausführung steuern. Die Steuereinheit besteht aus Befehlsregister, Befehlsdecoder,<br />

Speicheradressregister und Befehlszähler (Program Counter).<br />

Der Speicher eines von-Neumann-Rechners besteht aus einer Vielzahl von Speicherworten, die<br />

wahlfrei adressiert werden können.<br />

Innerhalb eines von-Neumann-Rechners erfolgt der Datentransport auf internen Datenwegen, den<br />

Bussen:<br />

• Der Datenbus wird normalerweise parallel übertragen, d. h. bei einem 32-Bit-System besteht<br />

der Datenbus aus 32-Leitungen. Er transportiert Speicher- oder E/A-Daten von und zur CPU.<br />

• Der Adressbus besteht aus den Adressleitungen, deren Anzahl vom Adressbereich der CPU<br />

abhängt.<br />

• Der Steuerbus koordiniert den Zugriff auf die Komponenten und enthält u. a. Leitungen für<br />

die Interrupt-Steuerung, Buszugriffssteuerung, der Taktung, Reset- und Statusleitungen.<br />

Vorteile der v. Neumann-Architektur: 10


1.2 Befehlszyklus<br />

Das folgende Bild zeigt den prinzipiellen Ablauf bei Bearbeiten eines Befehls.<br />

• Im Befehlsregister (IR, Instruction Register) befindet sich jeweils der aktuell bearbeitete<br />

Befehl<br />

• Der Befehlsdecoder entschlüsselt den Befehl und erzeugt die zur Ausführung notwendigen<br />

Hardware-Steuersignale<br />

• Im Speicheradressregister (MAR, Memory Adress Register) steht die Adresse des nächsten<br />

auszuführenden Befehls oder die Adresse eines Datenwortes, falls zur Ausführung eines<br />

Befehls ein Datenwort vom Speicher geholt bzw. in den Speicher gebracht werden muss.<br />

• Der Befehlszähler (PC, Program Counter) enthält die Adresse des nächsten auszuführenden<br />

Befehls.<br />

Der Befehlszyklus wird also von der CPU ständig durchlaufen:<br />

• die Befehle stehen im Speicher.<br />

• das Leitwerk "weiß" jederzeit, welcher Befehl als nächster auszuführen ist.<br />

• die Adresse (= Nummer der Speicherzelle) des nächsten auszuführenden Befehls steht in<br />

einem speziellen Register des Leitwerks, dem Befehlszähler (Program Counter, PC, BZ,<br />

Instruction Address Register, IAR, Instruction Pointer, IP).<br />

• üblicherweise stehen aufeinanderfolgende Befehle in aufeinander folgenden Speicherzellen,<br />

der zuerst auszuführende Befehl hat die niedrigste Adresse.<br />

• zu Beginn des Programms wird der BZ mit dessen Startadresse geladen.<br />

Ablauf des Befehlszyklus<br />

Mikrocomputertechnik<br />

1.2 Befehlszyklus 11


Mikrocomputertechnik<br />

In der Befehlsholphase erfolgt ein Speicherzugriff (1a) auf die vom Befehlszähler (BZ) angezeigte<br />

Adresse. Der entsprechende Befehl wird in das Befehlsregister (IR) des Leitwerks gebracht (1b).<br />

Anschließend wird der BZ um 1 erhöht. Er zeigt damit auf den nächsten Programmbefehl. Besteht ein<br />

Befehl aus mehreren Speicherworten, setzt sich diese Phase auch aus mehreren Speicherzugriffen<br />

zusammen (BZ wird jedes Mal erhöht), bis der Befehl vollständig im IR steht. Es erfolgt hier in der<br />

Befehlsholphase bereits eine Teilauswertung des Operations-Codes (s. Grafik). Das Befehlsregister<br />

besteht hier aus Op-Code-Register (OR, Befehlsregister) und Adress-Register (AR).<br />

Der Befehl im OR wird nun decodiert (Befehlsdecoder) und der Ablaufsteuerung zugeführt. Diese ist<br />

in der Regel als Mikroprogramm realisiert. Die Ablaufsteuerung erzeugt nun die nötigen<br />

Steuersignale.<br />

Benötigt der Befehl Operanden, so wird deren Adresse aus dem Inhalt des AR ermittelt. Häufig ist im<br />

Befehl nicht die tatsächliche Operandenadresse, sondern nur eine Teilinformation enthalten, die noch<br />

geeignet ergänzt werden muss ( Adressrechnung.<br />

Nun erfolgt ein Speicherzugriff (4a) auf die so festgestellten Operanden-Adresse. Der Operand wird in<br />

das vom Op-Code spezifizierte Register oder in das Rechenwerk (4b) oder in die ausgewählte<br />

Speicherzelle gebracht.<br />

Falls durch den Op-Code weitere Teiloperationen gefordert sind, werden diese nun ausgeführt. Dabei<br />

kann auch der Inhalt des BZ verändert werden (Sprungbefehle, Unterprogramm-Aufrufe).<br />

Ablauf des Befehlszyklus 12


Mikrocomputertechnik<br />

Jeder Befehlszyklus besteht aus einer Anzahl von Teilschritten. Die Anzahl der Teilschritte kann für<br />

unterschiedliche Befehle verschieden sein, auch die Zeitdauer der einzelnen Befehle kann<br />

unterschiedlich sein.<br />

Die Befehlszyklen verschiedener Befehle können unterschiedlich lang sein. Die tatsächliche Dauer<br />

eines Befehlszyklus hängt von der Taktfrequenz der CPU ab. Der gesamte Ablauf in der CPU wird<br />

durch einen zentralen Takt gesteuert. Ein Befehlszyklus kann in eine Reihe von Maschinenzyklen<br />

zerlegt werden (z.B. Speicherzugriff in einem Maschinenzyklus). Ein Maschinenzyklus kann eine oder<br />

mehrere Taktperioden (Arbeitstakt des Prozessors) dauern.<br />

1.2 Erhöhung der Leistungsfähigkeit<br />

• Verlagerung der Prozessorfunktionen bei der Ein-/Ausgabe auf das E/A-Werk ("intelligente"<br />

Schnittstellen, E/A-Prozessoren, Vor-Rechner, Front-End-Rechner).<br />

• Weiterentwicklung des Architekturprinzips durch Steuerung der einzelnen Funktionseinheiten<br />

über eigene Prozessoren, wodurch eine teilweise Parallelarbeit möglich wird.<br />

• Bearbeiten einzelner, spezieller Befehle durch Spezialprozessoren, die abwechselnd mit der<br />

"normalen" CPU arbeiten (z. B. Arithmetik-Koprozessor).<br />

1.2 Erhöhung der Leistungsfähigkeit 13


Vermeiden oder Mildern des v. Neumann-Flaschenhalses<br />

• Neue Rechnerarchitekturen durchbrechen den streng sequentiellen Ablauf des v.<br />

Neumann-Rechners durch Parallelisierung verschiedener Abläufe im Computer.<br />

• Feldrechner bestehen aus mehreren parallelen Rechenwerken, mit gemeinsamen Steuerwerk.<br />

So kann die gleiche Operation auf vielen verschiedenen Datenwerten (Feldern) gleichzeitig<br />

ausgeführt werden.<br />

Asynchrone Trennung von Befehlshol- und -ausführungsphase<br />

•<br />

Pipeline-Rechner: Entweder mehrere hintereinandergeschaltete Rechenwerke, die verschieden<br />

Aufgaben erfüllen, aber gemeinsam gesteuert werden oder Aufbau eines Prozessors mit<br />

hintereinandergeschalteten spezialisierten Teilelementen. Die einzelnen Befehle werden in<br />

Teilaufgaben zerlegt, die nach einander von den Teilelementen bearbeitet werden.<br />

Die nächste Operation kann bereits begonnen werden, wenn die vorhergehende in die nächste<br />

"Station" gelangt ist.<br />

(schematisch dargestellt)<br />

Gleichzeitige Bearbeitung mehrerer Befehle<br />

Zur selben Zeit führt jedes Verarbeitungselement verschiedene Operationen auf<br />

unterschiedlichen Daten durch.<br />

überlappende Befehlszyklen<br />

• Vektorrechner: Kombination mehrerer Pipelines<br />

• Multiprozessorsysteme: Koppelung mehrerer Prozessoren, die auf den gleichen Speicher<br />

(bzw. Speicherbereich) zugreifen und weitgehend unabhängig voneinander arbeiten. Jede<br />

CPU kann ein eigenes Programm bearbeiten MIMD.<br />

• Polyprozessorsysteme: Multiprozessorsystem mit verteilter Kontrolle, bei dem die einzelnen<br />

CPUs autonom arbeiten, aber miteinander kommunizieren und kooperieren.<br />

Meist besitzt jeder Prozessor einen eigenen Speicher, z. B. Transputer. Fehlertolerante<br />

Mehrrechnersysteme eng/lose gekoppelt (z. B. in der Raumfahrt).<br />

1.4 Die Harvard-Architektur<br />

Mikrocomputertechnik<br />

Die Harvard-Architektur ist im Kern älter als die von-Neumann-Architektur, denn die ersten<br />

Computer (etwa die Zuse 3) hatten eigentlich nur einen Datenspeicher. Der "Programmspeicher"<br />

Vermeiden oder Mildern des v. Neumann-Flaschenhalses 14


Mikrocomputertechnik<br />

manifestierte sich als Lochstreifen oder -karten. Erst später wurde das Programm auf Speichermedien,<br />

z. B. einem Trommelspeicher abgelegt. Typisch war also die Trennung von Daten- und<br />

Programmspeicher.<br />

Die Harvard-Architektur bezeichnet heute ein Schaltungskonzept zur Realisierung besonders schneller<br />

CPUs und Signalprozessoren. Befehlsspeicher und Datenspeicher sind voneinander getrennt und<br />

werden über getrennte Busse angesteuert. Daher können Befehle und Daten gleichzeitig geladen, bzw.<br />

geschrieben werden. Bei einer klassischen Von-Neumann-Architektur sind hierzu mindestens zwei<br />

aufeinander folgende Buszyklen notwendig. Zudem sorgt die Trennung von Daten und Programm<br />

dafür, dass bei Softwarefehlern kein Programmcode überschrieben werden kann. Nachteilig ist<br />

allerdings, dass nicht benötigter Datenspeicher nicht als Programmspeicher genutzt werden kann.<br />

Die Harvard-Architektur wurde zunächst überwiegend in RISC-Prozessoren konsequent umgesetzt.<br />

"RISC" steht für "Reduced Instruction Set Computer" (Computer mit eingeschränktem Befehlssatz -<br />

siehe unten). RISC-Prozessoren haben einen kleinen Befehlssatz, bei dem aber fast alle Befehle<br />

innerhalb eines einzigen Taktzyklus ausgeführt werden können.<br />

Moderne Prozessoren in Harvard-Architektur sind in der Lage, parallel mehrere Rechenwerke<br />

gleichzeitig mit Daten zu füllen und auf diesen Daten Befehle auszuführen. Ein weiterer Vorteil der<br />

Trennung besteht darin, dass Datenwortbreite und Befehlswortbreite unabhängig voneinander sind.<br />

Damit kann, falls erforderlich, die Effizienz des Programmspeicherbedarfs verbessert werden, da sie<br />

nicht direkt von den Datenbusbreiten abhängig ist, sondern ausschließlich vom Befehlssatz. Besonders<br />

bekannte Vertreter dieser Architektur sind die Produkte der Firma Microchip Technology Inc. (PIC)<br />

und die Mikrocontroller der AVR-Reihe von Atmel.<br />

Eine bedeutende Erweiterung der Harvard-Architektur wurde von Analog Devices durch die<br />

Einführung der SHARC-(Super-Harvard-Architecture)-Technologie vorgenommen, bei der die<br />

Speichersegmente als Dual-Port-RAMs realisiert wurden, die kreuzweise zwischen den Programmund<br />

Daten-Bussen liegen.<br />

Viele moderne Prozessoren verwenden eine Mischform aus Harvard- und von-Neumann-Architektur,<br />

bei der innerhalb des Prozessors Daten und Programm voneinander getrennt verwaltet werden. Es<br />

existieren eigene Cache-Speicher und Memory Management Units mit getrennten internen Bussen.<br />

1.4 Die Harvard-Architektur 15


Extern wird jedoch in einem gemeinsamen Speicher zugegriffen. Beim Pipelining besteht der Vorteil<br />

dieser Mischform darin, dass deren einzelne Pipelinestufen in Bezug auf Speicherzugriffe getrennt<br />

arbeiten können.<br />

RISC "Reduced Instruction Set Computer"<br />

(Computer mit eingeschränktem Befehlssatz)<br />

Hat man anfangs versucht, beim Design neuer Prozessor-Chips immer mehr und immer<br />

leistungsfähigere Befehle zu integrieren (Complex Instruction Set Computer, CISC), so wird beim<br />

RISC-Prozessor der umgekehrte Weg beschritten.<br />

Für jeden Befehl des Prozessors gibt es eine fest verdrahtete Folge von Ablaufschritten im Chip, das<br />

Mikroprogramm. Je komplexer und mächtiger ein Befehl ist, desto mehr Einzelschritte muss das<br />

Mikroprogramm auf den Chip durchlaufen und desto mehr Taktzyklen sind notwendig, bis der<br />

Prozessor den nächsten Befehl verarbeiten kann. So liegt z.B. beim Prozessor 8088 die Zahl der<br />

Taktzyklen für einen Befehl zwischen 2 und 190.<br />

RISC-Prozessoren haben einen kleinen Befehlssatz, bei dem aber fast alle Befehle innerhalb eines<br />

einzigen Taktzyklus ausgeführt werden können. Das bedeutet auch eine Vereinfachung des Chips und<br />

erreicht auf diese Weise höhere Taktfrequenzen. Typische RISC-Mikrocontroller sind die<br />

PIC-Modelle von Microchip und etliche Atmel-Prozessoren.<br />

1.5 Begriffe<br />

Mikrocomputer:<br />

• Datenverarbeitungssystem mit einem Mikroprozessor als CPU<br />

• Extrem räumlich verkleinertes DVS (PC, Laptop, Steuerechner, etc.)<br />

• Leistungsfähigkeit eingeschränkt gegenüber Mini- und Groß-DVS<br />

• Verwendung häufig als Steuerungsrechner<br />

Mikroprozessor:<br />

• Auf einem Chip integrierte Steuer- und Verarbeitungseinheit, die als CPU im Mikrocomputer<br />

verwendet wird (Steuer- und Leitwerk)<br />

• Mikroprozessor alleine ist nicht einsatzfähig - erst der Mikrocomputer<br />

• Mikrocomputer = Mikroprozessor + Speicher + E/A-Bausteine [+ Peripherie]<br />

Mikrocontroller:<br />

• Mikrocomputer, die auf einem Chip integriert sind Single-Chip-Mikrocomputer<br />

• begrenzter Arbeitsspeicher (meist weniger als 1 MByte)<br />

• kein Massenspeicher (Festplatte,...)<br />

• längere Zykluszeiten (PC: bis GHz, MC: wenige MHz)<br />

• Möglichkeit der Signalverarbeitung (z. B.: integrierte serielle Schnittstelle,<br />

Analog-/Digital-Wandler, Zeitgeber, Impulszähler)<br />

1.6 Entwicklung<br />

Mikrocomputertechnik<br />

RISC "Reduced Instruction Set Computer" 16


Mikrocomputertechnik<br />

Mikroprozessor und Mikrocomputer sind Ergebnis der Entwicklungen im Bereich der<br />

Halbleitertechnik Mikroelekronik, ständige Erhöhung der Integrationsdichte.<br />

• SSI (small scale integration): einige Gatter<br />

• MSI (medium scale integration): Zähler, Register, ALU<br />

• LSI (large scale integration): Mikroprozessor, Speicher<br />

• VLSI (very large scale integr.): komplexere Mikroprozessor, Speicher<br />

• ULSI (ultra large scale integr.): Speicher hoher Kapazität<br />

Die zunehmende Integrationsdichte führte zu immer stärkerer Spezialisierung der Funktion und zur<br />

Einschränkung der Einsatzmöglichkeiten kundenspezifische LSI-Schaltkreise. Auswege:<br />

• standardisierte Bausteine<br />

• programmgesteuerte Bausteine (Mikroprozessor, Mikrocomputer)<br />

Der erste Mikroprozessor wurde 1970/71 von Intel als Steuerbaustein für ein Bildschirmterminal<br />

entwickelt. Da er für den vorgesehenen Zweck zu langsam war, wurde er als universeller<br />

Steuerbaustein vermarktet (4004, 8008). Durch Zufall kam dieses Produkt zur richtigen Zeit als<br />

Alternative zu kundenspezifischen Bausteinen auf den Markt. Folge: sensationell zunehmende<br />

Entwicklung des Mikrocomputer-Einsatzes. Die Entwicklung erfolgte in zwei Richtungen:<br />

• Ersatz festverdrahteter Logikschaltungen<br />

Steuerungsrechner<br />

Verwendung des Mikrocomputer als spezieller<br />

• Entwicklung kleiner und billiger Universalrechner Personal Computer<br />

Die ersten Mikroprozessoren von Intel, 4004 und 8008<br />

Mikrocomputer als Ersatz festverdrahteter Logik<br />

Einsatz für komplexe Steuerungsaufgaben in sich ständig ausweitenden Anwendungsgebieten. Die<br />

weitaus größere Zahl von Mikroprozessoren wird hier eingesetzt. Das Programm für eine bestimmte<br />

Aufgabe wird im ROM abgelegt. Ein kleiner RAM-Bereich speichert die Variablen, z. B.:<br />

1.6 Entwicklung 17


• Single-Chip-Mikrocomputer mit RAM und ROM auf dem Chip<br />

• Mikroprozessor + ROM + E/A-Baustein mit integr. RAM<br />

Einsatzbeispiele:<br />

Mikrocomputertechnik<br />

• Meßtechnik:<br />

komfortable und leistungsfähige Meßgeräte (Bereichswahl, Berechnung, Eichkurven, graph.<br />

Darstellung, ...)<br />

• Steuerung:<br />

NC-Maschinen, Prozeßsteuerung, Roboter, SPS, automat.Testsysteme, KFZ-Technik<br />

• Nachrichtentechnik:<br />

Fernsprechtechnik + Vermittlungstechnik (Nebenstellenanlagen, ISDN, Mobiltelefon, ...),<br />

Telefax, Sender + Empfänger, Radar, Spracherkennung, ...<br />

• Bürotechnik:<br />

Kopierer (heute schon voll digital), Registrierkassen, Schreibautomaten, Anrufbeantworter, ...<br />

• KFZ-Elektronik:<br />

Motorsteuerung, ABS, Bord-Computer, Verkehrsleitsysteme, Diagnose-Computer, ... letzte<br />

Entwicklungen: autonomes, "sehendes" Fahrzeug<br />

• Haushaltelektronik:<br />

Waschmaschine, Nähmaschine, Heizungssteuerung, Alarmanlagen, ...<br />

• Unterhaltungselektronik:<br />

Radio- und Fernsehgeräte, HIFI-Geräte, Videorecorder, Satelliten-Empfänger, ...<br />

• Datenverarbeitung:<br />

Intelligente Peripherie (Terminals, Drucker, Plotter, Scanner, ...)<br />

Eines der ersten Entwicklungssysteme: KIM1 mit Prozessor 6502, 1 kByte Speicher, Hex-Tastatur<br />

und Siebensegmentanzeige<br />

Mikrocomputer als Ersatz festverdrahteter Logik 18


Mikrocomputer als Universalrechner<br />

Ursprünglich als Entwicklungssysteme für den o.g. Anwendungsbereich konzipiert erfolgte eine<br />

Weiterentwicklung zu Arbeitsplatzrechnern (PC, Homecomputer).<br />

• Durch Vernetzung dezentrale DV<br />

• Vorstoß in den Bereich der Minicomputer Die 16-, 32- und 64-Bit-Mikroprozessor zielen in<br />

diese Richtung.<br />

Kennzeichen:<br />

• Verwendung höherer Programmiersprachen<br />

• komplexe und leistungsfähige Betriebssysteme<br />

• Funktionsmerkmale von Großrechnern (virtuelle Speicherung, Cache)<br />

Technische Entwicklung:<br />

Anzahl Transistoren eines Intel 8080 Mikroprozessors 4 500<br />

Anzahl Transistoren eines Intel 80286 Mikroprozessors 134 000<br />

Anzahl Transistoren eines Intel 80386 Mikroprozessors 275 000<br />

Anzahl Transistoren eines Intel Pentium Mikroprozessors 3 100 000<br />

Anzahl Transistoren eines Intel Pentium 4 Mikroprozessors 42 000 000<br />

Anzahl Transistoren eines AMD KG (Athlon 64) Mikroprozessors 105 900 000<br />

Anzahl Transistoren eines Intel Core i7 Mikroprozessors 731 000 000<br />

Anzahl Transistoren eines Eight Core Xeon Nehalem-EX Mikroprozessors 2 300 000 000<br />

Anzahl Transistoren eines RV820 ATI/AMD Grafikprozessors 2 154 000 000<br />

Anzahl Transistoren eines GF100 NVIDIA Grafikprozessors 3 000 000 000<br />

Festplattenkosten pro Gigabyte 1990 53 000<br />

Festplattenkosten pro Gigabyte 1995 850<br />

Festplattenkosten pro Gigabyte 2000 20<br />

Festplattenkosten pro Gigabyte 2005 1<br />

Festplattenkosten pro Gigabyte 2010 0.1<br />

RAM-Kosten pro Gigabyte 1990 120 000<br />

RAM-Kosten pro Gigabyte 1995 33 000<br />

RAM-Kosten pro Gigabyte 2000 1 400<br />

RAM-Kosten pro Gigabyte 2005 190<br />

RAM-Kosten pro Gigabyte 2010 20<br />

(Alle Preisangaben in US-Dollar)<br />

1.7 Embedded Systems<br />

Mikrocomputertechnik<br />

"Embedded Systems" ist der englische Fachbegriff für eingebettete (Computer-)Systeme, die in der<br />

Regel unsichtbar ihren Dienst in einer Vielzahl von Anwendungsbereichen und Geräten versehen, wie<br />

Mikrocomputer als Universalrechner 19


z.B. in Flugzeugen, Autos, Kühlschränken, Fernsehern, Werkzeugmaschinen, Kaffeeautomaten,<br />

DVD-Playern oder anderen Geräten. In der Computerbranche werden solche Systeme auch gerne<br />

"Appliance" genannt. ("appliance: A device or instrument designed to perform a specific<br />

function, especially an electrical device, such as a toaster.)<br />

Wenn man den Begriff aufschlüsselt ergibt sich:<br />

Mikrocomputertechnik<br />

• Ein "System" ist in diesem Kontext immer eine informationsverarbeitende Maschine<br />

• "eingebettet" bedeutet: für einen spezifischen Zweck in einer technischen Umgebung<br />

entworfen, eingebaut und betrieben.<br />

Ein eingebettetes System verrichtet, weitgehend unsichtbar für den Benutzer, den Dienst in einer<br />

Vielzahl von Anwendungsbereichen und Geräten, wie z. B. in Flugzeugen oder Autos,<br />

Haushaltsgeräten, in der Unterhaltungselektronik, bei Mobiltelefonen oder in industriellen<br />

Steuerungen. Ein eingebettetes System interagiert mit seiner meist elektromechanischen Umwelt.<br />

Dabei ist kein menschlicher Benutzer vonnöten; er muss auch keinerlei Kenntnisse über die<br />

technischen Innereien des eingebetteten Systems haben, um das Gesamtsystem bedienen zu können.<br />

Im Fall von komplexen Gesamtsystemen handelt es sich dabei meist um eine Vernetzung einer<br />

Vielzahl von autonomen, eingebetteten Systemen.<br />

Eingebettete Systeme können in Einzelfällen auf ähnlicher Hardware wie Arbeitsplatzcomputer<br />

basieren (sogenannte embedded-PCs), in der Regel unterliegen sie jedoch stark einschränkenden<br />

Randbedingungen: Minimale Kosten, geringer Platz-, Energie-, Speicherverbrauch. Einzelne<br />

Komponenten wie Prozessor oder Arbeitsspeicher müssen auch wesentlich länger auf dem Markt<br />

verfügbar sein, um die langfristige Einsetzbarkeit und Ersatzteilbeschaffung zu gewährleisten.<br />

Moderne eingebettete Systeme basieren auf den verschiedensten Prozessor-Plattformen, die in<br />

Bezug auf die Peripheriemodule hochintegriert sind und durch moderne Stromspartechniken wenig<br />

Energie verbrauchen.<br />

"Embedded Systems" vereinigen daher durch ihre oftmals sehr hardwarenahe Konstruktion die große<br />

Flexibilität von Software mit der Leistungsfähigkeit der Hardware. Die Software-Entwicklung für<br />

diese Systeme unterscheidet sich oft grundsätzlich von jener für Desktop- oder PC-Systeme: oftmals<br />

werden Betriebssysteme eingesetzt, die zwar nicht über eine grafische Benutzeroberfläche verfügen,<br />

dafür jedoch Echtzeitanforderungen genügen.<br />

Bevorzugte Programmiersprachen sind daher z. B. <strong>Assembler</strong> oder C. Bekannte<br />

Embedded-Betriebssysteme sind z.B. QNX, VxWorks, Windows CE, DOS, LynxOS, Nucleus,<br />

zunehmend auch spezielle Linux-Derivate, wenn die Echtzeitbedingungen keine dominante Rolle<br />

spielen. Einige Beispiele für Embedded Systems sind:<br />

• Die Elektronik in einem Kaffeevollautomaten. Mit ihr wird beispielsweise die Kaffeemenge<br />

und -stärke sowie die Wassermenge reguliert. Die Kaffemaschine an sich ist kein<br />

datenverarbeitendes System.<br />

• Auch die Elektronik in einem Videorecorder ist ein eingebettetes System, auch wenn der<br />

Videorecorder selbst ein (eingeschränkt) datenverarbeitendes System ist.<br />

• Der Zündcomputer im Auto ist ebenfalls ein im Stillen wirkendes System, wobei in einem<br />

Fahrzeug der Oberklasse inzwischen einige Dutzend Computer werkeln.<br />

• Die Steuerungen von NC-Werkzeugmaschinen (NC = Numeric Control) oder anderen<br />

industriellen Systemen sind fast immer Embedded Systems.<br />

• Fast alle Peripheriegeräte in der Datenverarbeitung (Drucker, Scanner, Barcode-Leser, Router<br />

usw.) sind mit eigener Intelligenz zur Verarbeitung der Daten ausgerüstet.<br />

Kennzeichnende Merkmale von embedded Systemen sind:<br />

1.7 Embedded Systems 20


Mikrocomputertechnik<br />

• sie sind fester Bestandteil eines technischen Systems<br />

• sie sind zweckbestimmt (im Gegensatz zum Universalrechner)<br />

• sie interagieren mit der Umgebung durch Sensoren und Aktoren<br />

• sie reagieren meist in Realzeit<br />

Sekundäre Merkmale von embedded Systemen sind:<br />

• sie werden oft für Regelungs- und Steuerungsaufgaben vorgesehen<br />

• sie sind häufig Massenware, Konsumgut, billig<br />

• sie sind vielfach schlecht bzw. nicht wartbar und nicht erweiterbar<br />

• sie sind manchmal auch sicherheitskritisch<br />

Eingebettete Systeme beanspruchen einen Marktanteil bei der Prozessor-Produktion von ca. 98%. Die<br />

restlichen 2% dienen dem Aufbau von interaktiven Systemen wie z. B. Laptops, Desktop-Computern<br />

und Servern. Nahezu die Hälfte der gesamten Microcontroller-Jahresproduktion sind immer noch<br />

8-Bit-Prozessoren. Bereits heute gibt es mehr eingebettete Systeme als Menschen auf der Welt. Deren<br />

Elektronik dient oft als Wegwerf-Artikel (z. B. RFID-Tags, Grusspostkarten).<br />

Man setzt deshalb für die Definition des eingebetteten Systems voraus, dass<br />

• die genaue Aufgabe des Systems vor der Entwicklung feststeht,<br />

• immer nur ein einziges Programm abläuft und<br />

• Hardware und Software eine funktionale Einheit bilden.<br />

Tatsächlich haben sich im der Industrie immer häufiger Standard-PC-Komponenten bei<br />

Neuentwicklungen von eingebetteten Systemen durchgesetzt -- geringe bis mittlere Stückzahlen und<br />

kurze Produktzyklenzeiten vorausgesetzt. Die Komponenten von der Stange ("Commodity of the<br />

Shelf", COTS) kosten oft nur einen Bruchteil vergleichbarer proprietärer Industrielösungen und sind<br />

dabei wesentlich flexibler. Diese "Embedded PCs" sind aber nicht überall sinnvoll: Oft zwingen rauhe<br />

Umgebungen und Platzmangel zu speziellen Eigenentwicklungen. Bei hohen Stückzahlen ist dies<br />

ohnehin obligatorisch.<br />

Anders als stationäre Systeme haben eingebettete Systeme besondere Anforderungen hinsichtlich<br />

Robustheit, Energieverbrauch und Speicherbedarf, Im Gegensatz zu einem Arbeitsplatzrechner wird<br />

ein eingebettetes System im Allgemeinen nicht "heruntergefahren", bevor man es ausschaltet. Es muss<br />

im Gegenteil damit zurechtkommen, dass ihm der Strom jederzeit und ohne Vorwarnung abgestellt<br />

werden kann. Damit ein solcher Shutdown, etwa aufgrund eines Stromausfalls, problemlos<br />

überstanden wird und die Software nach dem Booten in einen definierten Anfangszustand gelangt.<br />

Bewegliche Teile wie Lüfter oder Festplatte sind meist nicht erwünscht. Besonders sind auch meist<br />

die Umgebungsbedingungen wie Temperatur und Feuchtigkeit. Um auch diesen Anforderungen<br />

gerecht zu werden, steht eine möglichst geringe Stromaufnahme des Prozessors bzw. des Boards im<br />

Vordergrund. Im Vergleich zum "Stomfresser" im Desktop-Rechner kommt ein embedded Board<br />

meist mit weniger als 1 Watt aus. Embedded Systems laufen buchstäblich während ihrer gesamten<br />

Lebensdauer, also an sieben Tagen pro Woche und 24 Stunden pro Tag. Gelegentliche Abstürze mit<br />

der Notwendigkeit eines Neustarts sind hier absolut inakzeptabel (insofern fällt mein kürzlich<br />

erworbener DVB-T-Empfänger/Decoder aus dem Rahmen, bei schlechtem Empfang hängt er sich<br />

schon mal auf).<br />

Embedded Systems basieren also oft auf ähnlicher Hardware wie Arbeitsplatzcomputer, unterliegen<br />

jedoch meist stark einschränkenden Randbedingungen: minimale Kosten und damit geringer Platz-,<br />

Energie-, Speicherverbrauch. Die Fertigung in großen Stückzahlen, oft im Millionen-Bereich, ist ein<br />

weiterer wichtiger Punkt zur Kostenreduzierung. Hinzu kommt, dass die einzelnen Komponenten wie<br />

Prozessor und RAM auf Weiterentwicklungen älterer Komponenten basieren, was die Langlebigkeit<br />

1.7 Embedded Systems 21


steigert, Stromverbrauch und -kosten jedoch senkt.<br />

Für viele Anwendungen können auch ältere Komponenten eingesetzt werden, wenn zudem die<br />

Vereinfachung der Architektur des ursprünglichen Systems dazu beiträgt, weitere Kosten zu senken.<br />

Programme eines Embedded Systems müssen oft Echtzeitanforderungen genügen. In der Regel<br />

existieren verglichen mit Desktop-PC-Hardware nur stark reduzierte Ressourcen, zumeist ohne<br />

Festplatte, Betriebssystem, Tastatur oder Bildschirm. Ein ROM- oder Flash-Speicher ersetzt meist<br />

mechanische Speicherkomponenten wie eine Festplatte: bewegliche Teile bedeuten Verschleiß, der<br />

hier unerwünscht ist. Wenn überhaupt, dann gibt es meist nur ein Tastenfeld und die Ausgabe wird -soweit<br />

überhaupt vorgesehen -- durch ein LCD realisiert.<br />

Design von Embedded Systems<br />

Die Elektronik wird meist von einem Mikroprozessor mit entsprechender Peripherie oder einem<br />

Microcontroller gebildet. Vielfach handelt es sich auch um komplette PC-Boards mit stromsparenden<br />

Bauteilen und anderem Formfaktor. Ein solcher PC gilt bereits als groß, wenn er Postkartenformat<br />

besitzt. Um das Board herum ist dann die dem Aufgabengebiet entsprechende Peripherie angeordnet.<br />

Folgende Aspekte spielen u. a. bei Designentscheidungen von Embedded Systems eine Rolle:<br />

• Integration: Je mehr Funktionalität der verwendete Mikrocontroller bereits besitzt, desto<br />

weniger Peripheriebausteine werden benötigt, um die Anbindung an die benötigten<br />

Systemschnittstellen (Ein-/Ausgabe) zu ermöglichen. Je weniger Bausteine eine Platine<br />

benötigt, desto geringer sind der Platzbedarf der Leiterbahnen und die Signallaufzeiten<br />

zwischen den Bausteinen.<br />

• Echtzeitanforderungen: Hohe Verfügbarkeit und definierte Antwortzeit sind häufig gestellte<br />

Anforderungen an ein Embedded System und somit auch an dessen Betriebssystem und die<br />

Software. Die Verwendung spezieller Echtzeitbetriebssysteme erlaubt es, schon in der<br />

Entwicklungsphase die Reaktionszeiten des Gesamtsystems abzuschätzen.<br />

• Cross-Entwicklung: Oft ist das System, auf dem die Software entwickelt wird, nicht<br />

identisch mit dem Zielsystem. Es werden dann Compiler eingesetzt, die Binärcode für das<br />

Zielsystem erzeugen. Bei kleinen Embedded Systems (die oft nicht einmal ein Betriebssystem<br />

besitzen) erfolgt der Programmtransfer durch Programmieren des Flash-Speichers auf dem<br />

Entwicklungsrechner. Der Speicherbaustein wird dann zum Testen ins Zielsystem eingesteckt.<br />

Bei modernen Microcontrollern ist in der Regel die Möglichkeit gegeben, den Flash-Speicher<br />

on board zu programmieren -- es genügen dann ein paar Drähte zwischen Entwicklungs- und<br />

Zielsystem. Besitzt das Zielsystem ein eigenes Betriebssystem, kann der Datentransfer auch<br />

über Standardschnittstellen oder Netzwerk erfolgen.<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 07. Okt 2012<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Design von Embedded Systems 22


2 Hardware von Mikrocomputern<br />

2.1 Struktur eines Mikrocomputers<br />

Prinzipieller Aufbau<br />

Ein Mikrocomputer hat grundsätzlich die gleichen Eigenschaften, wie ein größeres DV-System, die<br />

von-Neumann-Struktur. Die Besonderheiten sind:<br />

• CPU ist in einem Chip integriert (Mikroprozessor)<br />

• Der Arbeitsspeicher zerfällt i.A. bei Steuerungsrechnern in Programmspeicher (ROM, PROM,<br />

EPROM,...) und Datenspeicher (RAM)<br />

• Das E/A-Werk besteht aus speziellen E/A-Bausteinen, die als IC zahlreich und passend für<br />

den verwendeten Mikroprozessor-Typ angeboten werden Mikroprozessor-Familie:<br />

♦ einfache serielle/parallele E/A-Bausteine,<br />

♦ DMA-, CRT-, Floppy- und Platten-Controller,<br />

♦ E/A-Prozessoren,<br />

♦ Arithmetikprozessoren,<br />

♦ Timer,<br />

♦ Speicherverwaltungsbausteine,<br />

♦ usw.<br />

• Die Verbindung der einzelnen Komponenten erfolgt durch eine Bus-Struktur. ( teilweiser<br />

Verzicht auf Parallelarbeit einzelner Komponenten).<br />

• Ein einfacher Mikrocomputer besteht aus relativ wenigen, hochintegrierten Bausteinen.<br />

Der System-Bus<br />

Bus = Anzahl von Leitungen, an die mehrere Funktionseinheiten parallel angeschlossen sind. Der<br />

Informationsaustausch zwischen diesen Einheiten erfolgt zeitmultiplex über den Bus. Zu jedem<br />

Zeitpunkt sind immer nur zwei Einheiten (Sender, Empfänger) miteinander verbunden.<br />

• unidirektionaler Bus: Information geht nur in einer Richtung (i.a. nur 1 Sender)<br />

2 Hardware von Mikrocomputern 23


• bidirektionaler Bus: Informationsaustausch in beiden Richtungen (mehrere Sender)<br />

In Mikroprozessor-Systemen ist (mit Ausnahme des DMA) der Mikroprozessor immer einer der<br />

beiden aktiven Bausteine. Die Bus-Leitungen werden in funktionelle Gruppen gegliedert:<br />

• Adreß-Bus (A-Bus):<br />

unidirektional, 8-32 Leitungen, Auswahl von Speicherzellen, Bausteinen, E/A-Registern<br />

• Daten-Bus (D-Bus):<br />

bidirektional, 8-32 Leitungen, Datentransport zw. Mikroprozessor und Speicher/Peripherie<br />

• Steuer-Bus (Control-Bus, S-Bus):<br />

Unterschiedliche Übertragungsrichtungen - aber jede Leitung für sich unidirektional, 4-20<br />

Leitungen, Steuerung der Zusammenarbeit der einzelnen Baugruppen<br />

Der Bus ist eine ökonomische Verbindung mehrerer Baugruppen. Es sind flexible Erweiterung und<br />

systematische Verschaltung möglich (Backplane, Bus-Platine). Der Zugang erfolgt über Steckplätze<br />

(Slots). Ein Bus ist aber auch relativ langsam, da keine Parallelarbeit möglich ist und das Fan-Out der<br />

sendenden Komponenten ist begrenzt (u.U. spezielle Pufferbausteine = Bus-Treiber, Bus-Extender<br />

nötig). Es gibt Systeme, bei denen ein Teil des Busses für verschiedene Funktionen mehrfach genutzt<br />

wird Zeitmultiplex-Betrieb (z. B. 8085: Datenbus/LSB Adressbus)<br />

A-Bus Adreßbus<br />

D-Bus Datenbus<br />

S-Bus Steuerbus (Control-Bus)<br />

RAM Random-Access-Memory (Schreib-Lese-Speicher) ROM Read-Only-Memory<br />

(Festwert-Speicher) SIO Serial Input Output PIA Parallel Input Output<br />

Bus-Treiber<br />

Problem bei Bus-Systemen: Es darf immer nur ein einziger Sender am Bus aktiviert sein - alle anderen<br />

Sender müssen abgeschaltet sein.<br />

Aufgaben des Bus-Treibers:<br />

Mikrocomputertechnik<br />

• An-und Abschalten der angeschlossenen Funktionseinheiten am Bus<br />

• Durchschalten der gewünschten Übertragungsrichtung bei bidirektionalen Busanschlüssen<br />

Der System-Bus 24


• Erhöhung des Fan-Out (Anschlußkapazität) eines Busses Bustreiber sind heute in der Regel<br />

Gatter mit Tri-State-Ausgang: Der dritte Zustand (Z-State) ist ein hochohmiger Zustand =<br />

Trennen des Treibers vom Bus. Die Umschaltung des Z-State erfolgt mit einem<br />

Enable-Steuersignal.<br />

Die Ausgänge des Mikroprozessors und der übrigen Bausteine sind i. a. als Tri-State-Ausgänge<br />

ausgeführt direkter Busanschluß möglich. Für Funktionseinheiten ohne Tri-State-Ausgänge und als<br />

Bus-Extender gibt es spezielle Treiber-ICs.<br />

Unidirektionaler Treiber (Buffer, Line Driver) z. B. 74244<br />

Bidirektionaler Treiber (Transceiver) z. B. 74245 (8-fach)<br />

Systembeispiel<br />

Aufzugsteuerung mit Mikroprozessor 6802. Auf dem CPU-Chip sind 128 Byte RAM integriert. Somit<br />

wird extern nur noch E/A und ROM benötigt.<br />

2.2 Mikroprozessor<br />

Mikrocomputertechnik<br />

Zwischenbemerkung: Die Wahl des Prozessors hängt auch von der Anwendung ab (so ist z.B. für<br />

einfache Steuerungen ein 8-Bit-Prozessor vollkommen ausreichend). Die Umstellung des Entwicklers<br />

Bus-Treiber 25


von einem auf den anderen Mikroprozessor ist i.a. nicht allzu schwierig. Im praktischen Teil wird der<br />

8-Bit-Mikroprozessor 6809 verwendet, der sich durch einen einfachen, überschaubaren und<br />

orthogonalen Befehlssatz auszeichnet.<br />

Versorgung und Steuerung<br />

Gruppierung der µP-Anschlüsse:<br />

Die Steuer-Signale dienen zur programmunabhängigen Beeinflussung des Mikroprozessors, z. B.<br />

Reset, Interrupts. Deren Quittungssignale sind teilweise auch dem S-Bus zuzuordnen.<br />

Die Spannungsversorgung erfolgt heute mit + 5V; früher waren of mehrere Spannungen notwendig<br />

(+5V, -5V, +12V).<br />

Der Takt wird entweder mit einem externen Taktgenerator oder intern erzeugt. Normalerweise genügt<br />

ein Quarz, bei einfachen Systemen sogar ein R-C-Glied.<br />

• nicht überlappender Zweiphasentakt (wegen der internen Ablaufsteuerung und des<br />

Rechenwerks)<br />

• Mindestfrequenz darf bei einigen Modellen nicht unterschritten werden (Register sind als<br />

dynamische Speicher realisiert).<br />

Die Taktfrequenz sagt nichts über die tatsächliche Ablaufgeschwindigkeit aus. Bei interner<br />

Takterzeugung ist i.a. nur noch ein externer Quarz nötig. Die Quarzfrequenz beträgt ein Vielfaches der<br />

Taktfrequenz (2 - 18 * Taktfrequenz).<br />

Steuerungs-Signale<br />

Dierser Abschnitt soll einen Überblick der Signale vermitteln. Nicht jeder Mikroprozessor verfügt<br />

über alle genannten Möglichkeiten.<br />

Rücksetzen (Reset)<br />

Mikrocomputertechnik<br />

2.2 Mikroprozessor 26


Herstellen eines definierten Grundzustandes des Prozessors:<br />

• Meist durch fallende Flanke am Reset-Anschluß des Mikroprozessors<br />

• BZ auf definierten Anfangswert setzen (0, festen Wert oder durch Vektor definierten Wert)<br />

• Prozessor startet Befehlszyklus mit diesem Wert<br />

• Interrupts sperren (Freigabe muß durch Programm erfolgen)<br />

• Nicht immer: Rücksetzen der Register<br />

Wichtig: Einschaltverhalten der Mikroprozessor beachten! Reset darf erst erfolgen, nachdem die<br />

Versorgungsspannung eine bestimmte Zeit stabil anliegt (Einschwingzeit des Quarzoszillators).<br />

Warten (Wait, Memory Ready, MRDY, Ready)<br />

Dieser Anschluß dient der Anpassung an langsame Speicher oder E/A-Bausteine. Erreicht wird eine<br />

Verlängerung des Speicherzugriffszyklusses.<br />

• gezielte Verlängerung einzelner Taktphasen (z. B. 6809)<br />

• Einschieben leerer Zyklen (synchron) (80x86, "Wait States")<br />

• Warten auf Fertigmeldung (asynchron) (68000)<br />

Halten (Hold, Halt, Stop)<br />

Anhalten des Programmablaufs nach Beendigung des laufenden Befehls.<br />

• Bus geht in den Tri-State-Zustand<br />

• Mikroprozessor nach außen inaktiv (intern weiter aktiv)<br />

• Anwendungen:<br />

♦ einfache DMA-Möglichkeit<br />

♦ Start/Stop von außen (Test)<br />

♦ Einzelschrittsteuerung<br />

♦ Stop bei bestimmter Adresse<br />

• "Aufwecken" nur durch Reset oder Interrupt<br />

Befehlsunterbrechungen (DMA, BREQ)<br />

Mikrocomputertechnik<br />

Anhalten der Ausführung des aktuellen Befehls nach Beendigung des laufenden Zyklusses - also<br />

mitten im Befehl.<br />

• Bus geht in den Tri-State-Zustand<br />

• Anwendung: DMA<br />

• Nach Beendigung der Unterbrechung wird der unterbrochene Befehl fortgesetzt<br />

Steuerungs-Signale 27


Befehls-Abbruch (Abort)<br />

Abbruch des laufenden Befehls bei virtueller Speichertechnik<br />

• Wegspeichern des Programmstatus<br />

• Seitenwechsel durchführen<br />

• Programmstatus wiederherstellen<br />

• abgebrochenen Befehl neu aufsetzen<br />

Programm-Unterbrechung (Interrupt)<br />

Unterbrechung des laufenden Programms nach Beenden des laufenden Befehls. Ausführen einer<br />

Interrupt-Serviceroutine (ISR).<br />

Arten:<br />

• Abspeichern des Programmstatus<br />

• Setzen BZ auf feste oder vektorisierte Adresse<br />

• Sperren weiterer Interrupts<br />

• Auslösung durch Flanke oder Pegel<br />

• Lokalisierung durch Polling oder HW-Vektor (z.B. bei 8080)<br />

• Abarbeiten der ISR<br />

• Restaurieren des Programmstatus und Fortsetzung des Programms<br />

• bedingter (maskierbarer) Interrupt<br />

• unbedingter Interrupt<br />

2.3 Arbeitsspeicher<br />

Speicher-Bausteine<br />

Als Speicherbausteine werden Halbleiterspeicher verwendet. Folgenden Begriffe dienen zur<br />

Spezifizierung eines Speichers:<br />

• a Adreßbreite<br />

• d Wortbreite<br />

s Speicherkapazität; s = 2a •<br />

• tacc Zugriffszeit<br />

• tcyc Zykluszeit<br />

Anschlüsse:<br />

Mikrocomputertechnik<br />

• CS - Chip Select: Leitung(en) zur Bausteinauswahl<br />

• R/W - Write Enable: Festlegung der Datentransportrichtung 1 = Lesen, 0 = Schreiben<br />

• Adreß- und Datenleitungen<br />

Steuerungs-Signale 28


Organisationsformen:<br />

• d = 1: bitorganisierter Speicher, z.B. 64K x 1<br />

• d > 1: Nibble (d = 4)-, Byte (d = 8)- oder Wort (d = 8, 16, 32, 64)-organisierter Speicher<br />

Zusammenschalten von Speicherbausteinen<br />

Der Gesamtspeicher wird durch Zusammenschaltung von Speicherbausteinen gebildet (sofern nicht<br />

schon ein Baustein ausreicht). Er besteht aus RAM und ROM (PROM, EPROM). Die<br />

Zusammenschaltung kann erfolgen:<br />

• in Wortrichtung (d = Wortbreite des Mikroprozessors)<br />

• in Bitrichtung (d = 1 oder d < Wortbreite des Mikroprozessors)<br />

• gemischt (Wort- und Bitrichtung)<br />

Bei der Zusammenschaltung in Bitrichtung werden alle Bausteine parallel adressiert.<br />

In allen anderen Fälle gilt:<br />

Mikrocomputertechnik<br />

• Zur Wortadressierung innerhalb des Bausteins dient nur ein Teil der Adresse<br />

• Der Rest der Adresse dient zur Bausteinanauswahl:<br />

♦ Uncodierte Bausteinauswahl<br />

♦ Decodierung auf dem Baustein (mehrere CS-Eingänge)<br />

♦ externe Decodierung (nur 1 CS nötig)<br />

♦ Kombination externe/interne Decodierung<br />

Beispiel 1: Zusammenschaltung in Wortrichtung, uncodierte Bausteinauswahl:<br />

Speicher-Bausteine 29


Beispiel 2: Zusammenschaltung in Wortrichtung, codierte Bausteinauswahl, externe Decodierung<br />

Ergänzende Bemerkungen<br />

Ist der Adreßraum des Mikroprozessors breiter als der zur Speicheradressierung eingesetzte Adreßbus,<br />

tritt Mehrfachadressierung auf: Adressen, die sich nur in den unbenutzten höherwertigen Bits<br />

unterscheiden, sprechen die gleiche Speicherzelle an. Dieser Effekt kann erwünscht sein - das<br />

Entwicklungssystem adressiert seinen Daten-Speicher ab $8000, der Steuerungsrechner ab Adresse 0.<br />

Gelegentlich muß noch ein Signal zur zeitlichen Koordination der Speicherzugriffe eingesetzt werden.<br />

Bei ROM-Bausteinen gibt es häufig noch einen Eingang zum Schalten der Ausgänge in den<br />

Tri-State-Zustand (OE=Output Enable).<br />

2.4 Ein-/Ausgabe-Bausteine<br />

Struktur von E/A-Bausteinen<br />

Mikrocomputertechnik<br />

Der E/A-Baustein ist Bindeglied zwischen Prozessor und Peripherie. Seine Aufgaben sind unter<br />

anderem:<br />

Datentransport, zeitliche Anpasung, Signalumsetzung, Pegelumsetzung, Erweiterung der<br />

Belastbarkeit, Datenformat-Anpassung, Codeumsetzung, ...)<br />

Zusammenschalten von Speicherbausteinen 30


Mikrocomputertechnik<br />

Das Einsatzgebiet der E/A-Bausteine reicht von einfacher Byte-orientierter Ein- und Ausgabe bis zur<br />

autonomen Verwaltung komplexer Protokolle, wie z. B. die Netzwerkanbindung. E/A-Komponenten<br />

werdenin der Regel so entworfen, dass sie jeweils einen möglichst großen Bereich von Anwendungen<br />

abdecken. Die Spezialisierung für die Anwendung geschieht durch Initialisierung des Bauteils im<br />

System, ein Vorgang, der in Datenblättern und im allgemeinen Sprachgebrauch "Programmierung"<br />

genannt wird: Nach jedem Einschalten des Systems müssen bestimmte Steuerregister in diesen<br />

Bausteinen von der CPU aus mit bestimmten Werten initialisiert werden.<br />

Bausteine für programmierten E/A-Transfer<br />

Zur bitparallelen Ein/Ausgabe werden von fast jedem Hersteller Bausteine angeboten und nahezu<br />

jeder Controller verfügt über parallele E/A. Verschiedene Bezeichnung sind in Gebrauch:<br />

• PIO Parallel I/0 Interface<br />

• PIA Peripheral Interface Adapter<br />

• PPI Programmable Peripheral Interface usw.<br />

Der Baustein besitzt hierzu Steuerregister, deren Inhalte die Datenrichtung, Bedeutung von<br />

Steuersignalen (Handshake) und das Interruptverhatten festlegen.<br />

Der Zugriff auf die Peripherie erfolgt entweder programmgesteuert (polling) oder interruptgesteuert.<br />

Sie werden am häufigsten verwendet. Auch Bus-Treiber können als sehr einfache E/A-Bausteine<br />

eingesetzt werden. So wurde z. B. die Standard-Druckerschnittstelle des IBM-PC mit zwei<br />

8-Bit-Latches und zwei 8-Bit-Bustreibern realisiert. Kaum komplexer sind auch Speicher-Register mit<br />

nachgeschalteten Leistungstreibern. Sie übernehmen auch die zeitliche Anpassung. Zum Teil sind sie<br />

mit Steuerlogik, Betriebsartenwahl (Ein/Aus) und Interrupt-Auslösung versehen.<br />

Wesentlich flexibler im Einsatz sind programmierbare E/A-Bausteine, wie man sie heute verwendet.<br />

Eigenschaften und Funktion sind per Software einstellbar. Programmierbare Eigenschaften können<br />

sein:<br />

• Datenrichtung<br />

• Übertragungsgeschwindigkeit<br />

• Übertragungsformat<br />

• Paritätsprüfung<br />

• Art des Interrupt-Signals von der Peripherie<br />

• Interrupt-Maske<br />

Diese Bausteine erlauben meist sowohl programmgesteuerten programmierten E/A-Transfer als auch<br />

interruptgesteuerten programmierten E/A-Transfer. Für den einfachen E/A-Transfer gibt es zwei<br />

Bausteine-Grundtypen:<br />

1. Parallele Schnittstelle (Parallel Interface Adapter, Parallel Input Output) Schnittstelle für<br />

parallelen Datenaustausch (z.B. Centronics-Druckerschnittstelle, Relais-Ausgang,<br />

Digital-Analog- und Analog/Digital-Wandler, digitale Eingangssignale). In der Regel sind<br />

mehr als ein 8 Bit breiter "Port" vorhanden (meist 2 bis 4). Steuer- oder Statusregister können<br />

pro Port separat vorhanden sein.<br />

Struktur von E/A-Bausteinen 31


2.<br />

Mikrocomputertechnik<br />

SIA (Serial Interface Adapter, Serial Input Output) Dies ist eine Schnittstelle für bitseriellen<br />

Datenverkehr. Die Bausteine enthalten je einen Parallel-Seriell- und Seriell-Parallel-Wandler<br />

(Schieberegister).<br />

Bei seriellen Schnittstellen kann es sich um einen UART (Universal Asynchronous<br />

Receiver/Transmitter) handeln, wie man ihn von der guten alten seriellen Schnittstelle des PC<br />

her kenn, aber auch um spezielle Schnittstellen für die Kommunikation zwischen einzelnen<br />

ICs, beispielsweise die I 2 C- oder die SPI-Schnittstelle. Generell gilt:<br />

♦ CPU schreibt ein Byte (liegt "parallel" an), die serielle Schnittstelle muss es Bit für<br />

Bit aussenden.<br />

♦ Beim Empfang muss ein Bit nach dem anderen gespeichert und als komplettes Byte<br />

an die CPU geleitet werden.<br />

♦ Festzulegende Parameter: Bit-Geschwindigkeit (Baudrate), Anzahl Stoppbits, Parität,<br />

Steuerleitungen usw.<br />

Der Baustein enthält einen getrennten Sende- und Empfangsteil, sodass Vollduplexbetrieb<br />

möglich ist. Ein USART (Universal Synchronous/Asynchronous Receiver/Transmitter) bietet<br />

neben der asynchronen Betriebsweise auch synchrone Betriebsarten. Im synchronen Betrieb<br />

einer seriellen Übertragung werden Blöcke von Bytes (z. B. Zeichen oder beliebige<br />

Binärinformation) ohne Pausen übertragen. Die Synchronisation zwischen Sender und<br />

Empfänger, die beim asynchronen Betrieb für jedes Zeichen am Empfänger neu hergestellt<br />

werden muss, bleibt im synchronen Betrieb nicht nur während eines Zeichens erhalten,<br />

sondern während eines langen Bitstroms (Datenblock).<br />

Struktur von E/A-Bausteinen 32


Um die Syrichronisation auch dann aufrecht zu erhalten, wenn der Sender nicht schnell genug<br />

weitere Oktets liefern kann, wird solange automatisch ein vorgebbares<br />

Synchronisationszeichen übermittelt damit der serielle Bitstrom nie abreißt. Dadurch werden<br />

Start- und Stopbits überflüssig, was zu höheren effektiven Datenraten führt. Meist wird auch<br />

das Paritätsbit bei jedem Zeichen durch eine CRC-Prüfinfo (CRC = Cyclic Redundancy<br />

Check)am Ende einer ganzen Serie von Zeichen ersetzt, wodurch die Effektivität der<br />

Datenrate und der Fehlersicherung wesentlich erhöht wird.<br />

Daneben existieren noch viele weitere E/A-Bausteine. Sie sind i.a. wesentlich komplexer aufgebaut<br />

und bieten zahlreiche Programmierungsmöglichkeiten. Zum Beispiel:<br />

• Interrupt-Controller: Erweiterung der Interruptmöglichkeiten (Priorisierung,<br />

Vektorgenerierung)<br />

• Programmierbare Zähler (Timer, Counter) Auslösung von Interrupts in regelmäßigen<br />

Zeitabständen Erzeugen von Einzelimpulsen definierter Länge Erzeugung von<br />

Rechteckimpulsen<br />

• spezielle Steuerbausteine Memory Management, Floppy-Disk, Festplatte, Bildschirm,<br />

LC-Display, ...<br />

• Bausteine für DMA-Transfer<br />

Zusammenfassung: Aufgaben einer E/A-Schnittstelle<br />

Die Gesamtheit der Einrichtungen, über welche die CPU mit den peripheren Geräten kommuniziert,<br />

nennt man E/A-Schnittstelle. Im Allgemeinen findet ein (bidirektionaler) Datentransport zwischen<br />

Speicher und Peripherie statt. Neben dem reinen Datentransport ist eine Anpassung der<br />

Datendarstellung zwischen CPU und Peripherie erforderlich = Umsetzung der Bus- auf die<br />

Peripherieschnittstelle: Zeitliche Anpassung (CPU und Peripherie arbeiten i. a. nicht synchron, d. h.<br />

sie sind zeitlich zu entkoppeln).<br />

• Signalumsetzung (z. B. Pegelanpassung)<br />

• Datenformatanpassung (z. B. seriell/parallel-Wandlung)<br />

• Codewandlung<br />

• Fehlererkennung und -korrektur Schnittstellen können von unterschiedlicher Komplexität sein:<br />

• Im einfachsten Fall bestehen sie aus einer oder mehreren einfachen nicht-intelligenten<br />

E/A-Schnittstellen zur rein hardwaremäßigen Anpassung und Umsetzung. Die gesamte<br />

Steuerung des Datentransfers erfolgt durch die CPU programmierter E/A-Transfer.<br />

• Komplexere Schnittstellen können den Datentransfer autonom durchführen. Sie werden von<br />

der CPU nur angestoßen und wickeln den Datentransfer ohne weitere Hilfe der CPU ab<br />

Direkt- Speicher-Zugriff (DMA = Direct Memory Access) ohne Ablauf eigener<br />

Programme.<br />

• Flexiblere und leistungsfähigere Schnittstellen besitzen einen speziellen E/A-Prozessor, der<br />

nach einem Anstoß durch die CPU unabhängig vom (Haupt-)Prozessor mit eigenem<br />

Programm arbeitet und getrennten Zugriff zum Speicher besitzt.<br />

Steuerung von E/A-Bausteinen<br />

Steuersingnale von der CPU:<br />

• Rücksetzen (Reset, RES)<br />

• Freigabe, Aktivierung (Enable, E, CE)<br />

• Baustein-Auswahl (Chip Select, CS)<br />

• Register-Auswahl (Register Select, RS)<br />

• Datenrichtung (Read/Write, R/W)<br />

Mikrocomputertechnik<br />

Struktur von E/A-Bausteinen 33


Steuersignale von der Peripherie:<br />

• Interruptleitungen (Erzeugung IRQ-Signal für CPU)<br />

• weitere Steuersignale (z.B. Handshakeleitungen bei SIA)<br />

Steuerleitungen vom E/A-Baustein zur CPU:<br />

• Interrupt-Anforderung (Interr. Request, IRQ)<br />

• Weitergabe des IRQ von der Peripherie zur CPU (Maskierungsmöglichkeit)<br />

• Erzeugung eines IRQ-Signals durch E/A-Baustein selbst<br />

Anschluß von E/A-Bausteinen<br />

Mikrocomputertechnik<br />

Die Steuersignale werden mit dem Steuer-Bus verbunden. Aus dem Adreß-Bus werden die<br />

Cchip-Select- und Register-Select-Signale abgeleitet. Normalerweise werden die RS-Signale mit<br />

den niederwerigen Adreßleitungen verbunden (RS 0 mit A 0 , RS 1 mit A 1 , usw.). Über den Daten-Bus<br />

erfolgt der eigentliche Datenaustausch.<br />

Da i. a. mehrere E/A-Bausteine (mit mehreren Registern) an ein System angeschlossen werden, ist<br />

eine Adressierung der E/A-Bausteine nötig. Es gibt dafür zwei Methoden:<br />

1. Getrennte Adressierung (Isolated I/O, I/O-Mapped I/O)<br />

Der Rechner verfügt über spezielle E/A-Befehle und einen eigenen E/A-Adreßraum. Die<br />

E/A-Adresse wird oft auch Port genannt. Sie wird entweder auf separaten Adressleitungen<br />

zu den Schnittstellen geführt oder über den normalen Adreßbus geleitet. In diesem Fall gibt<br />

es (eine) zusätzliche Steuerleitung(en) zur Unterscheidung zwischen E/A- und<br />

Speicheradressen. Da i.a. der E/A-Adreßraum kleiner als der Speicheradreßraum ist, wird<br />

nur ein Teil der A-Bus-Leitungen verwendet (z. B. 8080/8085: 8 Bit, 80386: 10 Bit).<br />

2. Speicheradressierung (Memory Mapped I/O)<br />

Der E/A-Adreßraum wird in den Speicher-Adreßraum abgebildet, d.h. bestimmte Adressen<br />

stellen keine Speicheradressen, sondern E/A-Adressen dar geringfügige Einschränkung<br />

des Speicheradreßraums. Die E/A-Adressen werden von der CPU genauso behandelt und<br />

angesprochen, wie Speicheradressen. E/A-Operationen werden mit den normalen<br />

Transportbefehlen durchgeführt (z. B. Load, Store) Einsparung zusätzlichen Aufwandes<br />

für Adreß-/Steuerleitungen und für spezielle E/A-Befehle.<br />

Steuerung von E/A-Bausteinen 34


Programmgesteuerter E/A-Transfer (Polling)<br />

Einfache E/A-Schnittstellen für programmierten E/A-Transfer bestehen wesentlich aus:<br />

• E/A-Datenregister (EADR)<br />

• E/A-Steuer- und Statusregister (EASR)<br />

• Adreß- und Steuerlogik<br />

Mikrocomputertechnik<br />

Sie ist normalerweise an den Systembus der CPU angeschlossen. Das EADR dient zur<br />

Zwischenspeicherung des zu übertragenden Datenwerts (zeitliche Anpassung). Neben den zu<br />

übertragenden Daten braucht die Schnittstelle Signale zur richtigen Abwicklung des Datentransfers:<br />

• Statussignale von der Peripherie<br />

z. B. Anzeige, dass das Peripheriegerät einen neuen Wert ins EADR geliefert hat oder bereit<br />

ist, den nächsten Wert zu übernehmen.<br />

• Steuersignale zur Peripherie<br />

z. B. Anzeige, dass der vorhergehende Datenwert gelesen wurde und die Peripherie einen<br />

neuen Wert ins EADR einschreiben kann.<br />

• Steuersignale zur Schnittstelle selbst<br />

z. B. Signale zum Einstellen bestimmter Betriebsmodi bei programmierbaren Schnittstellen.<br />

Diese Signale werden - soweit sie für längere Zeit zur Verfügung stehen müssen - im EASR<br />

gespeichert. Das EASR kann auch aus separaten Registern für Status- und Steuersignale bestehen.<br />

Normalerweise verfügt ein Computer über mehr als eine E/A-Schnittstellen Adressierung<br />

erforderlich. Im allgemeinen erhalten EADR und EASR eine eigene, separate Adresse. Beide sind<br />

am Datenbus angeschlossen. Steuersignale werden wie Datenwerte ins EASR geschrieben,<br />

Statussignale werden wie Datenworte aus dem EASR gelesen - die Verarbeitung muss in der CPU<br />

durch geeignete Befehle erfolgen (z.B. logische Verknüpfung).<br />

Anschluß von E/A-Bausteinen 35


Die E/A-Befehlsfolge steht innerhalb eines Programms und wird im Rahmen der normalen<br />

Programmausführung abgearbeitet. Die gesamte Initiative zur E/A geht vom Programm aus. Zeigt<br />

der Inhalt des EASR an, dass keine neuen Daten im EADR stehen, muss das Programm erneut das<br />

EASR abfragen Warteschleife, "Polling". Dabei können zwei "Randbereiche" Probleme<br />

verursachen:<br />

• Die Zeit, die das Programm braucht, um einen Eingabewert zu bearbeiten ist manchmal<br />

(oder sogar immer) länger als die Zeitspanne innerhalb der sich das Eingangssignal ändern<br />

kann es werden Ereignisse "übersehen".<br />

• Bei "langsamen" Peripheriegeräten ist der Computer während der Übertragung eines<br />

Datenblocks die meiste Zeit mit Abfragen bschäftigt, die in den meisten Fällen negativ<br />

ausfallen.<br />

Direktspeicherzugriff (DMA = Direct Memory Access)<br />

Beim DMA steuert die E/A-Schnittstelle den Transfer nach Anstoß durch die CPU selbstständig<br />

und ohne Zuhilfenahme der CPU Datentransport zwischen Speicher und Peripherie unter<br />

Umgehung der CPU. Selbst, wen die CPU in dieser Zeit nichts anderes tut, ist ein wesentlich<br />

schnellerer Datentransport möglich (weitgehender Wegfall der Verwaltungsarbeit). Daher ist DMA<br />

für den schnellen Transfer großer Datenmengen besonders geeignet. Zum Anstoßen des<br />

DMA-Transfers übermittelt die CPU der DMA-Schnittstelle:<br />

• die Anfangsadresse (im Arbeitsspeicher) des zu übertragenden Datenblocks<br />

• die Länge des zu übertragenden Datenblocks<br />

• Gegebenenfalls muss noch - wie beim programmierten Transfer - das EASR entsprechend<br />

geladen werden Initialisierung der Schnittstelle.<br />

Die DMA-Schnittstelle benötigt zwei weitere Register:<br />

• E/A-Adreßregister (EAAR)<br />

• E/A-Blocklängenzähler (EAZR)<br />

Mikrocomputertechnik<br />

Programmgesteuerter E/A-Transfer (Polling) 36


Da während des DMA-Transfers anstelle der CPU die DMA-Schnittstelle die Kontrolle über den<br />

Systembus besitzt, muss sie zusätzlich über eine Bus-Steuerlogik verfügen (Konkurrenz zwischen<br />

DMA Schnittstelle und CPU um den Bus).<br />

Ablauf eines DMA-Transfers:<br />

• Initialisieren der DMA-Schnittstelle<br />

• Bus-Freigabe-Anforderung an die CPU (DMA-Request)<br />

• CPU bestätigt Bus-Freigabe (DMA-Acknowledge) (Die Bus-Freigabe der CPU geschieht<br />

durch Umschalten der Bustreiber-Ausgänge in den hochohmigen Zustand)<br />

• Nun bedient die DMA-Schnittstelle den Adreß-, Daten- und Steuerbus auf die gleiche Art<br />

und Weise, wie die CPU. Der Inhalt des EAAR wird an den A-Bus gelegt und die für die<br />

Speichersteuerung notwendigen Signale auf den Steuerbus. Das EADR wird mit dem<br />

Datenbus verbunden.<br />

Man unterscheidet verschiedene DMA-Modi:<br />

• Byteweise Übertragung (Byte Mode)<br />

Die CPU gibt auf DMA-Request hin den Bus nach Beendigung des gerade laufenden<br />

Maschinenzyklus frei. Nach dem Transfer eines Datenwortes erhält die CPU die Kontrolle<br />

über den Bus zurück und sie setzt den laufenden Befehl weiter fort (bis zum nächsten<br />

DMA-Request) Cycle Stealing.<br />

• Burst-Modus<br />

Auch hier wird die CPU mitten in der Bearbeitung eines Befehls kurz angehalten, jedoch<br />

für mehrere Zyklen Transfer eines ganzen Datenblocks.<br />

• Halt-Modus<br />

Die CPU wird nach Beendigung der gerade laufenden Instruktion angehalten - solange, bis<br />

der DMA-Transfer eines ganzen Blocks abgewickelt ist.<br />

• Transparent-Modus<br />

DMA-Schnittstelle und CPU arbeiten zeitmultiplex während jedes Maschinenzyklus jeweils<br />

in einer halben Periode. Dazu ist ein sehr schneller Speicher erforderlich keine<br />

Beeinträchtigung der CPU.<br />

2.5 Timer (Zeitgeber)<br />

Mikrocomputertechnik<br />

Zur Gruppe der Port-Level-Controller gehören auch die sehr häufig eingesetzten Zähler- und<br />

Zeitgeber-Bausteine. Da in den meisten Systemen Impulse gezählt oder erzeugt werden bzw. die<br />

Dauer von Impulsen gemessen werden muss, stellt es eine große Entlastung der CPU dar, wenn<br />

diese Vorgänge nicht per Programm gesteuert, sondern durch zusätzliche Hardware unterstützt<br />

werden.<br />

Ein Timer besteht aus einem programmierbaren (voreinstellbaren) Rückwärts-Zähler mit eigenem,<br />

vom Prozessor unabhängigen, Takt. Der Takt kann über Steuerregister freigegeben bzw. gesperrt<br />

werden. Der aktuelle Zählerstand kann jederzeit von der CPU ausgelessen werden. Bei Zählerstand<br />

0 wird ein maskierbarer Interrupt erzeugt. Der Timer hat in der Regel mehrere Modi:<br />

Direktspeicherzugriff (DMA = Direct Memory Access) 37


• Rechteckgenerator bzw. Zähler: Beim Erreichen des Zählerstandes 0 wird ein Interrupt<br />

erzeugt und automatisch wieder der Startwert geladen. Somit erfolgt ein Interrupt in<br />

regelmäßigen Zeitabständen.<br />

• Monoflop, One-Shot: Nach Erreichen des Zählerstandes 0 wird ein Interrupt erzeugt und<br />

dann bleibt der Timer inaktiv, bis wieder ein Startwert geladen wird. Typische<br />

Anwendungen dieser Monoflops sind auch Programmüberwachungen (Watchdog) in<br />

Systemen mit einer Endlos-Programmschleife, die zyklisch durchlaufen wird: Ein Befehl<br />

innerhalb dieser Schleife triggert das Monoflop nach; geschieht das nicht mehr, so hat sich<br />

das Programm "aufgehängt" und das System würde fehlerhaft arbeiten. Das Abfallen des<br />

Monoflops signalisiert jedoch per Interrupt den Fehler. Gegebenenfalls kann man einen<br />

Neustart des Systems (Reset) auslösen.<br />

• Frequenz- oder Periodendauermessung: Der Interrupt erfolgt, wenn die Freqenz bzw.<br />

Periodendauer eines an einem externen Eingang angelegten Signals länger dauert, als die<br />

Timerperiode. Durch Variation des Startwertes kann die Frequenz bzw. Periodendauer<br />

gemessen werden.<br />

• Rechtecksignal mit variablem Tastverhältnis<br />

• Verzögerter Impuls softwaregetriggert<br />

• Verzögerter Impuls hardwaregetriggert<br />

• und andere ...<br />

Anwendungen:<br />

• Erzeugen von Interrupts in festen Zeitabständen<br />

• Rechteckgenerator mit programmierbarer Frequenz<br />

• Monoflop mit programmierbarer Zeit<br />

• Pulsweiten-Modulation<br />

• "Watch-Dog" (Reseterzeugung, wenn nicht regelmäßig per Software nachgetriggert wird<br />

automatisches Rücksetzen bei Störungen)<br />

2.6 Systemkonfigurationen<br />

Dieses Kapitel zeigt die Zusammenschaltung von Speicher (RAM, ROM) und E/A-Bausteinen zu<br />

einem Mikrocomputer-System. Die zeitliche Koordination wied hier nicht behandelt (da von<br />

Prozessor zu Prozessor verschieden).<br />

Aufteilung des Adreßraums<br />

Mikrocomputertechnik<br />

Hierbei geht es um die Zuordnung verschiedener Speicher- und E/A-Bereiche zu den Adressen.<br />

Man unterscheidet:<br />

• Voll-Decodierung<br />

Die Adressierung jedes Bausteins wird unter Verwendung aller Adreßleitungen decodiert.<br />

2.5 Timer (Zeitgeber) 38


•<br />

Weitere Bausteine sind problemlos zuschaltbar.<br />

Vorteil: Adreßraum nur soweit nötig gebraucht, Erweiterung problemlos<br />

Nachteil: Mehr Hardware nötig<br />

Minimaldecodierung:<br />

Es wird nur eine Minimalzahl von Adreßleitungen ausgewertet. Der Speicher und die<br />

E/A-Schnittstellen erscheinen mehrmals unter verschiedenen Adressen.<br />

Vorteil: Minimaler Schaltungsaufwand<br />

Nachteil: Adreßraum wird vollständig verbraucht<br />

In der Praxis finden sich häufig Mischformen (Teildecodierung), d. h. es wird nur soweit decodiert,<br />

daß alle Bausteine einen eigenen Adreßraum besitzen - also eindeutig ansprechbar sind. Dabei kann<br />

es durchaus sein, daß ein Baustein unter mehreren Adressen ansprechbar ist Bauteileersparnis<br />

beim Decodieren.<br />

Oft erfolgt die Vergabe bestimmter Bereiche für bestimmte Gruppen von Bausteinen, z. B. ROM: 0<br />

- $7FFF, RAM: $8000 - $8FFF, E/A: F000 - FFFF.<br />

Die Vergabe ist vom Prozessor abhängig (8080: ROM bei 0, 6800: ROM bei $FFFF wegen<br />

Reset-Vektor). In letzteren Fall kann man durch Teildecodierung erreichen, daß das ROM sowohl<br />

bei 0, als auch bei $FFFF adressierbar ist.<br />

Systembeispiel<br />

Minimalsystem mit 6802:<br />

Mikrocomputertechnik<br />

• Prozessor 6802 (mit 128 Byte RAM)<br />

• EPROM 2732 als Programmspeicher (4K x 8)<br />

• PIA 6821 als E/A-Baustein<br />

• Adreßraum:<br />

♦ RAM: $0000 - $007F<br />

♦ ROM: $F000 - $FFFF<br />

♦ PIO: $0080 - $0083 (memory mapped I/O)<br />

Aufteilung des Adreßraums 39


Beispiele zur Systemkonfiguration<br />

1. Volldecodierung:<br />

Prozessor mit eingebautem RAM<br />

CS vom ROM active low!<br />

2. Volldecodierung, erweitert<br />

CS von ROM und RAM active low!<br />

3. Minimaldecodierung<br />

CS vom ROM und PIO active low!<br />

Mikrocomputertechnik<br />

Beispiele zur Systemkonfiguration 40


Adressierung modulo $1000!<br />

ROM erscheint bei $0000, $1000, $2000, ..., $D000, $E000, $F000<br />

4. Minimaldecodierung ROM und E/A<br />

Mikrocomputertechnik<br />

Adressierung modulo $1000!<br />

ROM erscheint bei $0000, $1000, $2000, ..., $7000<br />

PIO erscheint bei $8000, $8004, $8008, ..., $FFFF<br />

5. Teildecodierung (Volldecodierung mit Lücken)<br />

µP, D− und S−Bus aus Platzgründen weggelassen!<br />

CS active low!<br />

Beispiele zur Systemkonfiguration 41


Mikrocomputertechnik<br />

RAM erscheint bei $0000, $4000, usw.<br />

ROM erscheint bei $1000, $5000, usw.<br />

PIO 1 belegt den gesamten Bereich $2000 - $2FFF, $6000 - $6FFF, usw.<br />

PIO 2 belegt den gesamten Bereich $3000 - $3FFF, $7000 - $7FFF, usw.<br />

2.7 Programmunterbrechungen<br />

Programmunterbrechungen können durch Signale aus der Rechnerumgebung (z.B. vom gesteuerten<br />

Prozeß) ausgelöst werden, um quasi "die Aufmerksamkeit" des Rechners auf sich zu lenken.<br />

Insbesondere auf dringende, aber relativ selten auftretende Ereignisse können so die entsprechenden<br />

Programme (Interrupt Service Routinen) schnell reagieren.<br />

In der Regel führt die Ablaufsteuerung nach der Beendigung des gerade ausgeführten Befehls die<br />

Programmunterbrechung durch und setzt nach der Abarbeitung der Interrupt Service Routine (ISR)<br />

das unterbrochene Programm fort.<br />

Die Aufgaben der Interruptbehandlung im einzelnen:<br />

a. Aufnehmen und Überprüfen der Unterbrechungsanforderung:<br />

Im einfachsten Fall hat das Unterbrechungswerk nur eine einzige Eingangsleitung für die<br />

Unterbrechungsanforderungen. Diese führt auf ein Flip-Flop, das durch ein<br />

Anforderungssignal auf 1 gesetzt wird und bei Bedienung des Interrupts sofort wieder<br />

gelöscht werden muß um evtl. weitere Interrupt-Anforderungen aufnehmen zu können.<br />

Dieses FF ist notwendig, um die zu beliebigen Zeitpunkten ankommenden<br />

2.7 Programmunterbrechungen 42


.<br />

Mikrocomputertechnik<br />

Interrupt-Anforderungen (Interrupt-Request) so lange zu speichern, bis sie vom Leitwerk<br />

am Ende der Befehlszyklen abgefragt werden.<br />

Häufig darf jedoch eine Interrupt-Anforderung nicht sofort zur Unterbrechung führen, z.B.<br />

während der Ausführung zeitkritischer Programmabschnitte. Eine einfache Möglichkeit<br />

besteht in der "Maskierung" des Signals mit Hilfe eines Masken-FF's und eines Gatters. Nur<br />

wenn das Masken-FF gesetzt ist, führt eine "anstehende" Unterbrechungsanforderung auch<br />

zu einem Interrupt. Das Masken-FF kann i.a. durch Maschinenbefehle gesetzt und gelöscht<br />

werden ("enable" bzw. "disable interrupt").<br />

Identifizierung des Interrupt-Verursachers:<br />

Typische Anwendungen mit mehreren Quellen für Interrupt-Anforderungen verlangen, daß<br />

für jedes Signal auch ein spezifisches Unterbrechungs-Bearbeitungs-Programm (ISR =<br />

Interrupt Service Routine) vorhanden ist, da ja auf jedes Signal anders zu reagieren ist.<br />

Damit ergibt sich das Problem der Interrupt-Identifizierung als Voraussetzung für die<br />

Zuordnung der richtigen ISR und für das Löschen des richtigen<br />

Interrupt-Anforderungs-Flip-Flops.<br />

Die beiden wichtigsten Grundprinzipien der Interrupt-Identifizierung sind:<br />

♦ Polling: Der Interrupt-Verursacher kann sich nicht selbst zu erkennen geben; am<br />

Prozessor erscheint lediglich das Anforderungssignal und es ist die Aufgabe des<br />

Interrupt-Bearbeitungs-Programms, über eine Kette von Abfragen an die in Frage<br />

kommenden Peripherie-Bausteine, den aktuellen Interrupt-Verursacher<br />

herauszufinden. Mit "Abfragen" ist hier das Lesen der Statusregister der<br />

Peripheriebausteine gemeint, in denen die Tatsache der Interrupt-Anforderung<br />

jeweils in einem bestimmten gesetzten Bit (Interrupt-Request-Bit) vermerkt ist.<br />

♦ Interrupt-Vectoring: Der Interruptverursacher liefert (im Zuge der Bussequenzen<br />

bei der Interrupt-Annahme durch den Prozessor) einen "Kenn-Code" mit ab (meist<br />

über den Datenbus), an dem der Prozessor erkennen kann, um welchen Interrupt es<br />

sich handelt. Dieser sogen. "Interrupt-Vektor" wird i.a. gleich als (indirekte)<br />

Startadresse der zugehörigen ISR verwendet. Damit entfällt das zeitraubende<br />

Abfragen, die sogenannte Interrupt-Reaktionszeit wird kürzer.<br />

c. Vorrangsteuerung der Interruptverursacher:<br />

Nicht alle Interrupts sind mit der gleichen Dringlichkeit zu bearbeiten; so muß z.B. die<br />

Interrupt-Anforderung, die den Zusammenbruch der Netzspannung anzeigt, vorrangig<br />

behandelt werden gegenüber einer Interrupt-Anforderung, die lediglich zur Übernahme<br />

eines Datenwortes von einer Eingabeschnittstelle auffordert.<br />

d. Retten und Rückspeichern des Prozessorzustandes:<br />

Wenn eine Programmunterbrechung ausgeführt werden soll, so muß auf jeden Fall der<br />

Zustand des Prozessors gerettet werden. Denn das Interrupt-Service-Programm benutzt ja<br />

ebenfalls den Prozessor und verändert dabei dessen Zustand. Soll anschließend das<br />

unterbrochene Programm fortgesetzt werden, so ist es unbedingt nötig, vorher den Zustand<br />

wieder herzustellen, wie er bei Auftreten der Unterbrechung herrschte. Die<br />

Prozessorzustände, die während einer Befehlsausführung durchlaufen werden, sind nur sehr<br />

aufwendig zu beschreiben (z. B. mitten in einer Multiplikation). Entsprechend groß wäre<br />

der Aufwand zur Rettung des Prozessorzustandes, wenn man Unterbrechungen mitten im<br />

Befehlszyklus zuließe. Man läßt deshalb Unterbrechungen i. a. nur am Ende eines Befehls<br />

2.7 Programmunterbrechungen 43


Mikrocomputertechnik<br />

zu, denn dann ist der Prozessorzustand vollständig durch den Inhalt der Prozessorregister<br />

definiert.<br />

In einer typischen Interrupt-Service-Routine werden die Inhalte von Prozessor-Registern<br />

verändert. Aber selbst wenn keine derartigen Befehle in der ISR vorkommen, so müssen<br />

doch zumindest zwei Register gerettet werden: der Programmzähler und das<br />

Prozessor-Status-Register, denn die Inhalte dieser Register ändern sich in jedem Fall. Man<br />

bezeichnet diese beiden Register auch als "Zustandsvektor". Die einfachste Möglichkeit,<br />

den Zustandsvektor zu retten, besteht darin, ihn in bestimmte reservierte Speicherzellen zu<br />

schreiben, und ihn von dort nach Beendigung der ISR wieder zu lesen. Dies hat den<br />

offensichtlichen Nachteil, daß keine Verschachtelung (Nesting) von<br />

Programmunterbrechungen möglich ist, d.h. man müßte das Unterbrechen einer ISR<br />

verbieten, weil sonst der gerettete Zustandsvektor überschrieben würde.<br />

Wesentlich besser eignet sich zum Retten des Zustandsvektors ein sogenannter<br />

Kellerspeicher (engl. stack, oder auch LIFO = last in first out). Das Stackprinzip kann<br />

hardwaremäßig realisiert sein (spezielle Chips) oder in einem reservierten Bereich des<br />

normalen Arbeitsspeichers nachgebildet sein. Zu diesem Zweck existiert ein Zeigerregister,<br />

das immer den letzten Eintrag im Stack adressiert (Stackpointer zeigt immer auf den "Top<br />

of Stack", d.h. auf den letzten Eintrag).<br />

Mit jeder neuen (geschachtelten) Programmunterbrechung wächst der Kellerspeicher um<br />

die entsprechenden Einträge, mit jedem Rücksprung in ein vorher unterbrochenes<br />

Programm reduziert er sich wieder entsprechend, so daß das zuletzt unterbrochene<br />

Programm nach Beendigung des laufenden wieder aufgenommen wird. Der Stack wächst<br />

und schrumpft mit jedem Eintreten/Verlassen von ISRs, man sagt, der Stack "pulsiert".<br />

Häufig müssen außer den beiden o.g. Registern (PC und Prozessor-Status-Register) auch<br />

noch andere gerettet und rückgespeichert werden, nämlich dann, wenn sie von der ISR<br />

verändert werden. Auch hier bringt die Verwendung eines Stacks die gleichen Vorteile wie<br />

oben erwähnt. Da diese Register jedoch nicht immer gerettet werden müssen besteht hier<br />

die Möglichkeit, sie entweder genau wie den Zustandsvektor per Hardware (d.h. per<br />

Ablaufsteuerung) zu retten oder per Maschinenbefehl(e), also programmgesteuert.<br />

Während bei der Hardware-Lösung sämtliche Register gerettet werden müssen (sie "weiß"<br />

je nicht, welche es sein müssen), kann die programmierte Lösung sich auf genau die<br />

Register beschränken, die in der ISR verändert werden (der Programmierer weiß welche -<br />

hoffentlich!). Die sicherere und meist auch schnellere, jedoch auch aufwendigere Methode<br />

ist die Hardware-Lösung.<br />

Die Notwendigkeit, bei der Ausführung einer Programmunterbrechung zunächst den Zustand des<br />

unterbrochenen Programms zu retten, kann also eine Reihe von Transportoperationen benötigen;<br />

vom Moment des Eintreffens der Unterbrechnungsanforderung vergeht daher einige Zeit, die<br />

Interrupt-Reaktionszeit, bis der erste produktive Befehl der ISR ausgeführt wird. Diese<br />

Reaktionszeit setzt sich aus den folgenden Komponenten zusammen:<br />

• T1: Durchschaltezeit (der Anforderung bis zur Unterbrechungsanmeldung) aufgrund einer<br />

gesetzten Sperre (z.B. auch dann, wenn gerade eine Interrupt-Service-Routine bearbeitet<br />

wird). Diese Zeit kann u.U. recht lang sein!<br />

• T2: Wartezeit bis zur Beendigung des gerade ausgeführten Befehls (maximal die des<br />

längsten vorkommenden Befehls)<br />

• T3: Zeit zum Retten des Programm-Zustandes und Laden des Unterbrechungs-Vektors.<br />

Selbst wenn die Durchschaltung der Anforderung unmittelbar erfolgt (T1 = 0, weil keine<br />

Sperre gesetzt ist), kann die Summe von T2 und T3 für zeitkritische Echtzeitanforderungen<br />

doch noch zu groß sein.<br />

2.7 Programmunterbrechungen 44


Mikrocomputertechnik<br />

Unterbrechungsgesteuerter E/A-Transfer<br />

Die E/A-Befehlsfolge wird durch einen von der E/A-Schnittstelle ausgelösten Interrupt gestartet.<br />

Der Interrupt wird von der Schnittstelle abgesetzt, wenn ein Datenwort empfangen wurde und im<br />

EADR steht (bzw. wenn ein Datenwort aus dem EADR abgeholt wurde). Die CPU braucht nicht in<br />

einer Programmschleife zu warten, sondern kann in der Zwischenzeit ein anderes Programm<br />

bearbeiten, das durch den Interrupt kurzzeitig unterbrochen wird. Der interruptgesteuerte Transfer<br />

gestattet zudem die quasi-simultane Bedienung mehrerer langsamer Schnittstellen. Zur Realisierung<br />

muß eine Interrupt-Leitung von der E/A-Schnittstelle (EASR) zum Unterbrechungswerk der CPU<br />

vorhanden sein.<br />

Vorteil des programmierten Transfers: Sehr einfache Schnittstellen, die übersichtlich und leicht zu<br />

verwenden sind.<br />

Nachteil des programmierten Transfers: Für den Transfer jedes einzelnen Datenworts wird die CPU<br />

benötigt. Diese muss dabei relativ viel Verwaltungsaufwand leisten (Laden/lesen EASR,<br />

Interrupt-Behandlung) die maximale Datenrate ist sehr begrenzt.<br />

Durch den Interupt wird auch der Befehlszyklus erweitert. Nach Abarbeitung des Befehls wird das<br />

Vorhandensein eines Interrupts geprüft und ggebenenfalls in die Interrupt-Serviceroutine (ISR)<br />

verzweigt. Dabei werden alle Register auf dem Stack abgelegt und beim Beenden der ISR wieder<br />

restauriert.<br />

Unterbrechungsgesteuerter E/A-Transfer 45


Man unterscheidet bei der Adressangabe für die ISR zwei Möglichkeiten:<br />

• vektorisierter Interrupt: Es kann der ISR eine beliebige Adresse zugeordnet werden,<br />

welche von der CPU eingelesen wird.<br />

• nicht vektorisierter Interrupt: Der ISR wird eine feste Startadresse zugeordnet.<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 07. Okt 2012<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Unterbrechungsgesteuerter E/A-Transfer 46


3. Programmierung des Mikroprozessors<br />

68HC11<br />

3.1 Überblick<br />

Programmiermodell<br />

Da man wohl kaum einen Schaltplan des CPU-Herstellers bekommt und da dieser auch viel zu<br />

komplex ist, wird für die Programmierung mit dem sogenannten "Programmiermodell" gearbeitet.<br />

Dies umfaßt:<br />

• Die Gesamtheit der dem Programmierer zugänglichen Register der CPU<br />

• Die Gesamtheit der vom Programmierer veränderbaren Register der CPU<br />

Der Prozessor 68HC11 ist eine Weiterentwicklung des 6800 (weitgehend befehlskompatibel,<br />

erweiterter Befehlssatz, zusätzliche Register). Der 68HC11 besitzt vier 8-Bit-Register und fünf<br />

16-Bit-Register:<br />

• 2 Akkumulatoren A und B (8 Bit)<br />

♦ Zusammenfassung von A und B zum 16-Bit-Akku D (A: MSB, B: LSB)<br />

16-Bit-Instruktionen<br />

♦ Beide Akkumulatoren werden gleich behandelt<br />

♦ Zwei Akkus Vorteile bei der Programmierung (z. B. bei Schleife: A zum Rechnen,<br />

B als Schleifenzähler)<br />

• Program Counter PC (Befehlszähler, 16 Bit) 64 K Adreßraum<br />

• Stackpointer S<br />

Für Unterprogrammsprünge, Prozessor-Status bei Interrupt Der Stackpointer kann auch als<br />

Index-Register verwendet werden<br />

• 2 Indexregister X und Y (16 Bit)<br />

3. Programmierung des Mikroprozessors 68HC11 47


♦ Für indizierte Adressierung<br />

♦ Beide sind gleichwertig (Abarbeitung mit X etwas schneller als mit Y)<br />

• Condition Code Register CC (8 Bit) Statusregister (3 Bit für Stop/Interrupt-Verarbeitung, 5<br />

Bit für ALU)<br />

♦ Jedes Bit wirkt wie ein Flip-Flop (1 = gesetzt, 0 = rückges.)<br />

♦ Welche Bits (= Flags) von den einzelnen Befehlen auf welche Art beeinflusst werden,<br />

ist in der Befehlsliste angegeben.<br />

♦ Ein Flag bleibt solange unverändert, bis ein Befehl ausgeführt wird, der es beeinflusst.<br />

♦ Jedes Bit des CC kann per Befehl gezielt gesetzt/rückgesetzt werden<br />

♦ Die Bedeutung der Bits:<br />

C: Carry-Flag<br />

1, wenn bei arithmetischen Operationen ein Übertrag vom höchstwertigen Bit<br />

auftritt (bei Subtraktion: wenn "geborgt" wird). Wird ausserdem durch<br />

Schiebe- und Rotationsbefehle beeinflußt.<br />

V: Overflow-Flag<br />

1, wenn ein Arithmetik-Überlauf (Zahlenbereichsüberschreitung) auftritt.<br />

Dies tritt nur bei konegativen Zahlen auf und ist dann der Fall, wenn bei<br />

Addition oder Subtraktion die beiden Operanden das gleiche Vorzeichen<br />

besitzen und das Vorzeichen des Ergebnisses davon verschieden ist.<br />

Z: Zero-Flag<br />

1, wenn das Ergebnis einer Operation das Ergebnis Null hat.<br />

N: Negativ-Flag<br />

1, wenn das Ergebnis einer Operation negativ ist. Das N-Bit ist gleich dem<br />

höchstwertigen Bit des Ergebnisses.<br />

H: Half-Carry-Flag<br />

1, wenn bei einer 8-Bit-Operation ein Übertrag von Bit 3 nach Bit 4 auftritt.<br />

I: Interrupt Mask<br />

Falls 1, werden Interrupt-Anforderungen auf der IRQ-Leitung nicht bedient<br />

(Freigabe des IRQ I-Bit auf 0 setzen). Bleibt solange gesperrt, solange der<br />

Stackpointer nicht initialisiert wurde.<br />

X: Non Maskable Interrupt Mask<br />

Falls 1, werden Interrupt-Anforderungen auf der NMI-Leitung nicht bedient.<br />

Eigentlich ein Paradox, denn der NMI sollte ja gerade nicht maskierbar sein.<br />

Der NMI wird jedoch gesperrt, wenn der Stackpointer noch nicht initialisiert<br />

wurde und wenn gerade die NMI-Interrupt-Serviceroutine abgearbeitet wird.<br />

S: Stop disable<br />

1, wenn der STOP-Befehl nicht ausgeführt werden soll.<br />

Einteilung der Befehle<br />

Mikrocomputertechnik<br />

Programmiermodell 48


Der 68HC11 kennt 59 verschiedene Grundbefehle überschaubarer Befehlssatz. Anwendung der<br />

Befehle mit unterschiedlichen Registern und Adressierungsarten führt zu 1464 verschiedenen<br />

OP-Codes. Der OP-Code besteht (einschließlich Angabe über Adressierungart) aus einem, zwei oder<br />

drei Bytes: Der Adreßteil (falls vorhanden) besteht aus einem oder zwei Bytes; es gibt also 1-, 2-, 3-,<br />

4- und 5-Byte-Befehle. Das Befehlsformat kann also sein:<br />

Das "prebyte" erweitert den Befehlsumfang, so daß mehr als 256 Befehle möglich sind. Der Nachteil<br />

dabei ist, daß die Abarbeitung des Befehls länger dauert und der Befehl natürlich auch ein Byte mehr<br />

an Speicher braucht.<br />

Adressen werden in zwei aufeinanderfolgenden Speicherbytes abgelegt und zwar in der Form<br />

AH AL<br />

ea ea+1<br />

Mit "ea" wird die effektive Adresse = echte Adresse = Adresse des Operanden im Speicher<br />

bezeichnet. Je nach Adressierungsart (siehe unten) ist eine Adreßberechnung notwendig. Das Ergebnis<br />

der Adreßrechnung landet im Adreßregister und wird dann zur Adressierung des Speichers verwendet.<br />

Befehlsklassen:<br />

• Verarbeitungsbefehle<br />

♦ Transportbefehle<br />

♦ arithmetische Befehle<br />

♦ logische Befehle<br />

♦ Schiebe- und Rotations-Befehle<br />

• Steuerbefehle<br />

♦ Testbefehle (beeinflussen CC-Register)<br />

♦ Sprungbefehle<br />

♦ Unterbrechungsbefehle<br />

♦ Befehle zur Beeinflussung des Systemzustands<br />

Angaben über gültige Adressierungsarten, Länge, CC-Beeinflussung, Dauer (Anzahl der Taktzyklen)<br />

stehen in der Befehlstabelle.<br />

3.2 Adressierungsarten<br />

Mikrocomputertechnik<br />

Einteilung der Befehle 49


Die meisten Befehle gestatten mehrere Adressierungsarten, aber nicht alle Adressierungarten lassen<br />

sich auf jeden Befehl anwenden. Jede zulässige Adressierungsart bei einem Befehl führt zu einen<br />

eigenen OP-Code. Die zulässigen Adressierungsarten und der jeweilige OP-Code lassen sich der<br />

Befehlsliste entnehmen. Die tatsächliche Länge und Ausführungszeit eines Befehls hängen von der<br />

Adressierungsart ab. Die Zahl der Bytes eines Befehls und seine Ausführungszeit lassen sich aus der<br />

Befehlsliste entnehmen.<br />

Konstanten-Adressierung (Immediate Addressing)<br />

Die Daten folgen unmittelbar auf den OP-Code. Je nach Befehl/Register sind es 8 Bit (1 Byte) oder 16<br />

Bit (2 Byte). Im <strong>Assembler</strong> wird dies durch Voranstellen von "#" kenntlich gemacht, zum Beispiel:<br />

LDAA #20 - Lade Akku A mit dem Wert 20<br />

Absolute Adressierung<br />

Mikrocomputertechnik<br />

Absolut vollständige Adressierung (Extended Addressing)<br />

Der Adreßteil des Befehls enthält eine vollständige 16-Bit-Adresse. Es ist eine Adressierung des<br />

gesamten Adreßraums möglich. Zum Beispiel:<br />

LDAA $A174 - Lade Akku A mit dem Inhalt der Speicherzelle $A174<br />

Absolut unvollständige Adressierung (Zero Page / Direct Addressing)<br />

Der Adreßteil enthält nur den niederwertigen Teil (LSB) der Adresse. Der höherwertige Teil wird auf<br />

Null gesetzt. Damit lassen sich die Adressen zwischen 0 und 255 ($0 - $FF) erreichen. Der Befehl ist<br />

ein Byte kürzer als bei der absoluten Adressierung und deshalb auch schneller in der Ausführung. Im<br />

<strong>Assembler</strong> wird dies durch Voranstellen von "


Implizite Adressierung (Inherent Addressing)<br />

Alle Adreßangaben sind im OP-Code des Befehls enthalten, es gibt keinen Adreßteil.<br />

• AD-Teil im Befehl nicht nötig<br />

• entweder keine AD-Angabe nötig (NOP)<br />

• oder AD-Angabe bezieht sich auf Register (LSRA, ABX, ...)<br />

Indizierte Adressierung (Indexed Addressing)<br />

Die effektive Adresse ergibt sich hier aus dem Inhalt eines Adreßregisters (z. B. X oder Y) und einer<br />

dazu addierten Distanz (Offset), die auch Null sein kann. Der Offset wird grundsätzlich konegativ<br />

bewertet (-128 .. +127). Die Adreßrechnung erfolgt modulo 64 K (bleibt also immer im Adreßraum<br />

des 68HC11). Zum Beispiel:<br />

CLR 5,X (ergibt als Code: 6F 05)<br />

CLR -5,X (ergibt als Code: 6F FB)<br />

Mikrocomputertechnik<br />

Anmerkungen zur Progam Counter-relativen Adressierung:<br />

Es wird der Stand des Program Counterszum Zeitpunkt der Befehlsausführung verwendet (Dies ist<br />

nicht die Adresse, an der der Befehl beginnt, denn der Program Counter enthält ja immer die Adresse<br />

des nächsten, auszuführenden Befehls. Der Program Counter ist gleich der Adresse des Befehls +<br />

Länge des Befehls). Die Program Counter-relative Adressierung wird oft bei Sprungbefehlen<br />

verwendet. Zweck: lageunabhängige Programme (Ablauf an jeder Position im Speicher).<br />

Befehlsaufbau: offset = Zieladresse - Befehlsadresse - Befehlslänge<br />

Befehlsausführung: Zieladresse = Befehlszählerstand + offset<br />

Implizite Adressierung (Inherent Addressing) 51


Alle Adressierungsarten im Überblick<br />

zeigt die folgende Grafik:<br />

3.3 <strong>Assembler</strong>-Befehlsaufbau<br />

Der <strong>Assembler</strong> ist ein Programm zur Übersetzung mnemotechnischer Befehlsbezeichnungen in die<br />

Maschinensprache. Es erfolgt 1:1-Abbildung der Befehle in die Maschinensprache, d. h. eine<br />

<strong>Assembler</strong>zeile entspricht einem Befehl.<br />

Maschinensprache:<br />

• OP-Code im Maschinencode (binär bzw. sedezimale Abkürzung)<br />

• Adresse als Maschinenadresse (binär bzw. sedezimale Abkürzung)<br />

<strong>Assembler</strong>sprache:<br />

• Festlegung symbolischer Bezeichnungen, die vom <strong>Assembler</strong>-Programm erkannt und<br />

verarbeitet werden.<br />

• OP-Code: mnemonische Bezeichnung (Mnemonics)<br />

• Adresse: symbolische Bezeichnung (Name, Marke (Label))<br />

Allgemeiner Aufbau eines <strong>Assembler</strong>befehls:<br />

Mikrocomputertechnik<br />

Marke OP-Code Operand/Adresse Kommentar<br />

Indizierte Adressierung (Indexed Addressing) 52


Beispiel:<br />

START LDAA DAT1 ; Zähler initialisieren<br />

• Op-Code muß immer vorhanden sein<br />

• Operand/Adresse, falls der Befehl es verlangt<br />

• Marke und Kommentar sind optional<br />

• Trennzeichen zwischen den einzelnen Feldern: Leerzeichen<br />

Marken-Feld: (optional)<br />

Das Feld beginnt in Spalte 1 (also ganz vorne). Die Marke besteht aus Buchstaben, Ziffern<br />

und Sonderzeichen (".", "_", "@") und beginnt mit einem Buchstaben. Die Länge ist auf 31<br />

Zeichen begrenzt. Die Marke kann durch einen ":" abgeschlossen werden, dieser wird vom<br />

<strong>Assembler</strong> ignoriert. Es wird bei manchen <strong>Assembler</strong>n - wie beispielsweise auch in C -<br />

zwischen Groß- und Kleinschreibung unterschieden. Registernamen (A, B, C, D, X, Y, S) sind<br />

reserviert und dürfen nicht verwendet werden. Marken bezeichnen Konstante oder<br />

Speicheradressen.<br />

OP-Code-Feld: (muß vorhanden sein)<br />

Falls keine Marke vorhanden, muß wenigstens ein Leerzeichen davor stehen. Sinnvoller ist es<br />

jedoch, die Opcodes in einer Spalte untereindander zu schreiben. Die Befehle werden durch<br />

Mnemonics aus zwei bis vier Buchstaben dargestellt. Bei einigen Befehlen ist eine<br />

Registerangabe direkt an das Mnemonic anzuhängen (z. B. ADDA, ADDB, ADDD). In<br />

diesem Feld kann auch eine <strong>Assembler</strong>-Direktive (Pseudobefehl) stehen Anweisung für<br />

den <strong>Assembler</strong>, Genaueres später.<br />

Operanden/Adreß-Feld: (abhängig vom OP-Code)<br />

Dieses Feld enthält den Operanden des Befehls, meist eine Adresse oder eine Konstante.<br />

Aufbau hängt von der Adressierungsart ab. Falls eine Adressierungsart mehrere Operanden<br />

verlangt (z. B. Register + Offset) erfolgt Trennung der Operanden mit Komma.<br />

Bei vielen <strong>Assembler</strong>n sind arithmetische und logische Ausdrücke aus Konstanten möglich.<br />

Die Adreßangabe (Offset) kann erfolgen als:<br />

◊ Bezeichner, z. B. MAXIMUM<br />

◊ Dezimalzahl (ohne Kennzeichnung), z. B. 72<br />

◊ Sedezimalzahl (Vorsatz $), z. B. $48<br />

◊ Dualzahl (Vorsatz %), z. B. %01001000<br />

◊ ASCII-Zeichen(-folge), z. B. 'Hallo' oder "Hallo"<br />

◊ als Offset vom "Location Counter" (Vorsatz *), z. B. *+5<br />

Im Operandenfeld kann auch mit den vier Grundrechenarten (+ - * /) und Klammern<br />

gearbeitet werden. Beachten Sie, daß die Ausdrücke zur Assemblierungszeit ausgewertet<br />

werden - nicht zur Laufzeit des Programms! Es sollte sich also immer um "konstante"<br />

Ausdrücke handeln, z. B.<br />

BOTTOM EQU TOP + 10<br />

Kommentar-Feld: (optional)<br />

Das Kommentarfeld wird durch den Strichpunkt oder zwei Schrägstriche eingeleitet. Es<br />

enthält beliebige Zeichenfolgen und wird vom <strong>Assembler</strong> ignoriert.<br />

Zusätzlich sind auch reine Kommentarzeilen möglich, die mit einem "*" in Spalte 1 beginnen.<br />

Der <strong>Assembler</strong> hat zwei Durchläufe:<br />

Beispiel:<br />

Mikrocomputertechnik<br />

1. Durchlauf (pass one): Syntaxprüfung und Aufbau des Adreßbuchs.<br />

2. Durchlauf (pass two): Vollständigkeitsprüfung und Aufbau des Zielprogramms.<br />

3.3 <strong>Assembler</strong>-Befehlsaufbau 53


1. Quellcode<br />

Die Felder für Adresse und Code sind hier noch leer, sie werden vom <strong>Assembler</strong> gefüllt. Es gibt zwei<br />

Pseudobefehle, die weiter unten genauer behandelt werden: ORG legt die Startadresse des erzeugten<br />

Codes fest und END beendet den Quellcode.<br />

Adresse Inhalt Marke Befehl Operand Kommentar<br />

ORG $8000 In den Speicher ab $8000<br />

MAIN BRA MARKE relativer Vorwärtssprung<br />

JMP MARKE absoluter Vorwärtssprung<br />

BRA MAIN relativer Rückwärtssprung<br />

MARKE JMP MAIN absoluter Rückwärtssprung<br />

END<br />

2. Erster <strong>Assembler</strong>lauf: Adresspegel und Code eintragen<br />

Im ersten Durchlauf werden die Befehle übersetzt. Damit liegt die Adresse eines jeden Befehls fest<br />

(weil die Länge eines Befehls ja bekannt ist). Jedoch können die Sprungadressen noch nicht<br />

eingetragen werden, weil bei Vorwärtssprüngen diese beim Übersetzen des jeweiligen Befehls noch<br />

nicht bekannt sind.<br />

Adresse Inhalt Marke Befehl Operand Kommentar<br />

ORG $8000 In den Speicher ab $8000<br />

8000 20 ?? MAIN BRA MARKE relativer Vorwärtssprung<br />

8002 7E ?? ?? JMP MARKE absoluter Vorwärtssprung<br />

8005 20 ?? BRA MAIN relativer Rückwärtssprung<br />

8007 7E ?? ?? MARKE JMP MAIN absoluter Rückwärtssprung<br />

END<br />

Mikrocomputertechnik<br />

3. Zweiter <strong>Assembler</strong>lauf: Adressen absättigen<br />

Beim ersten Durchlauf hat der <strong>Assembler</strong> parallel zur Übersetzung noch eine Symboltabelle angelegt,<br />

welche die Zuordnung zwischen Marke (Name) und Adresse enthält. Nun können mit Hilfe dieser<br />

Tabelle im zweiten Durchlauf die Adressen eingetragen werden.<br />

Adresse Inhalt Marke Befehl Operand Kommentar<br />

ORG $8000 In den Speicher ab $8000<br />

8000 20 05 MAIN BRA MARKE relativer Vorwärtssprung<br />

8002 7E 80 07 JMP MARKE absoluter Vorwärtssprung<br />

8005 20 F9 BRA MAIN relativer Rückwärtssprung<br />

8007 7E 80 00 MARKE JMP MAIN absoluter Rückwärtssprung<br />

END<br />

Die Symboltabelle nimm neben den Sprungadressen auch alle Namen von Konstanten und Variablen<br />

auf. Im zweiten Lauf werden dann auch diese Namen durch die ermittelten Werte ersetzt.<br />

1. Quellcode 54


3.4 Pseudobefehle (<strong>Assembler</strong>-<strong>Direktiven</strong>)<br />

Pseudobefehle erzeugen keine Maschinenbefehle sondern<br />

• erzeugen Konstanten und Variablen (bytes, words, longwords, strings)<br />

• beeinflussen den Adresspegel<br />

• führen zu Einträgen in der Symboltabelle<br />

• steuern den Übersetzungsvorgang<br />

Der <strong>Assembler</strong> führt einen Zähler, der Auskunft über den aktuellen Adreßpegel gibt. Dieser 'Location<br />

Counter' dient beispielsweise zum Berechnen von Sprungadressen. Er entspricht im Prinzip dem<br />

'Program Counter' im realen Prozessor. Die Pseudobefehle werden im OP-Code-Feld einer<br />

<strong>Assembler</strong>zeile angegeben. Unser <strong>Assembler</strong> kennt folgende <strong>Direktiven</strong>:<br />

ORG Origin<br />

Der Location Counter wird auf die im Operandenfeld angegebene Adresse<br />

gesetzt. Er legt damit die Adresse fest, an der der Code später im Speicher des<br />

Controllers abgelegt wird, z. B.:<br />

ORG $8000<br />

EQU Equate<br />

Definition eines Namens (Konstante, Marke). Der im Operandenfeld<br />

angegebene Wert wird dem im Markenfeld angegebenen Namen gleichgesetzt,<br />

z. B.:<br />

ETX EQU 3<br />

CR EQU $D<br />

LF EQU $A<br />

PUFL EQU $100<br />

DC.B Define Constant Byte<br />

Reservierung von Speicherplatz und Belegung mit den im Operandenfeld<br />

angegebenen konstanten Byte-Werten. Mehrere Operanden durch Komma<br />

trennen! Z. B.:<br />

TAB DC.B $0D,$0A,$03<br />

Neben einfachen Konstanten sind in (einfache oder doppelte) Hochkomma<br />

eingeschlossene Zeichenketten möglich. Die Hochkommas gehören dabei<br />

nicht zur Zeichenkette. In den Zeichenketten sind folgende Sonderzeichen<br />

erlaubt:<br />

Z. B.:<br />

• \a Bell ($07)<br />

• \f Formfeed ($0C)<br />

• \n Newline ($0A)<br />

• \r Carriage Return ($0D)<br />

• \t Tabulator ($09)<br />

• \\ \<br />

TEXT DC.B "Hello World!\n\r"<br />

Mikrocomputertechnik<br />

Bei manchen <strong>Assembler</strong>n wird anstelle von DC.B das Kürzel FCB (Form<br />

Constant Byte) verwendet (bei unserem geht beides).<br />

3.4 Pseudobefehle (<strong>Assembler</strong>-<strong>Direktiven</strong>) 55


DC.W Define Constant Word<br />

Reservierung von Speicherplatz und Belegung mit den im Operandenfeld<br />

angegebenen konstanten 16-Bit-Werten. Mehrere Operanden durch Komma<br />

trennen, z. B.:<br />

ATAB DC.W $FF30,$FF45,$FFA0<br />

Bei manchen <strong>Assembler</strong>n (auch unserem) wird anstelle von DC.W das Kürzel<br />

FDB (Form Double Byte) verwendet.<br />

DC.L Define Constant Longword<br />

Reservierung von Speicherplatz und Belegung mit den im Operandenfeld<br />

angegebenen konstanten 32-Bit-Werten. Mehrere Operanden durch Komma<br />

trennen, z. B.:<br />

DS.B<br />

DS.W<br />

DS.L<br />

XTAB DC.L $FF30FF45,$F000FFA0<br />

Define Storage Bytes/Words/Longwords<br />

Reservieren von Speicherbytes, Speicherworten (16 Bit) oder Langworten (32<br />

Bit) ohne Vorbelegung. Der Operand gibt die Anzahl der zu reservierenden<br />

Elemente (Bytes, Worte oder Langworte) an, z. B.:<br />

PUFFER DS.B 100<br />

ADRTAB DS.W 23<br />

Der Reservierungsvorgang hat eher informatorischen Charakter. Es findet<br />

seitens des <strong>Assembler</strong>s keinerlei Adress- oder Bereichsüberprüfung statt! Bei<br />

manchen <strong>Assembler</strong> wird stattdessen nur eine Reservierung in Bytes mit dem<br />

Befehl RMB (Reserve Memory Byte) vorgenommen.<br />

INCLUDE Einfügen einer Quelldatei an der entsprechenden Stelle. Der Dateiname wird<br />

entweder in < ... > (voreingestelltes Include-Verzeichnis) oder " ... "<br />

(beliebiger Dateipfad) eingeschlossen, z. B.:<br />

INCLUDE "definitionen.a"<br />

INCLUDE <br />

Mikrocomputertechnik<br />

NOLIST Unterdrücken der Erzeugung eines Programmlistings bis zum nächsten<br />

LIST-Befehl.<br />

LIST Fortsetzen des Listings nach einem vorher platzierten NOLIST-Befehl.<br />

END Ende des <strong>Assembler</strong>programms. Optionaler Befehl am Programmende. Wird<br />

aus Gründen der Kompatibilität vom <strong>Assembler</strong> akzeptiert, kann aber<br />

weggelassen werden. Text nach diesem Befehl wird vom <strong>Assembler</strong> ignoriert.<br />

Speicher-Organisation<br />

Mit Hilfe der ORG-Anweisung kann der Programmierer verschiedene Programmteile oder<br />

Datenbereiche an beliebigen Stellen im gesamten Adreßraum ablegen. Eine sinnvolle<br />

Speicheraufteilung hat jedoch verschiedene Randbedingungen zu berücksichtigen.<br />

Von der Hardwareseite her sind z.B. RAM- und ROM-Bereiche verschiedener Größe gegeben, denn<br />

Programme sollen häufig im ROM liegen während variable Datenbereiche natürlich nur im RAM sein<br />

können. Eine effiziente Nutzung der physikalisch vorhandenen Speicher verlangt auch die Definition<br />

von lückenlos zusammenhängenden Teilbereichen sowohl von Programmteilen (Hauptprogramm,<br />

Unterprogramme, Interrupt-Service-Routinen) als auch von Datenbereichen (Datenpuffer,<br />

Ausgabetexte, Zustandsvariablen, Stacks, Peripherie-Baustein-Register etc).<br />

Speicher-Organisation 56


Als Grundregel gilt: Je eine ORG-Anweisung für den Daten- und den Programmbereich genügt, denn<br />

dann sind beide Bereiche jeweils zusammenhängend. Es ist nicht nötig, z.B. für jedes Unterprogramm<br />

oder jede Interrupt-Service-Routine ein neues ORG zu setzen. Jede weitere ORG-Anweisung steigert<br />

nur die Gefahr von Fehlern (z.B. überlappende Bereiche) bzw. Speicherverschwendung durch<br />

unnötige Lücken. Bedenken Sie, dass Sie vom <strong>Assembler</strong> nicht gewarnt werden, wenn sich<br />

Speicherbereiche überlappen oder Sie Bereiche wählen, an denen kein realer Speicher vorhanden ist.<br />

Ganz auf die ORG-Anweisung zu verzichten ist zwar möglich (Programm- und Datenbereich hängen<br />

dann zusammen und beginnen bei Null), aber nicht zu empfehlen. Durch kommentierte<br />

ORG-Anweisungen zeigt man, das diese wohlüberlegt gewählt wurden; also besser ORG $0000<br />

angeben als einfach weglassen.<br />

Anmerkung: Da bei einem Mikrocontroller ja zwischen ROM- bzw. EEPROM-Speicher und RAM<br />

unterschieden werden muß, ist auch die Reservierung von Speicher von dieser Unterscheidung<br />

betroffen. Mit DC.B, DC.W oder DC.L vordefinierte Konstante liegen im ROM/EEPROM-Bereich,<br />

mit DS.B, DS.W oder DS.L reservierter Speicher im RAM-Bereich.<br />

Merkregeln für die Verwendung von EQU, DS.B/DS.W/DS.L und DC.B/DC.W/DC.L<br />

• EQU nur für Konstanten, die mit symbolischen Namen versehen werden sollen. Sollen solche<br />

Werte später doch geändert werden, so muss das Quellprogramm geändert und neu<br />

assembliert werden.<br />

• DS.B/DS.W/DS.L nur zum Bereitstellen von RAM-Speicherplatz für Daten, die vom<br />

Programm erst dorthin geschrieben werden, z.B. eingelesene Messwerte, etc.<br />

• DC.B/DC.W/DC.L zum Vorbelegen von Datenbereichen im ROM/EEPROM mit konstanten<br />

Werten, Umrechnungstabellen, Texten etc.<br />

Grundsätzlicher Aufbau eines 68HC11-<strong>Assembler</strong>programms<br />

1. Konstantendefinitionen<br />

Hier werden alle Definitionen für Werte und Adressen (EQU-Anweisung) vorgenommen. Diese<br />

"Namensdefinitionen" belegen keinen Speicherplatz, sondern dienen nur der besseren Lesbarkeit und<br />

Wartbarkeit des Programms. Zum Beispiel:<br />

STACK EQU $7FFF Stackbereich<br />

PROG EQU $8000 Programmbereich<br />

DATA EQU $2000 Datenbereich (auch Adr. 0 möglich)<br />

RVECT EQU $FFFE Reset-Vektor<br />

SCCR1 EQU $102C<br />

SCCR2 EQU $102D<br />

CR EQU 13 Carriage-Return-Zeichen<br />

LF EQU 10 Linefeed-Zeichen<br />

ETX EQU 3 Textende<br />

MAXDATA EQU 100<br />

Wichtig sind die ersten fünf Zeilen, die bei keinem Programm fehlen dürfen. Sie legen die<br />

Adressbereiche für RAM und EEPROM fest und definieren die Adressen der beiden Vektoren, die<br />

immer gesetzt werden müssen.<br />

2. Variablendefinitionen<br />

Mikrocomputertechnik<br />

Hier werden alle Daten definiert, die Speicherplatz belegen. Es ist ratsam, den Datenbereich durch<br />

eine eigene ORG-Anweisung einzuleiten, um die Daten an definierter Stelle im Speicher abzulegen.<br />

Bei einem Steuerungsrechner muß auf jeden Fall in Datenbereich (RAM) und Programmbereich<br />

Speicher-Organisation 57


(PROM) unterschieden werden. Man kann die Variablen auch nach dem Programmcode ablegen. Zum<br />

Beispiel:<br />

ORG DATA Datenbereich z.B. ab Adresse $2000<br />

COUNT DC.B 0 Wert mit Null vorbelegen<br />

PUFFER DS.B 80 80 Byte Pufferbereich reservieren<br />

TEXT DC.B 'Hello World' Text, abgeschlossen durch Zeilen-<br />

DC.B CR, LF, ETX wechsel und Nullbyte<br />

3. Programmbereich<br />

Nun folgt das eigentliche Programm. Es wird immer mit einer ORG-Anweisung an eine definierte<br />

Adresse gelegt. Diese Adresse ist auch Startadresse des Programms.<br />

Achtung: Der <strong>Assembler</strong> kümmert sich nicht um die Adreßlage des Programms, auch Überlappungen<br />

mit dem Datenbereich werden nicht als Fehler gemeldet aufpassen.<br />

Es gibt zwei Möglichkeiten der Anordnung von Haupt- und Unterprogrammen. Üblich ist es, das<br />

Hauptprogramm am Anfang zu postieren und dann die Unterprogramme folgen zu lassen. Wer lieber<br />

die UP zuerst stehen hat, muß das HP mit einer Marke versehen (z. B. "MAIN") und nach der<br />

ORG-Anweisung als erste Anweisung einen Sprung zum HP eintragen, z. B.:<br />

....... Definitionen (1. und 2.)<br />

ORG PROG Programmbereich, z. B. $8000<br />

JMP MAIN<br />

....... Unterprogramme<br />

Mikrocomputertechnik<br />

MAIN LDS #STACK Stackpointer setzen, sonst geht nichts<br />

.<br />

.<br />

.<br />

.<br />

ORG RVECT<br />

DC.W MAIN Reset-Vektor auf Programmanfang setzen<br />

END<br />

Häufiger ist jedoch die Variante mit vorangestelltem Hauptprogramm anzutreffen. Beim folgenden<br />

Rumpfprogramm sind auch noch einige weitere Besonderheiten berücksichtigt:<br />

stak equ $7FFF ; Stackbereich ab $7FFF (RAM, abwaerts)<br />

prog equ $8000 ; Programmbereich ab $8000 (EEPROM)<br />

data equ $2000 ; Datenbereich ab $2000 (RAM)<br />

rvec equ $FFFE ; Reset-Vektor<br />

. ; ggf. weitere Vektoren<br />

org data ; Beginn Datenbereich<br />

. ; Variablen-Definitionen<br />

.<br />

org prog ; Beginn Programmbereich<br />

main lds #stak ; Stackpointer setzen<br />

.<br />

. ; alle Initialisierungen<br />

.<br />

loop . ; Befehle des Programms<br />

.<br />

.<br />

jmp loop<br />

Grundsätzlicher Aufbau eines 68HC11-<strong>Assembler</strong>programms 58


. ; ggf. fixe Tabellen dahinter<br />

.<br />

. ; ggf. Setzen der Interrupt-Vektoren<br />

. ; (Reihenfolge der Adressen beachten!)<br />

org rvec ; Setzen des Reset-Vektors<br />

fdb main<br />

end<br />

Beim Programmieren einer Controller-Anwendung ist u. a. auch zu berücksichtigen, dass<br />

RAM-Inhalte nach dem Ausschalten und späteren Wiedereinschalten verloren gehen. Das bedeutet,<br />

dass feste Werte wie Ausgabestrings, Anfangswerte von Variablen usw. nicht im RAM<br />

(Datenspeicher), sondern im EEPROM (Programmspeicher) abgelegt werden müssen. Das hat aber<br />

Konsequenzen:<br />

• Daten im Programmspeicher können nicht geändert werden (EEPROM!)<br />

• Braucht man Anfangswerte für Variablen, müssen diese im Programmspeicher abgelegt und<br />

in der Initialisierungsphase in Variablen im RAM kopiert werden.<br />

Hinweis: Die im Datenbereich abgelegten konstanten Werte (mittels DC.B etc.) werden nur einmal<br />

beim Herunterladen des Programms ins Zielsystem im Speicher eingetragen, danach nie wieder.<br />

Schon das Drücken der Reset-Taste kann zu "seltsamen" Verhaltenformen des Programms führen.<br />

3.5 CPU-Befehle<br />

Bei der folgenden Beschreibung der Befehle werden einige Standardnamen verwendet:<br />

• Mit A, B und D werden die Akkumulatoren bezeichnet<br />

• Mit X, Y und S werden die Indexregister und der Stackpointer bezeichnet<br />

• "adr." bezeichnet den Inhalt eines beliebigen Speicherbytes oder eine Konstante<br />

• (A) oder (adr.) bezeichnet den Inhalt von Akku A bzw. den Inhalt der Speicheradresse "adr.".<br />

Transport-Befehle<br />

Ladebefehle:<br />

Load Register from Memory or Constant<br />

Mikrocomputertechnik<br />

• anwendbar auf A, B (8 Bit) oder D, S, X, Y (16 Bit)<br />

3.5 CPU-Befehle 59


• bei 8-Bit-Register:<br />

LDAA adr.<br />

LDAB adr.<br />

• bei 16-Bit-Register: LDD adr<br />

LDS adr<br />

LDX adr<br />

LDY adr<br />

in (adr) steht das MSB in (adr+1) das LSB<br />

• Beeinflusst: N, V, Z<br />

• Flags<br />

CLR Clear Akkumulator: 0 Akkumulator-Register<br />

• CLRA<br />

CLRB<br />

• schneller als LDAA #0<br />

Speicherbefehle:<br />

Store Register into Memory (8 Bit/16 Bit)<br />

• STAA, STAB (8 Bit): (Reg) adr.<br />

• STD, STS, STX, STY (16 Bit): (Reg) adr., adr+1<br />

Clear Memory<br />

• CLR adr.<br />

Transport zwischen Registern:<br />

Kopie des Inhalts eines Registers in ein anderes (transfer)<br />

• TAB (A) B<br />

• TAP (A) Statusregister<br />

• TBA (B) A<br />

• TPA (Statusregister) A<br />

• TSX (S) X<br />

• TSY (S) Y<br />

Mikrocomputertechnik<br />

Transport-Befehle 60


• TXS (X) S<br />

• TYS (Y) S<br />

Bit X im Statusregister kann mittels TAP nicht gesetzt werden.<br />

Austausch von Registerinhalten (exchange)<br />

• XGDX D X<br />

• XGDY D Y<br />

• Zweck: Adreßrechnung in D, Adressierung dann über X oder Y.<br />

Beispiel: Tausch A B<br />

Benötigt wird eine Hilfsvariable im Daten-Speicherbereich<br />

STAA HILF<br />

TBA<br />

LDAB HILF<br />

Beispiel: Tausch X Y<br />

* Beispielbelegung X Y D<br />

* 1 2 3<br />

XGDX 3 2 1<br />

XGDY 3 1 2<br />

XGDX 2 1 3<br />

Beispiel: Unterprogramm zum Kopieren eines Speicherbereichs (nullterminierte Zeichenkette). Die<br />

Adresse des Quellstrings steht im X-Register, die Adresse des Zielbereichs im Y-Register:<br />

strcpy ldaa 0,x ; lade ein Zeichen aus der Quelle<br />

staa 0,y ; ablegen im Zielbereich<br />

beq strc_e ; wenn Nullbyte, dann fertig<br />

inx ; beide Zeiger inkementieren<br />

iny<br />

bra strcpy ; und naechstes Zeichen<br />

strc_e rts<br />

Soll ein beliebiger Speicherbereich kopiert werden, müsste noch ein Blocklängenzähler<br />

implementiert werden.<br />

Arithmetische Befehle<br />

Dies sind Befehle, die arithmetische Operationen bewirken. Im allgemeinen steht ein Operand in<br />

einem Akku und das Ergebnis wieder im gleichen Akku.<br />

Additionsbefehle:<br />

Addieren (add)<br />

Mikrocomputertechnik<br />

Arithmetische Befehle 61


• ADDA adr. (A) + (adr.) A<br />

• ADDB adr. (B) + (adr.) B<br />

• ADDD adr. (D) + (adr., adr+1) D (16-Bit-Addition)<br />

• ABA (A) + (B) A<br />

• ABX (X) + (B) X (Adreßrechnung), B als vorzeichenlose Zahl aufgefaßt<br />

• ABY (Y) + (B) Y (Adreßrechnung), B als vorzeichenlose Zahl aufgefaßt<br />

Addieren mit Übertrag (add with carry)<br />

• ADCA adr. (A) + (adr.) + C A<br />

• ADCB adr. (B) + (adr.) + C B<br />

• Anwendung: Mehrbyte-Addition<br />

Beispiel: Addition zweier 4-Byte-Zahlen<br />

1. Operand: Adresse $41 - $44<br />

2. Operand: Adresse $45 - $48<br />

Ergebnis: Adresse $49 - $4C<br />

LDAA $44 Niederwertiges Byte addieren<br />

ADDA $48<br />

STAA $4C<br />

LDAA $43 Zweites Byte addieren<br />

ADCA $47<br />

STAA $4B<br />

LDAA $42 Drittes Byte addieren<br />

ADCA $46<br />

STAA $4A<br />

LDAA $41 Höchstwertiges Byte addieren<br />

ADCA $45<br />

STAA $49<br />

Erhöhen (increment)<br />

Mikrocomputertechnik<br />

• Sonderfall: Addition von 1<br />

• C-Flag wird nicht beeinflusst (Addition mod 256)<br />

• Für z. B. Schleifenzähler<br />

• INCA (A) + 1 A<br />

• INCB (B) + 1 B<br />

• INS (S) + 1 S (kein Flag beeinflußt)<br />

• INX (X) + 1 X (nur Z-Flag beeinflußt)<br />

• INY (Y) + 1 Y (nur Z-Flag beeinflußt)<br />

Arithmetische Befehle 62


• INC adr. (adr.) + 1 adr. (Increment eines Speicherbytes)<br />

Subtraktionsbefehle:<br />

Subtraktion (subtract) = Addition des Zweierkomplements<br />

• SUBA adr. (A) - (adr.) A<br />

• SUBB adr. (B) - (adr.) B<br />

• SUBD: 16-Bit-Subtraktion, Operand in zwei aufeinanderfolgenden Speicherzellen<br />

Subtraktion mit Übertrag (subtract with carry)<br />

• SBCA adr. (A) - (adr.) + C A<br />

• SBCB adr. (B) - (adr.) + C B<br />

• Anwendung: Mehrbyte-Subtraktion<br />

Erniedrigen (decrement)<br />

• Sonderfall: Subtraktion von 1<br />

• C-Flag wird nicht beeinflusst (Subtraktion mod 256)<br />

• Für z. B. Schleifenzähler<br />

• DECA (A) - 1 A<br />

• DECB (B) - 1 B<br />

• DES (S) - 1 S (kein Flag beeinflußt)<br />

• DEX (X) - 1 X (nur Z-Flag beeinflußt)<br />

• DEY (Y) - 1 Y (nur Z-Flag beeinflußt)<br />

• DEC adr. (adr.) - 1 adr. (Decrement eines Speicherbytes)<br />

Vorzeichenwechsel (negate)<br />

• Sonderfall: 0 - (Akku), Bildung des Zweierkomplements<br />

• NEGA A komplementieren<br />

• NEGB B komplementieren<br />

• NEG adr. adr. komplementieren<br />

Multiplikation und Division:<br />

Multiplizieren (multiply)<br />

• MUL Vorzeichenlose Multiplikation (A) * (B) D<br />

• Z-Flag = 1, wenn Ergebnis = 0 ist, sonst Z = 0<br />

• C-Flag = Bit 7 von B<br />

Dividieren (divide)<br />

Beispiele:<br />

• IDIV Vorzeichenlose Division, ganzzahliger Anteil (integer divide)<br />

für D > X: (D) / (X) X, Rest in D<br />

• FDIV Vorzeichenlose Division, Quotient echter Bruch (fractional divide)<br />

für D < X: (D) / (X) X, Rest in D<br />

IDIV: FDIV:<br />

Mikrocomputertechnik<br />

$8421 : $0004 = $2108 R $0001 $1000 : $2000 = $.8000 R $0000<br />

Arithmetische Befehle 63


$0001 : $FFFF = $0000 R $0001 $0001 : $FFFF = $.0001 R $0001<br />

$FFFF : $0001 = $FFFF R $0000 $FFFF : $0001 = unzulässig, V=1<br />

Weitere arithmetische Befehle:<br />

DAA Decimal Adjust A<br />

• Dezimalkorrektur von Akku A für BCD-Arithmetik<br />

• Jedes Halbbyte (Nibble) entspr. 1 Dezimalziffer<br />

• Anwendung nach Addition im Akku<br />

• Korrekturaddition, wenn Pseudotetrade auftritt<br />

Akku enthält zwei BCD-Ziffern<br />

• Nach DAA enthält C-Flag den Übertrag in die nächste Stelle<br />

• NUR (!) nach dem Befehlen ABA, ADDA und ADCA wirksam (nicht beim INC-Befehl)<br />

• Bei der Subtraktion gilt Zehnerkomplement. -1 wird also nicht als $FF, sondern als $99<br />

dargestellt (-2 $98, -3 $97, usw.).<br />

Beispiel: Addition zweier 4-stelligen BCD-Zahlen<br />

1. Zahl: Adr. $31-$32<br />

2. Zahl: Adr. $33-$34<br />

Ergebnis: Adr. $35-$36<br />

LDAA $32 niederwertige 2 Ziffern<br />

ADDA $34 binär addieren<br />

DAA BCD-Justage<br />

STAA $36<br />

LDAA $31 höherwertige 2 Ziffern<br />

ADCA $34 binär addieren mit Carry!<br />

DAA BCD-Justage<br />

STAA $35<br />

Logische Befehle<br />

Bei logischen Befehlen erfolgt die bitweise logische Verknüpfung eines Akku-Inhalts mit einem<br />

Operanden (Speicherinhalt oder Konstante). Logische Befehle spielen vor allem beim Zugriff auf<br />

E/A-Komponenten eine Rolle, weil bei E/A-Operationen häufig einzelne Bits eines Datenworts<br />

gesetzt, gelöscht oder invertiert werden müssen.<br />

Und-Verknüpfung (and)<br />

Beispiele:<br />

Mikrocomputertechnik<br />

• ANDA adr. (A) and (adr.) A<br />

• ANDB adr. (B) and (adr.) B<br />

• Anwendung: Löschen einzelner Bits in einem Wort<br />

Arithmetische Befehle 64


1) Löschen der 4 höherwertigen Bits von Akku A<br />

ANDA #$0F<br />

2) Rücksetzen des 5. Bits<br />

ANDA #%11101111<br />

3) Rücksetzen des 4. Bits einer Variablen namens FLAG<br />

LDAA FLAG<br />

ANDA #%11110111<br />

STAA FLAG<br />

Oder-Verknüpfung (or)<br />

Beispiele:<br />

• ORAA adr. (A) or (adr.) A<br />

• ORAB adr. (B) or (adr.) B<br />

• Anwendung: Setzen einzelner Bits in einem Wort<br />

1) Setzen der 4 höherwertigen Bits von Akku A<br />

ORA #$F0<br />

2) Setzen des 5. Bits<br />

ORAA #%00010000<br />

3) Setzen des 4. Bits einer Variablen namens FLAG<br />

LDAA FLAG<br />

ORAA #%00001000<br />

STAA FLAG<br />

Exklusiv Oder (exor)<br />

Beispiele:<br />

• EORA adr. (A) exor (adr.) A<br />

• EORB adr. (B) exor (adr.) B<br />

• Anwendung: Invertieren einzelner Bits<br />

Maskenbit=1: Bit wird invertiert<br />

Maskenbit=0: Bit unverändert<br />

1) Invertieren der 4 höherwertigen Bits von Akku A<br />

EORA #%11110000<br />

2) Invertieren der Bits 0 und 3 einer Variablen namens FLAG<br />

LDAA FLAG<br />

EORA #%00000101<br />

STAA FLAG<br />

Bit prüfen (bit test)<br />

Mikrocomputertechnik<br />

Diese Befehle haben Bedeutung in Zusammenhang mit den weiter unten behandelten<br />

Sprungbefehlen. Sie erlauben den Test eines Akkumulators auf Null bzw. Vorzeichen, ohne dessen<br />

Inhalt zu ändern.<br />

Logische Befehle 65


• BITA adr. (A) and (adr.) Nur Flags neu setzen, A bleibt unverändert<br />

• BITB adr. (B) and (adr.) Nur Flags neu setzen, B bleibt unverändert<br />

Invertieren (complement)<br />

1-Komplement Invertieren aller Bits.<br />

Auch auf Speicherbytes anwendbar.<br />

• COMA adr. not (A) A<br />

• COMB adr. not (B) B<br />

• COM adr. not (adr.) adr.<br />

Beispiel: Verwendung des Speicher-Bytes $41 als Software-Flip-Flop. Zu Beginn des Programms<br />

muß der Inhalt von $41 gelöscht werden!<br />

COM $41 Inhalt wird $FF<br />

.<br />

.<br />

COM $41 Inhalt wird wieder 0<br />

.<br />

.<br />

usw.<br />

Schiebe- und Rotationsbefehle<br />

Die Schiebebefehle bewirken das Verschieben eines Akku- oder Speicherinhalts um eine Stelle<br />

nach rechts oder links. Bei den Rotationsbefehlen erfolgt die Ringverschiebung eines Akku- oder<br />

Speicherinhalts unter Einbeziehung des C-Flags nach links oder rechts. Die Befehle sind auf A, B,<br />

D oder einen Speicherinhalt anwendbar. Die Realisierung auf Speicherinhalt erfolgt durch: Laden in<br />

Rechenregister, Schiebeoperation im Rechenregister, Zurückspeichern des Register-Inhalts).<br />

Logische Verschiebung:<br />

LSRx Logical Shift Right:<br />

von links wird 0 nachgeschoben: 0 MSB<br />

LSB C-Flag<br />

Mikrocomputertechnik<br />

• LSRA Akku A nach rechts schieben<br />

Logische Befehle 66


• LSRB Akku B nach rechts schieben<br />

• LSRD Akku D nach rechts schieben<br />

• LSR adr. Speicherwort adr. nach rechts schieben<br />

LSLx Logical Shift Left:<br />

von rechts wird 0 nachgeschoben: 0 LSB<br />

MSB C-Flag<br />

• LSLA Akku A nach links schieben<br />

• LSLB Akku B nach links schieben<br />

• LSLD Akku D nach links schieben<br />

• LSL adr. Speicherwort adr. nach links schieben<br />

Arithmetische Verschiebung:<br />

ASRx Arithmetic Shift Right:<br />

Entspricht Division durch 2<br />

MSB MSB (Vorzeichen bleibt erhalten), LSB C-Flag<br />

• ASRA Akku A nach rechts schieben<br />

• ASRB Akku B nach rechts schieben<br />

• ASR adr. Speicherwort adr. nach rechts schieben<br />

ASLx Arithmetic Shift Left:<br />

von rechts wird 0 nachgeschoben: 0 LSB<br />

MSB C-Flag<br />

Identisch mit LSL!<br />

• ASLA Akku A nach links schieben<br />

• ASLB Akku B nach links schieben<br />

• ASLD Akku D nach links schieben<br />

• ASL adr. Speicherwort adr. nach links schieben<br />

Rotationsbefehle:<br />

Hin- und Herschieben des Akku- oder Speicherinhalts ohne ihn zu zerstören (anschließend Test des<br />

C-Flags). Vorzeichenlose duale Multiplikation und Division.<br />

ROLx Rotate Left<br />

C-Flag LSB<br />

MSB C-Flag<br />

• ROLA Akku A linksrotieren<br />

• ROLB Akku B linksrotieren<br />

• ROL adr. Speicherwort adr. linksrotieren<br />

RORx Rotate Right<br />

C-Flag MSB<br />

LSB C-Flag<br />

Mikrocomputertechnik<br />

• RORA Akku A rechtsrotieren<br />

• RORB Akku B rechtsrotieren<br />

• ROR adr. Speicherwort adr. rechtsrotieren<br />

Schiebe- und Rotationsbefehle 67


Beispiele:<br />

1) Multiplikation von Akku A mit 10: (A) * 10 A<br />

ASLA (A)*2 A<br />

STAA $40 Erg. zwischenspeichern<br />

ASLA (A)*4 A<br />

ASLA (A)*8 A<br />

ADDA $40 (A)*8 + (A)*2 A<br />

2) Akku D nach links schieben:<br />

A C B<br />

ASLB MSB von B --> Carry +----------+__+-+__+----------+<br />

ROLA Carry --> LSB von A +----------+ +-+ +----------+<br />

3) Zerlegung eines Bytes in zwei Halbbytes:<br />

Die Halbbytes sind in getrennten Speicherzellen als niederwertiges Halbbyte<br />

zu speichern (höherwertiges Halbbyte ist auf 0 zu setzen).<br />

$70: zu zerlegendes Byte<br />

$71: höherwertiges Nibble<br />

$72: niederwetiges Nibble<br />

LDAA $70 Byte holen (binär: xxxxyyyy)<br />

ANDA #$0F niederwertiges Nibble maskieren<br />

STAA $72 speichern (binär: 0000yyyy)<br />

LDAA $70 Byte nochmal holen<br />

LSRA 4 x nach rechts schieben (0xxxxyyy)<br />

LSRA (00xxxxyy)<br />

LSRA (000xxxxy)<br />

LSRA (0000xxxx)<br />

STAA $71 höherwertiges Nibble speichern<br />

Test- und Statusregisterbefehle<br />

Sie dienen der Überprüfung von Datenwerten auf bestimmte Eigenschaften. Die Überprüfung<br />

erfolgt durch arithmetische und logische Operationen. Als Ergebnis werden bestimmte Flags des<br />

CC-Register beeinflusst, der Inhalt der Akkus bleibt unverändert. Die Flags können zur Steuerung<br />

bestimmter Sprungbefehle verwendet werden Programmfortsetzung abhängig von<br />

Dateneigenschaften Steuerbefehle. Beispiele bei den Sprungbefehlen.<br />

Test<br />

Die Befehle sind anwendbar auf A, B und den Speicher. Test auf Null und negativ.<br />

• Z-Flag = 1, wenn Akku- oder Speicherinhalt = 0 ist.<br />

• N-Flag = MSB von Akku- oder Speicherinhalt<br />

• TSTA Akku A = 0 ?<br />

• TSTB Akku B = 0 ?<br />

• TST adr. (adr.) = 0 ?<br />

Vergleich (compare)<br />

Mikrocomputertechnik<br />

("Gedachte Subtraktion")<br />

Die Befehle sind anwendbar auf A, B, D, X und Y. Es wird jeweils ein Registerinhalt mit einem<br />

Speicherinhalt oder einer Konstanten verglichen (Ausnahme: CBA). Der Vergleich erfolgt durch<br />

eine Subtraktion ohne Anfallen des Ergebnisses.<br />

• Z-Flag = 1, wenn beide Operanden gleich sind<br />

• N-Flag = 1, wenn (Reg) < Operand (konegative Zahl) und kein arith. Überlauf<br />

• C-Flag = 1, wenn (Reg) < Operand (natürliche Zahl)<br />

Test- und Statusregisterbefehle 68


• V-Flag = 1, wenn arithm. Überlauf auftrat<br />

• CMPA #0 und TSTA sind von der Funktion her identisch<br />

Der Vergleich auf Null und "negativ" ermöglicht alle Vergleiche von Werten. Mathematisch<br />

gesehen werden die links stehenden Ungleichungen in die rechts stehenden umgesetzt:<br />

X 1 = X 2 X 1 - X 2 = 0<br />

X 1 < X 2 X 1 - X 2 < 0<br />

X 1 > X 2 X 1 - X 2 > 0<br />

Durch bedingte Sprungbefehle kann dann abhängig vom Ergebnis im Programm verzweigt werden.<br />

Es gibt 8-Bit- und 16-Bit-Vergleiche (je nach Wortbreite des Registers).<br />

• CMPA adr. (A) - (adr.) Flags<br />

• CMPB adr. (B) - (adr.) Flags<br />

• CPD adr. (D) - (adr., adr.+1) Flags<br />

• CPX adr. (X) - (adr., adr.+1) Flags<br />

• CPY adr. (Y) - (adr., adr.+1) Flags<br />

• CBA (A) - (B) Flags<br />

Bitorientierte Befehle<br />

Bitbefehle Statusregister<br />

Diese Befehle erlauben das komfortable Setzen und Rücksetzen einiger Bits des Statusregisters.<br />

clear carry flag X X X X X X X 0<br />

• CLC<br />

clear interrupt flag X X X 0 X X X X<br />

• CLI<br />

clear overflow flag X X X X X X 0 X<br />

• CLV<br />

set carry flag X X X X X X X 1<br />

• SEC<br />

set interrupt flag X X X 1 X X X X<br />

• SEI<br />

set overflow flag X X X X X X 1 X<br />

• SEV<br />

Bitbefehle Speicher<br />

Diese Befehle erlauben das Setzen oder Löschen einzelner Bits in Speicherworten. Als einzige<br />

Befehle haben sie zwei Operanden, die Adresse des zu ändernden Speicherbytes und eine konstante<br />

Maske. Da die Maske immer konstant sein muß, entfällt hier auch das "#"-Zeichen. Für jedes 1-Bit<br />

in der Maske wird das entsprechende Speicherbit gesetzt (BSET) oder gelöscht (BCLR).<br />

•<br />

BSET adr. mask<br />

Nachbildung:<br />

LDAA #mask<br />

ORAA adr.<br />

STAA adr.<br />

Mikrocomputertechnik<br />

Bitorientierte Befehle 69


•<br />

BCLR adr. mask<br />

Nachbildung:<br />

LDAA #mask<br />

COMA<br />

ANDA adr.<br />

STAA adr.<br />

Beeinflussung des Systemzustands<br />

Dies sind Befehle, welche die Programmausführung anhalten. Sie dienen der Synchronisation des<br />

Programmablaufs mit externen Ereignissen.<br />

Warte auf Interrupt (wait for interrupt)<br />

• WAI<br />

Ablage aller Register auf dem Stack, dann warten auf Interrupt.<br />

Stop<br />

• STOP<br />

Reaktion hängt ab von S-Flag im Statusregister:<br />

• S=1: next instruction (NOP)<br />

• S=0: halt clocks, enter standby mode, wait for XIRQ or IRQ<br />

Freigabe des STOP-Befehls:<br />

XIRQ & X=1: next instruction<br />

XIRQ & X=0: service interrupt<br />

IRQ & I=1: no activity<br />

IRQ & I=0: service interrupt<br />

TPA Statusreg. nach Akku A<br />

ANDA #$7F Freigabe (S-Flag auf 0)<br />

TAP Akku A nach Statusreg.<br />

Für den Fall S=0 und X=1 wird beim Aktivieren des XIRQ-Eingangs der Prozessor nach einem<br />

STOP-Befehl "aufgeweckt" und er macht im Programm ganz normal weiter.<br />

Sprungbefehle<br />

Mikrocomputertechnik<br />

Alle Sprungbefehle verändern den PC-Inhalt Programmausführung wird an anderer Stelle<br />

fortgesetzt. Das Statusregister wird nicht beeinflußt. Einige Befehle speichern Registerinhalte auf<br />

dem Stack oder holen Registerinhalte von dort wieder zurück.<br />

Beeinflussung des Systemzustands 70


Unbedingte Sprungbefehle (jump, branch)<br />

JMP adr. adr. PC<br />

Bei JMP erfolgt die Zielangabe mit vollständiger absoluter Adressierung (extended direct) oder<br />

indizierter Adressierung (mit X oder Y). Es ist ein Sprung im gesamten Adressraum möglich, denn<br />

der Operand ist ein 16-Bit-Wert.<br />

Der Sprungbefehl hat im <strong>Assembler</strong>programm normalerweise eine so genannte Marke als Operand.<br />

Diese Marke steht am Sprungziel, wie Sie da schon eingangs des Kapitels bei der Erklärung der<br />

beiden <strong>Assembler</strong>durchläufe sehen konnten. Der <strong>Assembler</strong> entnimmt die Adresse dieser Marke aus<br />

der Symboltabelle und fügt sie dem JMP-Befehl als Operand hinzu. Der Programmierer kann daher<br />

immer mit symbolischen Adressen arbeiten.<br />

BRA dest.<br />

Mikrocomputertechnik<br />

Hier wird keine absolute Adresse, sondern ein Offset relativ zum Program Counter angegeben (-128<br />

... +127). Hier berechnet der <strong>Assembler</strong> die Distanz zwischen BRA-Befehl und Sprungmarke und<br />

trägt als Offset eine 8-Bit-Zahl in Komplementntdarstellung ein.<br />

Bedingte Sprungbefehle ("Verzeigungsbefehle")<br />

Hier gibt es nur PC-relative Adressierung (branch conditionally). Es gibt acht Paare von zueinander<br />

komplementären Befehlen. Die Unterscheidung erfolgt in der jeweiligen Verzweigungsbedingung.<br />

Als Verzweigungsbedingung dienen (ein oder mehr) Bits des Statusregisters Verzweigung<br />

abhängig vom Ergebnis der vorhergehenden Operation ist die Bedingung erfüllt, erfolgt ein<br />

Sprung; im anderen Fall wird die Programmausführung beim nächsten Befehl fortgesetzt. Der<br />

<strong>Assembler</strong> übernimmt die Offset-Berechnung.<br />

Vergleich von Hochsprache und <strong>Assembler</strong>-Programmierung:<br />

Sprungbefehle 71


Die folgende Tabelle fasst alle bedingten Sprünge zusammen. Die erste Gruppe springt abhängig<br />

vom Wert bestimmter Flags des Condition Code Registers. Weitere Gruppen bilden die<br />

Sprungbefehle, die von arithmetischen Vergleichen abhängen.<br />

Achtung: Die Flags werden nicht nur bei arithmetischen Operationen oder Vergleichen<br />

(Compare-Befehl) gesetzt, sondern bei fast jedem Befehl (z. B. Ladebefehle, logische Operationen).<br />

Befehl Bedeutung Sprungbedingung<br />

BCC dest. carry clear C=0<br />

BCS dest. carry set C=1<br />

BVC dest. overflow clear V=0<br />

BVS dest. overflow set V=1<br />

BNE dest. result not equal<br />

zero<br />

Mikrocomputertechnik<br />

einfach (simple)<br />

Z=0 (BZC)<br />

BEQ dest. result equal zero Z=1 (BZS)<br />

BPL dest. result plus N=0 (BNC)<br />

BMI dest. result minus N=1 (BNS)<br />

natürlich (unsigned)<br />

BHI dest. higher Op1 > Op2<br />

BLS dest. lower or same Op1 = Op2<br />

konegativ (signed)<br />

Sprungbefehle 72


BGT dest. greater than Op1 > Op2<br />

BLE dest. less or equal Op1 = Op2<br />

bitabhängig<br />

BRCLR adr. mask dest springe, wenn die in der Maske mit "1" markierten Bits<br />

alle "0" sind alle Bits des Speicherbytes adr. werden<br />

mit der Maske UND-verknüpft und wenn das Ergebnis<br />

0 ist, wird gesprungen.<br />

BRSET adr. mask dest springe, wenn die in der Maske mit "1" markierten Bits<br />

alle "1" sind alle Bits des Speicherbytes adr. werden<br />

mit der Maske UND-verknüpft und wenn das Ergebnis<br />

gleich der Maske ist, wird gesprungen.<br />

Der Vergleich bei natürlichen Zahlen und konegativen Zahlen kann zu unterschiedlichen<br />

Ergebnissen führen. Betrachten Sie dazu die beiden folgenden Befehle:<br />

LDAA #$F8<br />

CMPA #$12<br />

Beim "unsigned"-Vergleich ist $F8 > $12, der Sprungbefehl BHI würde also ausgeführt. Betrachtet<br />

man die Zahlen jedoch als ganze (konegative) Zahlen, handelt es sich um die Zahl -8 dez. , die<br />

natürlich kleiner als $12 (18 dez. ) ist. Der Befehl BGT würde daher nicht ausgeführt.<br />

Betrachten Sie folgende Beispiele für die Anwendung von Sprungbefehlen, die Berechnen der<br />

Summe über ein Feld von Messwerten:<br />

FLENG EQU 100 ;Symbolische Konstante Feldlaenge vereinbaren<br />

FELD RMB FLENG ; Symbolischer Name und Speicherplatz<br />

; fuer ein Feld von 100 Bytes reservieren<br />

SUMME RMB 1 ; Symbolischer Name und Speicherplatz<br />

; fuer 1 Byte reservieren<br />

; das Indexregister X dient als Pointer!<br />

LDX #FELD ; symbolische Adresse des Feldanfangs ' X<br />

LDAB #FLENG ; Zaehler für die Feldlaenge initialisieren<br />

CLRA ; Summe in Akku A bilden, -> erst loeschen<br />

LOOP ADDA 0,X ; Feldelemente indiziert adressieren<br />

DECB ; Zaehler um eins vermindern<br />

; Feld abgearbeitet (bei 0 angekommen)?<br />

BEQ FERTIG ; wenn ja (Zaehler = 0): fertig<br />

INX ; sonst: Indexregister (Zeiger!) erhoehen<br />

BRA LOOP ; und weitermachen in der Schleife<br />

FERTIG STAA SUMME ; Ergebnis abspeichern<br />

In der Sprache C könnte das etwa folgendermaßen aussehen, wobei feld als Array der Größe<br />

fleng vereinbart ist.<br />

feldptr = &feld[0];<br />

summe = 0;<br />

Mikrocomputertechnik<br />

Sprungbefehle 73


i = fleng;<br />

do<br />

{<br />

summe = summe + *feldptr;<br />

feldptr++;<br />

i--;<br />

} while(i>0);<br />

Unterprogrammsprünge (jump/branch to subroutine)<br />

Die Unterprogrammtechnik ist ein wertvolles Hilfsmittel zur modularen Programmierung in<br />

<strong>Assembler</strong>. Darüber hinaus wird bei Verwendung von Unterprogrammen (UP) Speicherplatz für<br />

Programme gespart, wenn sie in einem Programm mehrfach verwendet (aufgerufen) werden.<br />

Gleiche oder sehr ähnliche Befehlssequenzen in einem Programm sollten deshalb immer zu<br />

Unterprogrammen zusammengefasst werden, wie eine Funktion in C. Ein weiterer Nutzen: Die<br />

Programme werden dadurch leichter zu lesen. Voraussetzung sind natürlich aussagekräftige Namen<br />

für die Unterprogramme und eine möglichst gute Kommentierung, auch im Programmkopf.<br />

Unterprogramme können außerdem geschachtelt, das heißt, von Unterprogrammen aufgerufen<br />

werden.<br />

UP können innerhalb der Programme, die diese verwenden, oder außerhalb derselben in<br />

UP-Bibliotheken definiert sein. Sie sollen möglichst universell programmiert und damit für<br />

wechselnde Datenwerte geeignet sein. Folglich müssen Eingabe- und Ausgabeparameter übergeben<br />

werden. Unterprogramme müssen auch an beliebiger Stelle des Hauptprogramms aufgerufen<br />

werden können (und damit auch an mehreren Stellen), sie sollten daher den Inhalt derjenigen<br />

Register sichern (z. B. auf dem Stack), die innerhalb des UP verändert werden. Das aufrufende<br />

Programm muss die Initialisierung des Stackpointers vornehmen, beim Aufruf des UP die<br />

Eingabeparameter an vereinbarter Stelle bereitstellen und eventuell Platz für Ausgabeparameter<br />

reservieren.<br />

Es wird allerdings ein Mechanismus notwendig, der die Rückkehr aus dem Unterprogramm zum<br />

Befehl nach dem Unterprogramm-Aufruf sicherstellt. Der Einsprung in ein Unterprogramm erfolgt<br />

deshalb mit einem speziellen Sprungbefehl, der automatisch den aktuellen Befehlszählerstand<br />

(Rücksprungadresse) auf den Systemstack rettet, bevor er mit der Sprungziel-Adresse überschrieben<br />

wird. Der Rücksprung nach Beendigung des Unterprogramms zurück ins aufrufende Programm<br />

besteht dann nur aus einem Zurückschreiben der beiden obersten Stack-Bytes in den Befehlszähler.<br />

Der "Jump to Subroutine" dient zum Sprung zu einem Unterprogramm (Function, Procedure in<br />

höheren Programmiersprachen). Der Unterschied zum "normalen" Sprung besteht darin, dass am<br />

Ende des Unterprogramms mit einem "Return from Subroutine" (RTS) an die Stelle des "Aufrufs"<br />

(Absprungs) zurückgekehrt werden muss.<br />

JSR adr.<br />

Mikrocomputertechnik<br />

• absolute Adressierung<br />

• wie JMP adr., aber zusätzlich Ablage des PC (der die Adresse des nächsten Befehls<br />

enthält) auf dem Stack Möglichkeit der Rückkehr<br />

Beim JSR wird also vor dem Überschreiben des PC der aktuelle PC-Stand auf den Stack gerettet,<br />

Unterprogrammsprünge (jump/branch to subroutine) 74


d.h. der Stack wächst dabei um 2 Bytes! So kann der RTS-Befehl auf dem Stack den ursprünglichen<br />

PC-Stand wiederfinden (Rücksprung aus dem Unterprogramm zurück in das aufrufende<br />

Programm).<br />

BSR dest.<br />

• Offset wird immer PC-relativ angegeben (-128 ... +127)<br />

• <strong>Assembler</strong> übernimmt Offset-Berechnung<br />

RTS (return from subroutine)<br />

Der RTS-Befehl dient dazu, aus einem Unterprogramm in das "aufrufende" Programm<br />

zurückzukehren. Notwendige Voraussetzung ist, dass vom aufrufenden Programm per JSR- oder<br />

BSRBefehl in das Unterprogramm gesprungen wurde, denn nur diese Befehle retten vor dem<br />

Sprung den Inhalt des PC auf den Stack.<br />

• Rücksprung aus Unterprogramm<br />

• Die Rücksprungadresse wird vom Stack geholt<br />

• letzter Befehl eines Unterprogramms<br />

• PULX<br />

JMP 0,X<br />

Unterprogramme lassen sich beliebig schachteln.<br />

Typische Anfängerfehler:<br />

Mikrocomputertechnik<br />

• Ein mit RTS logisch abgeschlossenes Unterprogramm wird mit JMP, BRA oder bedingtem<br />

Branch angesprungen! (Was geschieht?).<br />

• Ein mit JSR oder BSR angesprungenes Unterprogramm wird mit einem JMP, BRA oder<br />

bedingten Branch verlassen! (Was geschieht?)<br />

Unterprogrammsprünge (jump/branch to subroutine) 75


Programmunterbrechungsbefehle<br />

SWI (software interrupt)<br />

• Sprung in eine Interrupt-Service-Routine (ISR)<br />

• Startadresse ist Interruptvektor (steht in HW-mäßig festgelegter Speicherzelle)<br />

• vorher Ablage aller Register auf dem Stack<br />

• Anwendung:<br />

z. B. positionsunabhängiger Aufruf von BS-Routinen; Parameter in Registern oder auf dem<br />

U-Stack<br />

RTI (return from interrupt)<br />

• Rücksprung aus einer ISR<br />

• Rückladen der Register vom Stack<br />

• letzter Befehl der ISR<br />

Reine Verzögerungsbefehle<br />

• NOP No Operation<br />

• BRN Branch Never<br />

Anwendungen:<br />

• Zeitverzögerung (z. B. Laufzeitangleichung)<br />

• Platzhalter für spätere Programmverzeigungen (bei der Programmentwicklung)<br />

• Platz für Label<br />

• "Patchen" von Programmen (Ändern des Maschinencodes)<br />

3.6 Stapelspeicher (Stack)<br />

Mikrocomputertechnik<br />

Zum Zwischenspeichern von Information ist ein Register(-satz) prinzipiell sehr gut geeignet. Das<br />

Problem ist nur seine sehr begrenzte Kapazität. Legt man temporäre Zwischenspeicher im<br />

Arbeitsspeicher an, so muss man Geschwindigkeitseinbußen in Kauf nehmen aber vor allem ist die<br />

Verwaltung derartiger "Hilfszellen" umständlich und zeitraubend. Eine Lösung dieses Problems<br />

bietet ein Stapelspeicher (Stack). Dies ist ein wortorganisierter Speicher mit implizitem Zugriff<br />

LIFO-Speicher (Last In First Out). Die Realisierung beim 68HC11 erfolgt als externer Stack<br />

(Software-Stack). Er ist Teil des Arbeitsspeichers, Die automatische Adressierung erfolgt über den<br />

Stapelzeiger (Stackpointer, S). Der Stackpointer ist ein 16-Bit-Register und zeigt immer auf die<br />

nächste freie Zelle. Der Stack wächst zu kleiner werdenden Adressen ("nach unten").<br />

Am Programmanfang muß der Stack mit einem sinnvollen Wert besetzt werden.<br />

Die Vorteile des SW-Stacks mit Stackpointer-Adressierung sind unter anderem:<br />

• Kapazität des Stacks ist der jeweiligen Anwendung anpaßbar<br />

• keine Vereinbarung von Hilfszellen erforderlich<br />

Programmunterbrechungsbefehle 76


• keine Adreßangabe bei Verwendung des Stacks nötig<br />

Befehle für den Stack-Zugriff<br />

• Stack dient zum schnellen Ablegen von Registerinhalten<br />

• Befehle zum Schreiben in den Stack: PSHx ("Push")<br />

• Befehle zum Lesen aus dem Stack: PULx ("Pull")<br />

• Beim PSH-Befehl wird der SP nach dem Ablegen eines Register-Inhalts decrementiert<br />

• Beim PUL-Befehl wird der SP vor dem Holen eines Register-Inhalts incrementiert<br />

• Bei 16-Bit-Registern wird das LSB zuerst abgelegt (höhere Adr.),dann das MSB (niedrigere<br />

Adr.) MSB wird beim PUL zuerst geladen<br />

Schreiben in den Stack:<br />

♦ PSHA Register A Stack<br />

♦ PSHB Register B Stack<br />

♦ PSHX Register X Stack<br />

♦ PSHY Register Y Stack<br />

Lesen aus dem Stack:<br />

♦ PULA Stack Register A<br />

♦ PULB Stack Register B<br />

♦ PULX Stack Register X<br />

♦ PULY Stack Register Y<br />

Man kann normalerweise nur immer das "oberste" Stackelement lesen. Die Stack-"Verwaltung"<br />

muss sehr sorgfältig geschehen, damit jederzeit klar ist, welche Information gerade "oben" liegt<br />

oder - besser ausgedrückt - wo der Stackpointer gerade hinzeigt. Unsauberer Umgang mit dem<br />

Stack führt fast unweigerlich zu unverständlichen Programmabstürzen!<br />

Anwendung des Stack<br />

Mikrocomputertechnik<br />

Der Stack dient dem Zwischenspeichern von Registerinhalten um:<br />

• Register anderweit verwenden zu können<br />

• Parameterübergabe bei Unterprogrammen (siehe später)<br />

• "Retten" von Registerinhalten beim Unterprogrammaufruf: Zu Beginn des UP werden die<br />

verwendeten Register auf dem Stack abgelegt und vor Rückkehr zum Hautprogramm<br />

wieder restauriert<br />

• Speicherung der Rücksprungadresse bei Unterprogrammsprüngen: Die Abspeicherung<br />

erfolgt automatisch auf dem Stack bei JSR und BSR. Bei RTS wird die Rücksprungadresse<br />

automatisch vom Stack geladen.<br />

• Ablage des Programmstatus bei Interrupts durch CPU auf dem Stack. Automatisches Laden<br />

des Programmstatus bei RTI.<br />

3.6 Stapelspeicher (Stack) 77


Wichtig ist der sorgfältige und überlegte Umgang mit Stack- und SP-Operationen. Damit kein<br />

Stack-Überlauf(-Unterlauf) auftritt:<br />

• gleichviele PSH- und PUL-Befehle<br />

• PSH- und PUL-Befehle "symmetrisch", z. B.:<br />

•<br />

PSHA<br />

PSHB<br />

.<br />

.<br />

.<br />

PULB<br />

PULA<br />

eventuell Dekrementieren oder Incrementieren des SP nötig<br />

3.7 Unterprogramme (Subroutines)<br />

Unterprogramme sind Programmteile (=Befehlsfolgen), die mit einem Namen versehen sind und<br />

unter diesem Namen aufgerufen werden. UP können in den Programmen, die diese verwenden, oder<br />

außerhalb derselben definiert sein UP-Bibliotheken. Sie sollen möglichst universell<br />

programmiert (und damit für wechselnde Datenwerte) sein Parameter müssen übergeben werden<br />

(Eingabe- und Ausgabeparameter). UP müssen an beliebiger Stelle des Hauptprogramms<br />

aufgerufen werden können (und damit auch an mehreren Stellen), sie sollten daher den Inhalt<br />

derjenigen Register sichern (z. B. auf dem Stack), die innerhalb des UP verändert werden. Typische<br />

Anwendungen der UP-Technik sind:<br />

• Verwendung gleicher Programmteile an mehreren Programmstellen<br />

• Rückgriff auf Programmbibliotheken<br />

• Übersichtlicher Aufbau von Programmen (modular + strukturiert) Programmerstellung<br />

durch mehrere Programmierer möglich<br />

Programme mit UP dauern etwas länger als ohne (meist überwiegen jedoch die Vorteile der UP).<br />

Anmerkungen zur Dokumentation:<br />

• Dokumentation ist wichtig für problemlose und fehlerfreie Verwendung von UP (besonders<br />

von fremden UP)<br />

• Die innere Struktur der UP muß für deren Anwendung nicht unbedingt bekannt sein<br />

• Folgende Informationen sind notwendig:<br />

♦ Zweck (Beschreibung der Aufgabe) des UP<br />

♦ Beschreibung der Ein- und Ausgabeparameter<br />

♦ Angabe der veränderten Register und Speicherplätze<br />

♦ Anwendungs-(Aufruf-) Beispiel<br />

• Dokumentation soll bereits im Programmlisting durch entsprechende Kommentare<br />

vorgenommen werden<br />

Aufgaben des aufrufenden Programms:<br />

Mikrocomputertechnik<br />

• Initialisierung des/der Stackpointer (Hauptprogramm)<br />

• Bereitstellen der Eingabeparameter an vereinbarter Stelle<br />

• eventuell Platzreservierung für Ausgabeparameter<br />

• Aufruf des UP<br />

• falls erforderlich, Wegspeichern der Ausgabeparameter<br />

Anwendung des Stack 78


Unterprogramm-Sprungbefehle<br />

sind spezielle Sprungbefehle, die vor dem Sprung die Rücksprungadresse auf dem Stack sichern.<br />

Beim Rücksprung wird diese Adresse automatisch geladen.<br />

Sprung in das UP: JSR, BSR<br />

Unterscheidung in der Adressierungsart. Wirkung:<br />

• Speichern des PC auf dem Stack (da der Sprungbefehl bereits geholt und dekodiert wurde,<br />

zeigt der PC auf den nächsten Befehl (= Rücksprungadresse)). Zuerst Speicherung des<br />

PC-LSB, dann PC-MSB.<br />

• Laden des PC mit der Startadresse des UP<br />

Rücksprung aus dem UP: RTS<br />

Letzter Befehl des UP, Wirkung:<br />

• Laden der Rücksprungadresse vom Stack in den PC<br />

Achtung: Vor dem Rücksprung muß der Stackpointer i. a. auf die gleiche Adresse zeigen, wie nach<br />

dem Ansprung des UP Sorgfalt bei Stackoperationen notwendig! Beim UP-Sprung (und<br />

Rücksprung) wird nur der PC-Inhalt geändert, der Inhalt aller anderen Register bleibt erhalten.<br />

Register können zur Parameterübergabe verwendet werden<br />

Im UP verwendete Register müssen gegebenenfalls gesichert werden<br />

Vorteil der Speicherung der Rücksprungadresse auf dem Stack:<br />

• Aufruf weiterer UP durch ein UP möglich verschachtelte UP<br />

• Rückkehradresse immer am Stack-Ende<br />

• Schachtelungstiefe nur durch Stackgröße begrenzt<br />

Parameter-Übergabe<br />

Eingabeparameter: Werte UP<br />

Ausgabeparameter: Werte UP<br />

Möglichkeiten der Parameterübergabe:<br />

• Direkte Übergabe in Registern Elegante Methode, jedoch durch Registerzahl begrenzt<br />

• Über festen Speicherbereich inflexibel (manchmal bei BS-Aufrufen)<br />

• Über variablen Speicherbereich (Parameterblock) Anfangsadresse des Parameterblocks<br />

wird in einem Register übergeben indirekte Parameterübergabe<br />

• Über den Stack Ablage im aufrufenden Programm mittels PSHx. Da die Parameter vor dem<br />

UP-Sprung abgelegt wurden (und somit der PC-Stand der letzte Wert auf dem Stack ist),<br />

sind sie mit PULx nicht ohne weiteres erreichbar (außer Rücksprungadresse wird<br />

zwischengespeichert). Der Zugriff ist daher komplizierter. Vom HP kann vor UP-Aufruf<br />

Stackplatz für Ausgabeparameter freigehalten werden (Nach Rückkehr Bereinigung des<br />

Stack nötig).<br />

Beispiel: Verzögerungsroutine<br />

Mikrocomputertechnik<br />

Es soll eine Verzögerung von 1 ms erreicht werden. Das Prinzip der Routine ist recht einfach: Ein<br />

Akkumulator wird mit einem Anfangswert besetzt und dann in einer Schleife solange<br />

Unterprogramm-Sprungbefehle 79


dekrementiert, bis sein Wert Null geworden ist.<br />

ORG PROG Programm soll bei Adresse PROG beginnen<br />

MAIN BSR VERZ Aufruf Unterprogramm<br />

STOP BRA STOP Endlosschleife, stoppt Programm<br />

("Wiederbeleben" des Computers mit Reset)<br />

* Verzögerungs-Unterprogramm<br />

* Verzögerungszeit: 1 ms<br />

* Keine Parameter<br />

*<br />

VERZ LDAA #221 Anfangswert (Konstante) laden (siehe unten)<br />

VZ NOP No Operation (Zeitverzoegerung)<br />

NOP No Operation (Zeitverzoegerung)<br />

DECA A runterzählen bis 0<br />

BNE VZ solange A != 0, weiterer Durchlauf<br />

RTS Verzögerung erreicht (A = 0)<br />

END<br />

Berechnung der Verzögerungszeit: Aus der Befehlstabelle kann man die Anzahl der Taktzyklen für<br />

jeden Befehl entnehmen. Wenn man nun noch die Taktfrequenz weiß, kann man die Ablaufzeit<br />

eines Programms ausrechnen. Wir müssen vier Zeiten wissen:<br />

tl Ausführungszeit LDAA 2 Taktzyklen<br />

td -"- DECA + 2 NOP 6 -"-<br />

tb -"- BNE 3 -"-<br />

tr -"- RTS 5 -"-<br />

Bei unserem Praktikumsrecher dauert ein Taktzyklus 0,5 Mikrosekunden. Die Gesamtzeit tg ergibt<br />

sich zu:<br />

tg = 0,5 * n * (td + tb) + tl + tr<br />

= 0,5 * n * (6 + 3 ) + 2 + 5<br />

= 0,5 * (n * 9 + 7)<br />

Da tg = 1 ms = 1000 Mikrosekunden sein soll, berechnet sich n zu<br />

n = (1000 - 3,5) / 4,5<br />

= 996,5 / 4,5<br />

= 221,44<br />

n = 221<br />

Es ergibt sich also ein kleiner Fehler; unsere Schleife ist einen knappen Taktzyklus zu langsam.<br />

Will man wirklich genaue Zeitintervalle, greift man auf den integrierten Timer zurück (siehe<br />

später).<br />

Im gezeigten Beispiel "Verzögerungsroutine" ist die maximale Verzögerungszeit durch die<br />

Wortbreite des Akku A (8 Bit 0..255) auf etwas mehr als 1 ms begrenzt.<br />

Für größere Verzögerungen:<br />

Mikrocomputertechnik<br />

• Verlängerung von ts durch zusätzliche Befehle (NOP, BRN)<br />

• Verwendung eines 16-Bit-Registers (z. B. D, X, Y)<br />

• Schachtelung von Schleifen<br />

• Durch Parameter erhält man UP mit variabler Verzögerungszeit<br />

Beispiel: Gegeben ist folgende Verzögerungsroutine mit 16-Bit-Register:<br />

Parameter-Übergabe 80


* Verzögerungs-Unterprogramm<br />

* Verzögerungszeit: 500 ms<br />

* Keine Parameter<br />

*<br />

; delay dauert 3 + 5 + 4 + 5 + $f000*16 cycl<br />

; = 8,5 + $f000*8 us = 491528,5 us<br />

delay pshx ; X retten, 4 cycl<br />

ldx #$f000 ; Anfangswert laden, 3 cycl<br />

delay1 nop ; Zeit verschwenden, 5 x nop = 10 cycl<br />

nop<br />

nop<br />

nop<br />

nop<br />

dex ; X run<br />

bne delay1 ; solange X != 0 weiter, 3 cycl<br />

pulx ; X restor, 5 c<br />

rts ; und w<br />

3.8 Interrupts (Programmunterbrechungen)<br />

HAlle modernen Mikroprozessoren besitzen deshalb mehr oder weniger ausgefeilte<br />

Hardware-Mechanismen zur Programmunterbrechung durch solche Ereignisse. Ein<br />

Hardware-Ereignis erzwingt einen "Unterprogrammsprung" zu einem vorbereiteten<br />

Bearbeitungs-Programm, der so genannten Interrupt-Service-Routine (ISR). Die Ähn-lichkeit des<br />

Interrupt mit einem Unterprogrammsprung (JSR) ist tatsächlich groß. Das Auftreten des<br />

Interrupt-Request-Signals auf dem Bus wird vom Mikroprogramm am Ende jedes Befehlszyklus<br />

geprüft und führt zu einem Sprung zum Beginn der ISR. Ein JSR zu einem bestimmten<br />

Unterprogramm kann an beliebigen Stellen im Programm vorkommen, der Rücksprung RTS sorgt<br />

für die Rückkehr an die richtige Stelle im aufrufenden Programm. Ein Interrupt dagegen kann<br />

prinzipiell nach jedem beliebigen Befehl des Programms wirksam werden, dementsprechend muss,<br />

wie beim JSR, der PC-Stand gerettet werden; auch das erledigt die Ablaufsteuerung bei der<br />

Annahme des Interrupt Request, genau wie beim JSR. Die Interrupt-Service-Routine wird mit<br />

einem ähnlichen Befehl wie ein Unterprogramm verlassen (RTI statt RTS), denn auch hier muss der<br />

Rücksprung wieder zur Unterbrechungsstelle zurückführen. Man unterscheidet beim 68HC11<br />

Interrupts, die von Hardwaresignalen ausgelöst werden (XIRQ, IRQ und RESET) und den internen<br />

Interruptquellen (interne Peripherie-bausteine bzw. "illegal Operation"). Außerdem gibt es einem<br />

Befehl (SWI), der ebenfalls einen Interrupt auslöst. Ein weiteres Unterscheidungskriterium ist die<br />

Maskierbarkeit. Der "normale" Interrupt ist nur dann wirksam, wenn das entsprechende Maskenbit<br />

im CC-Register gelöscht ist (gleich 0). Die Signale RESET und XIRQ sind nicht maskierbar, sie<br />

werden deshalb auch als "nicht maskierbare Interrupts" (NMI) bezeichnet. Der XIRQ weist dabei<br />

noch eine Besonderheit auf: er ist nach einem RESET so lange gesperrt (maskiert), bis er durch<br />

Nullsetzen von Bit 6 im CC-Register freigegeben wird. Danach ist er nicht mehr sperrbar!<br />

Anwendungen:<br />

Mikrocomputertechnik<br />

• Quasiparallele Ausführung mehrerer Programme (normalerweise nur Hauptprogramm und<br />

ISR) - Parallelarbeit von Programmen und externen Geräten (interruptgesteuerter<br />

3.8 Interrupts (Programmunterbrechungen) 81


E/A-Transfer)<br />

• Reaktion auf unvorhersehbare Ereignisse (z. B. Spannungsabfall)<br />

• Testen von Programmen mittels Breakpoints (SW-Interrupt)<br />

• Aufruf von Betriebssystemfunktionen (SW-Interrupt)<br />

Aufgaben der CPU bei einen Interrupt:<br />

1. Abspeichern von Registerinhalten (bei 68HC11 im Stack)<br />

2. Setzen der Interruptmaske zum Sperren weiterer Interrupts<br />

(Unter Berücksichtigung der Priorität)<br />

3. Laden der Startadresse (= Interrupt-Vektor) der ISR in den PC<br />

♦ Der Interruptvektor steht an einer hardwaremäßig vorgegebenen Adresse, die von<br />

der Art des Interrupts abhängt.<br />

♦ Je nach Interrupt-Art wird die entsprechende Interrupt-Vektor-Adresse auf den Bus<br />

gegeben.<br />

♦ In den so adressierten Speicherzellen steht dann die Startadresse der ISR (=<br />

Interrupt-Vektor), die in den PC gebracht wird Start der ISR<br />

4. Fortsetzung des unterbrochenen Programms nach der Interrupt-Bearbeitung: RTI-Befehl<br />

♦ weggespeicherte Register werden vom Stack geholt<br />

♦ PC erhält Adresse des nächsten Befehls des unterbrochenen Programms<br />

Im allgemeinen wird ein Hardware-IRQ erst am Ende eine Befehlszyklus bedient. Außer dem PC<br />

und dem Stackpointer werden keine Register beeinflußt. Interrupts können geschachtelt werden (3<br />

Ebenen).<br />

Interruptsystem des 68HC11:<br />

Signal RESET Unbedinger Abbruch und Neustart<br />

Signal XIRQ & (X-Bit = 0) Unbedingte Unterbrechung (non maskable interrupt)<br />

Signal IRQ & (I-Bit = 0)<br />

Mikrocomputertechnik<br />

Bedingte Unterbrechung (interrupt request)<br />

(kann auch interne Ursachen haben)<br />

I-Bit beeinflußbar durch die Befehle SEI/CLI<br />

Befehl SWI Befehlsgesteuerte Unterbrechung (software interrupt)<br />

Befehl Illegal Opcode Nicht implementierter Befehl<br />

Beim Auftreten eines Interrupts wird das I-Bit auf 1 gesetzt (Sperren IRQ), bei Reset und XIRQ<br />

auch das X-Bit. Beim RTI wird durch das Zurückschreiben des Statusregisters diese Sperre<br />

automatisch wieder aufgehoben. Das X-Bit kann nicht per Programm beeinflußt werden.<br />

Jedem dieser Interrupts ist eine eindeutige Interrupt-Vektor-Adresse (= Adresse, unter welcher der<br />

Interrupt-Vektor, also die Adresse der Interrupt-Serviceroutine, zu finden ist) zugeordnet:<br />

Interruptsystem des 68HC11: 82


Mikrocomputertechnik<br />

Zu jeder Interrupt-Art ist eine eigene ISR möglich. Zumindest der RESET-Vektor muß bei<br />

Einschalten vorhanden sein ROM im höchsten Adreßbereich nötig.<br />

Beispiel: Starten der Interrupt-Service-Routine für XIRQ<br />

Grundsätzlich gilt für Programme mit Interrupt-Serviceroutinen, daß vier Schritte für die<br />

Initialisierung (zu Beginn des Hauptprogramms) nötig sind:<br />

1. Setzen des System-Stackpointers<br />

Solange er nicht gesetzt ist, werden keine Interrupts entgegengenommen.<br />

2. Initialisierung der Hardware<br />

In der Regel werden Interrupts von E/A-Bausteinen ausgelöst. Diese müssen entsprechend<br />

programmiert werden.<br />

3. Setzen des Interruptvektors<br />

Siehe oben.<br />

4. Freigeben des Interrupts durch Setzen des entsprechenden I-Flags im CC-Register auf 0.<br />

Bei einer ISR für XIRQ entfällt dieser Punkt natürlich.<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Interruptsystem des 68HC11: 83


Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 02. Jul 2012<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Interruptsystem des 68HC11: 84


4. Bausteine des Systems M68HC11<br />

4.1 Mikroprozessor 68HC11<br />

Der Prozessor<br />

• ist zuständig für die sequentielle Instruktionsausführung (Instruktion entspricht einer<br />

Zustandsänderug im Speicher oder in einem Register).<br />

• Ausführung synchron durch internen Taktgenerator (dieser wird beim 68HC11 durch einen<br />

externen Quarz-Oszillator gesteuert).<br />

• Systemtakt des 68HC11: 2 MHz<br />

(entsprach zur Entwicklungszeit der maximalen Taktfrequenz eines externen EPROMs)<br />

• Systemtakt wird für externe Zwecke (an Pin E) zur Verfügung gestellt.<br />

• eine Instruktion benötigt beim 68HC11 mindestens 2 Takte = 1 Mikrosekunde<br />

• längste Operation: Division (FDIV) mindestens 41 Takte = 20,5 Mikrosekunden<br />

Beim 68HC11 gibt es diverse Varianten, die sich hauptsächlich im integrierten Speicher<br />

unterscheiden. Zusammenfassend ergeben sich folgende Eigenschaften:<br />

• CPU mit 8 Bit Daten und 16 Bit Adressen<br />

• 256 Byte RAM<br />

• 2 - 8 KByte ROM<br />

• 515 - 2048 Byte EEPROM<br />

• Asynchrone serielle Kommunikationsschnittstelle<br />

• Echtzeit-Interrupts<br />

• 38 digitale Ein- und Ausgänge, teils mit Handshake-Funktion<br />

• 2 Hardware-Interrupts<br />

• Impulszähler<br />

• 16-Bit-Timer-System mit 3 Zeitmeß-Eingängen und 4 PWM-Ausgängen<br />

• Analog-Digital-Wandler mit 8 gemultiplexten Eingängen<br />

• Synchrone serielle Schnittstelle<br />

Der Prozessor arbeitet mit einer Taktfrequenz von 2 MHz, die von einem 8-MHz-Quarz abgeleitet<br />

wird. Die Betriebsspannung beträgt 5 V, die Stromaufnahme etwa 15 mA, wobei jedoch bei<br />

Batteriebetrieb der Mikrocontroller in Arbeitspausen durch Software-Befehle in einen<br />

Stromsparzustand geschaltet werden kann.<br />

4. Bausteine des Systems M68HC11 85


Die wichtigsten Anschlußpins<br />

Name Anzahl Art Bedeutung<br />

Vss<br />

(GND)<br />

1 E Versorgungsspannung 0V<br />

VDD 1 E Versorgungsspannung 5V<br />

EXTAL 1 E Quarz (oder externer, CMOS-kompatiblerTaktgenerator)<br />

XTAL 1 A Quarz<br />

E 1 A Bus-Takt L: interne Aktivität H: externe Aktivität (Datenverkehr)<br />

RESET 1 E Rücksetzen des M68HC11 X-Bit und I-Bit = 1, (FFFE,FFFF)<br />

Befehlszähler<br />

MODA 1 E L: single chip mode (nur interne Komponenten) H: expanded mode<br />

(externe Komponenten möglich)<br />

MODB 1 E L: special variation (down load or test) H: normal variation (applications)<br />

XIRQ 1 E unbedingte Unterbrechung (non maskable interrupt) maskiert durch X-Bit<br />

im CCR<br />

IRQ 1 E bedingte Unterbrechung (interrupt request) maskiert durch I-Bit im CCR<br />

PA i<br />

3<br />

4<br />

1<br />

E<br />

A<br />

E/A<br />

Mikrocomputertechnik<br />

Port A: 3 Digitaleingänge, 4 Digitalausgänge, 1 Digitalein/ausgang oder<br />

Pulsakku-Eingang (unterbrechungsfähig)<br />

PB A15-8 8 A Port B: 8 Digitalausgänge oder 8 Adressleitungen<br />

PCAD7-0 8 E/A Port C: 8 Digitalein/ausgänge oder 8 Adress/Datenleitungen (gemultiplext)<br />

STRA AS 1 E/A Steuerleitung (Eingang, unterbrechungsfähig) oder<br />

Adress/Datenleitungs-Steuerung<br />

1 A Steuerleitung (Ausgang) oder Datenrichtung (read/write)<br />

Der Prozessor 86


STRB<br />

R/W<br />

PD 6 E/A Port D: 6 Digitalein/ausgänge oder 1 SCI und 1 SPI<br />

PE 8 E Port E: 8 Digitaleingänge oder 8 Analogeingänge für A/D-Wandler<br />

Vrefh 1 E Referenz-Spannung für A/D-Wandler<br />

Vrefl 1 E Referenz-Spannung für A/D-Wandler<br />

Reset<br />

Mikrocomputertechnik<br />

Der Reset-Eingang wird dazu benutzt, den Mikroprozessor in einen definierten Anfangszustand zu<br />

bringen. Da für einige der intern ablaufenden Vorgänge zwingend ein Oszillatortakt benötigt wird,<br />

sollte ein Reset-Signal erst nach Stabilisierung des Oszillator-Kreises gegeben werden. Sobald der<br />

Prozessor die Reset-Bedingung gültig erkennt, werden alle internen Schaltungsgruppen in einen<br />

definierten Anfangszustand versetzt:<br />

• Nach dem Reset-Signal lädt die CPU den Reset-Vektor aus dem der gewählten Betriebsart<br />

entsprechenden Adressbereich in den Programcounter. Dies ist ($FFFE, $FFFF) im<br />

Normalbetrieb oder ($BFFE, $BFFF) in den Betriebsarten "Special Test" und "Bootstrap".<br />

Der Stackpointer und die anderen Register der CPU sind nach dem Reset weiterhin<br />

undefiniert, nur das X- und das I-Bit im CCR-Register werden gesetzt, um undefinierte<br />

Interrupts zu verhindern.<br />

• Das INIT-Register wird beim Reset auf $01 gesetzt. Damit liegt das interne Prozessor-RAM<br />

im Adressbereich $0000 bis $OOFF, die Control-Register liegen auf den Adressen $1000 bis<br />

$103F. Der Prozessor-Reset hat keinen Einfluß auf das Mapping der ROM- und<br />

EEPROM-Bereiche, da die beiden Bits, die die Zugriffe auf diese Bereiche kontrollieren,<br />

EEPROM-Zellen des Config-Registers sind.<br />

• Durch das Reset-Signal wird das prozessorinterne Timer-System auf $0000 gesetzt, alle<br />

Prescaler-Bits werden gelöscht und sämtliche Output-Compare-Register erhalten den Wert<br />

$FFFF. Der Inhalt der Input-Capture-Register ist undefiniert. Damit keine undefinierten<br />

Signale an den E/A-Pins des Prozessors durch das Timer-Systern ausgegeben werden können,<br />

werden alle Output-Compare-Systeme so initialisiert, daß sie keinen Einfluß auf die logischen<br />

Zustände der zugeordneten E/A-Pins haben. Die Flankenerkennung der drei<br />

Input-Capture-Register wird durch das Reset-Signal ausgeschaltet, alle dem Timer-System<br />

zugeordnete Interrupt-Flags werden gelöscht und alle neun Timer-Interrupt-Quellen werden<br />

gesperrt.<br />

• Die Behandlung der E/A-Ports bei einem Reset-Signal ist von der eingestellten Betriebsart<br />

abhängig; in der Betriebsart "Extended" sind die 18 E/A-Pins des 68HC11 den verschiedenen<br />

Bussystemen zugeordnet. In der Betriebsart "Single-Chip", werden alle Interrupt-Quellen, die<br />

mit den E/A-Ports in Verbindung stehen, gelöscht. Dazu gehören die Bits STAF, STAI und<br />

HNDS im PIOC-Register. Die Betriebsart der E/A-Ports wird durch das gelöschte HNDS-Bit<br />

auf "Simple Strobed E/A" festgelegt.<br />

Port C ist nach dem Reset als Eingang definiert, sein Datenrichtungsregister demnach mit $00<br />

besetzt. Port B ist als Ausgang mit auf Null gesetzten Ausgangssignalen initialisiert. Der<br />

flankenempfindliche Eingang STRA reagiert auf die ansteigende Flanke eines Signals.<br />

• Nach einem Reset-Signal ist die Baud-Rate des seriellen Interfaces in jedem Fall undefiniert<br />

und muß durch das Anwenderprogramm festgelegt werden. Sämtliche Interrupt-Quellen der<br />

seriellen Schnittstelle sind deaktiviert und die Zuordnung der Empfangs- und Sendeleitungen<br />

zu den entsprechenden E/A-Pins ist aufgehoben, so daß diese Pins als normale E/A-Pins zur<br />

Verfügung stehen. Das Übertragungsformat der seriellen Schnittstelle ist auf 8 Bit eingestellt.<br />

Im Statusregister des seriellen Systems werden die TDRE- und TC-Bits gesetzt.<br />

• Das Puls-Akkumulator-System des 68HC11 ist nach einem Reset ausgeschaltet, der Eingang<br />

(PAI) ist als normaler E/A-Pin geschaltet.<br />

Die wichtigsten Anschlußpins 87


• Die interne Prozessorüberwachung (COP) verhält sich entsprechend dem NOCOP-Bit im<br />

Config-Register(NOCOP-Bit = 1: Überwachung aus, NOCOP-Bit = 0: Überwachung ein). In<br />

diesem Fall wird das Time-Out-Intervall des COP-Systems auf die kleinste verfügbare Zeit<br />

gesetzt.<br />

• Das serielle Peripherie-Interface (SPI) wird durch ein Reset-Signal ausgeschaltet. Die<br />

zugehörigen E/A-Leitungen stehen als normale E/A-Pins zur Verfügung.<br />

• Die Definition des A/D-Wandler-Systems ist undefiniert. Nur das ADPU-Bit wird gelöscht, so<br />

daß das A/D-System deaktiviert bleibt.<br />

• Sämtliche EEPROM-Steuerbits, die zur Programmierung benötigt werden, sind nach einem<br />

Reset gelöscht, so daß aus dem EEPROM nur gelesen werden kann.<br />

• Der externe Interrupt bekommt die höchste Interrupt-Priorität zugewiesen, das<br />

Interrupt-Signal wird auf pegelabhängig geschaltet, so daß ein Standard-Interruptsystem mit<br />

mehreren Quellen möglich ist.<br />

Als Reset-Quelle steht beim 68HC11 nicht nur der externe Reset-Eingang zur Verfügung. Es gibt drei<br />

weitere interne Reset-Quellen: Power-On-Reset (POR), Watchdog-Timer (COP), Taktüberwachung<br />

(CMR). Jeder dieser Reset-Quellen ist ein eigener Reset-Vektor zugeordnet, der auf das zugehörige<br />

Interrupt-Programm zeigt.<br />

Der Bus<br />

• Verbindung zwischen den Komponenten (speziell: Verbindung der CPU mit dem Speicher)<br />

Adreßbusbreite beim 68HC11: 16Bit = 216 •<br />

= 65536 verschiedenen Speicherplätze mit je 8-bit<br />

Datenwort (64 KByte)<br />

• Bus im Multiplexbetrieb = Daten und Adressen über gleiche Leitungen (Kontrolle über<br />

Steuerleitungen)<br />

• Steuerleitungen geben den Bus-Zustand an (Daten/Adressen, schreiben/lesen)<br />

• Zugriff auf E/A-Ports: speicherabbgebildet<br />

Der Speicher<br />

Mikrocomputertechnik<br />

Der Speicher nimmt Instruktionen und Daten auf (wie beim klassischen von-Neuman Rechner).<br />

Speicherarten:<br />

• RAM: schreiben und lesen, sehr schnell, Speicherinhalt flüchtig (evtl. mit Batterie puffern)<br />

• ROM: nicht flüchtig, Inhalt nicht änderbar<br />

• PROM: 1x änderbar, nicht flüchtig<br />

• EPROM: löschen durch UV-Licht<br />

• EEPROM: lesen und schreiben, langsam (ms, bei RAM ns), begrenzte Lebensdauer<br />

Als Speicher hat der MC68HC811 ein ROM, ein EEPROM und ein RAM an Board. Programme<br />

können in jeden dieser Speicherbereiche geladen und in jedem Bereich ausgeführt werden. Das ROM<br />

kann allerdings nur während des Herstellungsprozesses programmiert werden, so daß diese Variante<br />

erst bei Abnahme von mehreren tausend Stück interessant wird. Ein Teil des ROM ist jedoch stets<br />

vorhanden, da es das Bootloader-Programm enthält. Bei kleinen Stückzahlen oder Einzelstücken ist<br />

das EEPROM der bevorzugte Programmspeicher. Da Programme im RAM nicht dauerhaft gespeichert<br />

werden, dient dieses zur temporären Speicherung von Rücksprungadressen im Stack-Bereich oder von<br />

Zwischenergebnissen des Programmlaufs. Die folgende Liste zeigt eine Zusammenfassung der<br />

Prozessorvarianten:<br />

Reset 88


Innerhalb der Familie gibt es nur geringe Unterschiede in Speicher (Art, Menge) und Ports (Anzahl,<br />

Art). Bei allen Varianten ist der Befehlssatz gleich gleiche (Assenbler-)Programme.<br />

Belegung des Adressraums bei verschiedenen Prozessortypen<br />

Asynchrone serielle Schnittstelle<br />

Über die asynchrone serielle Schnittstelle (SCI) wird das Programm vom PC in den Mikrocontroller<br />

geladen. Sie dient unter anderem auch dazu, beim Testen des Programms Statuswerte oder<br />

Zwischenergebnisse am Bildschirm darzustellen. Die Anschlüsse der seriellen Schnittstelle sind PD0<br />

= RxD (Dateneingang) und PD1 = TxD (Datenausgang).<br />

Timer-System<br />

Mikrocomputertechnik<br />

Das Timer-System steuert solche Funktionen, die einen Bezug zur Realzeit benötigen, also<br />

unabhängig von Befehlsausführungszeiten sein sollen. Intern werden alle Funktionen von einem<br />

konstant durchlaufenden, nicht beeinflußbaren 16-Bit-Taktzähler abgeleitet:<br />

• Der Real-Time-Interrupt (Echtzeitunterbrechung) dient dem Zweck, in genau periodischen<br />

Zeitabständen einen bestimmten Vorgang auszulösen.<br />

• Die 3 Input-Capture-Funktionen (Zeiterfassungsfunktionen) IC1 bis IC3 dienen zur<br />

Zeitmessung von Eingangssignalen an den Eingängen PA0 bis PA2.<br />

Der Speicher 89


• Mit den 4 Output-Compare-Funktionen (Zeitvergleichsfunktionen) OC1 bis OC4 können bei<br />

bestimmten Timer-Zählerständen H-Pegel bzw. L-Pegel an den Anschlüssen PA3 bis PA6<br />

ausgegeben werden.<br />

• Der COP-Watchdog-Timer sorgt dafür, daß die Programmlaufüberwachung innerhalb einer<br />

überwachungsperiode rechtzeitig zurückgesetzt wird. Im Fehlerfall wird ein Reset (Neustart)<br />

des Rechners veranlaßt.<br />

Digitale Ein- und Ausgänge<br />

Je 8 Ein- bzw. Ausgänge sind in den Ports A, B, C und E zusammengefaßt. Die meisten dieser<br />

Anschlüsse haben mehrere Funktionen, die softwaremäßig festzulegen sind. Die jeweilige<br />

Pfeilrichtung im Blockschaltbild kennzeichnet den Anschluß als Eingang oder Ausgang. Der Zugriff<br />

erfolgt wie auf den Speicher. Eigenschaften der fünf Ports:<br />

• Port A: (verbunden mit 16-bit Zähler)<br />

3 Eingänge (sichern des aktuellen Zählerstandes in ein Register durch ein Eingangssignal)<br />

4 Ausgänge (Vergleichsausgänge des Zählers: sobald der Zähler den im zugehörigen Register<br />

gespeicherten Wert erreicht hat, wird hier eine 1-Signal erzeugt)<br />

1 Ein- und Ausgang (Impulszähler)<br />

• Port B und C: Funktion hängt von der Betriebsart der Microcontrollers ab. Der 68HC11 kennt<br />

vier Betriebmodi (einstellbar an den Pins MODA, MODB):<br />

single chip<br />

Mode<br />

expanded<br />

Mode<br />

Mikrocomputertechnik<br />

normal Nur der interne Speicher ist verfügbar, Port B: digitale<br />

Ausgabeschnittstelle, Port C: digitale Eingabe- oder<br />

Ausgabe-Schnittstelle, STRB,STRA beliebig verwendbar (digitale Einbzw.<br />

Ausgänge)<br />

special special bootstrap mode:<br />

In diesem Modus lädt die Firmware über die serielle Schnittstelle (Port<br />

D) ein 255 Bytes großes Grundprogramm, welches anschliesend<br />

ausgeführt wird.<br />

normal Dieser Mode dient zum Anschließen externer Peripherie und externer<br />

Speicher. Der 68HC11 stellt sich dann wie ein normaler<br />

Mikroprozessor dar:<br />

Port B: Buserweiterung<br />

Port C: Buserweiterung<br />

STRA, STR B: Steuerleitungen<br />

special spezieller Testmodus<br />

Timer-System 90


• Port D:<br />

zwei Ein- /Ausgänge (serielle Schnittstelle)<br />

vier Ein- /Ausgänge (für synchronen Datenaustausch mit anderen 68HC11)<br />

• Port E:<br />

8-Kanal A/D-Wandler (Genauigkeit: 8-bit)<br />

Impulszähler<br />

Der Impulszähler dient je nach Software-Vorgabe zur Zählung von Pulsen oder zur Bestimmung einer<br />

Pulsdauer, wobei er im letzteren Fall auf das Timer-System zugreift.<br />

Analog-Digital-Wandler<br />

Mikrocomputertechnik<br />

Die 8 Anschlüsse des Ports E können je nach Bedarf im Multiplexbetrieb auf einen<br />

Analog-Digital-Wandler geschaltet werden. Der Wandler arbeitet mit einer Auflösung von 8 Bit und<br />

beinhaltet eine Sample-and-Hold-Funktion, so daß auch zeitveränderliche Signale amplitudengetreu<br />

verarbeitet werden.<br />

Synchrone serielle Peripherieschnittstelle<br />

Die synchrone serielle Peripherieschnittstelle (SPI) dient zum Datenaustausch mit einem anderen<br />

Mikrocontroller oder speziell dafür entwickelten Peripheriebausteinen, die an PD2 bis PD5<br />

angeschlossen werden.<br />

Digitale Ein- und Ausgänge 91


Vereinfachtes Blockschaltbild des 68HC11<br />

Mikrocomputertechnik<br />

4.2 Typische Anwendungsschaltung<br />

Wie aus dem Stromlaufplan ersichtlich ist, besteht die gesamte Schaltung des Mikrocontrollers nur aus<br />

drei integrierten Bausteinen. Den Mittelpunkt bildet der Mikrocontroller 68HC811 (IC1). Sämtliche<br />

Anschlüsse sind durch Widerstandsnetzwerke abgeschlossen. Der Takterzeugung dient ein<br />

8-MHz-Quarz (Q1), der mit Hilfe der beiden Keramikkondensatoren C3, C4 und dem<br />

Parallelwiderstand R1 auf der Grundwelle schwingt. Für das Laden der Programme und für den<br />

Kontakt mit der Außenwelt wurde ein serieller Pegelwandler vom Typ MAX 232 verwendet. Seine<br />

externe Beschaltung beschränkt sich auf vier Tantalkondensatoren (C6 bis C9) für die internen<br />

Spannungswandler (+12V/-12V). Mit dem Schalter SW1 kann der Mikrocontroller in den Bootmodus<br />

geschaltet werden. Nur in dieser Betriebsart ist es möglich, Programme zu laden und abzuspeichern.<br />

Der Taster TA1 löst einen Reset aus und versetzt die gesamte Schaltung in einen definierten<br />

Anfangszustand.<br />

Die Spannungsversorgung erfolgt durch IC3, einen Festspannungsregler vom Typ 7805. Die von<br />

einem externen Steckernetzteil zugeführte Gleichspannung von etwa 9 V wird hier auf eine konstante<br />

Versorgungsspannung von 5 V geregelt.<br />

Synchrone serielle Peripherieschnittstelle 92


Mikrocomputertechnik<br />

Achtung: Diese Schaltung ist nicht mit der Schaltung des im Praktikum verwendeten "Zwerg 11"<br />

identisch.<br />

Stückliste für das Mikrocontroller-Board<br />

Bezeichnung Bauteil Wert<br />

IC1 Mikrocontroller MC 68HC811 E2 FN<br />

IC2 IC MAX 232<br />

IC3 Regler-IC 7805<br />

Q1 Quarz 8 MHz<br />

RN1 - RN5 Widerstandsnetzwerk 8 x 10 KOhm<br />

R1 Widerstand 10 MOhm<br />

R2 Widerstand 1 KOhm<br />

R3, R4 Widerstand 10 KOhm<br />

R5 Widerstand 4,7 KOhm<br />

C1, C12 Kondensator 100 nF keramik<br />

4.2 Typische Anwendungsschaltung 93


C3, C4 Kondensator 22 pF keramik<br />

C2, C5 Tantalelko 1 Mikrofarad / 35 V<br />

C6, C7, C8, C9 Tantalelko 10 Mikrofarad / 16 V<br />

C10 Elko 100 Mikrofarad / 16 V<br />

C11 Elko 100 Mikrofarad / 16 V<br />

ST1 - ST5 Steckerleiste 2 x 8-polig<br />

Bu1 - Bu5 Buchsenleiste 8-polig<br />

Fassung für IC1 IC-Fassung PLCC 52<br />

Fassung für IC2 IC-Fassung 16-polig<br />

13 Stück Lötstifte 1 mm<br />

4.3 Praktikumssystem PS11 mit M68HC11A0<br />

Blockschaltung<br />

(CONFIG = $0C)<br />

Mikrocomputertechnik<br />

Praktikumsrechner mit Experimetierboard<br />

Stückliste für das Mikrocontroller-Board 94


Der ZWERG11plus<br />

Mikrocomputertechnik<br />

Unter den ganz kleinen Karten ist der ZWERG11A von<br />

Elektronikladen Detmold ein ganz Großer. Mittlerweile<br />

vieltausendfach im Einsatz gab es aber immer wieder<br />

Applikationen, die das Speicherangebot des ZWERG11A<br />

überforderten.<br />

So wurde als Ergänzung zum "kleinen ZWERG" ein "großer ZWERG" geschaffen: der<br />

ZWERG11plus. Die Schwierigkeit, auf einer Platinenfläche von nur 51mm x 54mm einen "großen"<br />

Rechner zu entwerfen, läßt sich sicherlich nachvollziehen. Die Lösung für dieses Problem hieß:<br />

6-Lagen-Multilayer, mehr SMT-Bauteile und doppelseitige Bestückung.<br />

Zum ZWERG11plus gibt es ein Entwicklungspaket. Es besteht aus folgenden Komponenten:<br />

• ZWERG11plus Controllermodul<br />

• Benutzerhandbuch mit Diskette<br />

• RS232 Interface-Modul (IF-Modul)<br />

• Flachbandkabel für IF-Modul und Sub-D9 Anschlußkabel für PC/AT<br />

• Terminalprogramm zur Kommunikation zwischen PC und ZWERG11plus<br />

• Programmier- und Download-Utilities<br />

• Cross-<strong>Assembler</strong> AS11 und Hilfsprogramme<br />

Zur Softwareentwicklung für den ZWERG11plus können Sie, neben dem <strong>Assembler</strong> im<br />

Entwicklungspaket, die Integrierte Entwicklungsumgebung IDE11 einsetzen.<br />

Als C-Compiler stehen Produkte von Imagecraft (ICC11) und Cosmic zur Verfügung. Außerdem<br />

kann man das MOPS-Betriebssystem (<strong>Assembler</strong>/Basic/Pascal) mit dem ZWERG11plus verwenden.<br />

Praktikumsrechner mit Experimetierboard 95


Technische Daten:<br />

Mikrocomputertechnik<br />

• MC68HC11A1 8Bit Mikrocontroller Motorola<br />

• Versorgungsspannung 5V, Stromaufnahme typ. 20-30mA<br />

• Reset-Controller<br />

• 32KByte RAM<br />

• 32KByte EEPROM<br />

• Uhrenbaustein RTC4553 mit Batterie (Option)<br />

• Anschluß für serielle Interfacemodule (IF-Module)<br />

• SPI: Interface für ser. Peripherie Bausteine (parallel I/O, AD/DA-Wandler usw.)<br />

• Timersystem 16 Bit mit 5x Output-Compare, 3x Input-Capture<br />

• 8 Bit AD-Wandler mit 8 Kanälen<br />

• Port Replacement Unit (PRU) MC68HC24<br />

• bis zu 40 digitale Ein-/Ausgänge (abzgl. genutzter Sonderfkt.)<br />

• Steckverbinder für alphanumerische oder grafische LCDs<br />

• steckerkompatibel zu ZWERG11A<br />

Anschluß des "Zwerg 11" an den PC<br />

Belegung des Schnittstellenkabels und des Experimentierboards<br />

Der ZWERG11plus 96


Bootloader Firmware for MC68HC11A8 (essentials)<br />

pddr equ $08<br />

baud equ $2B<br />

sccr2 equ $2D<br />

scsr equ $2E<br />

scdr equ $2F<br />

*<br />

Mikrocomputertechnik<br />

Belegung des Schnittstellenkabels und des Experimentierboards 97


org $BF40<br />

*<br />

main ldx #$1000 init x for indexed access to hardware<br />

ldaa #$A2<br />

staa baud,x restart timer , set baudrate to 7812 Bd<br />

ldaa #$0C<br />

staa sccr2,x enable receiver and transmitter<br />

bset sccr2,x $01 send break to signal start of download to master<br />

wait brset pddr,x $01 wait wait for startbit from master<br />

bclr sccr2,x $01 clear break<br />

char brclr scsr,x $20 char wait for first character from master (RDRF)<br />

ldaa scdr,x read character<br />

bne goon<br />

jmp $B600 start program in internal EEPROM<br />

goon cmpa #$55 test mode ?<br />

beq strt yes, skip download<br />

cmpa #$FF baud rate ok ?<br />

beq bdok yes, goon<br />

bset baud,x $33 change to 1200 Bd<br />

bdok ldy #$000 init pointer<br />

loop brclr scsr,x $20 loop wait for RDRF<br />

ldaa scdr,x get character<br />

staa 0,y store character to RAM<br />

staa scdr,x echo character to master<br />

iny adjust pointer<br />

cpy #$0000 end of area ?<br />

bne loop no, next character<br />

*<br />

strt jmp $0000 start downloaded userprogram<br />

*<br />

org $BFFE<br />

dc.w main start main on RESET (MODA = MODB = 0)<br />

*<br />

end<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Bootloader Firmware for MC68HC11A8 (essentials) 98


5. Peripherie des Systems M68HC11<br />

5.1 Peripherie-Register<br />

Standardlage (default): $1000 - $103F, Verschiebung an jede 4KByte-Grenze möglich<br />

(INIT-Register)<br />

Adresse Register Funktion Adresse Register Funktion<br />

$1000 PORTA port A data $1020 TCTL1<br />

$1001 spare $1021 TCTL2<br />

$1002 PIOC parallel I/O control $1022 TMSK1<br />

$1003 PORTC port C data $1023 TFLG1<br />

$1004 PORTB port B data $1024 TMSK2 timer mask 2<br />

$1005 PORTCL port C latch $1025 TFLG2 timer flag 2<br />

$1006 spare $1026 PACTL pulse accu control<br />

$1007 DDRC port C direction $1027 PACNT pulse accu count<br />

$1008 PORTD port D data $1028 SPCR SPI control<br />

$1009 DDRD port D direction $1029 SPSR SPI status<br />

$100A PORTE port E data $102A spare<br />

$100B CFORC $102B BAUD SCI baud rate<br />

$100C OC1M $102C SCCR1 SCI control 1<br />

$100D OC1D $102D SCCR2 SCI control 2<br />

$100E TCNT timer count high $102E SCSR SCI status<br />

$100F timer count low $102F SCDR SCI data<br />

$1010 TIC1H $1030 ADCTL A/D control<br />

$1011 TIC1L $1031 spare<br />

$1012 TIC2H $1032 spare<br />

$1013 TIC2L $1033 spare<br />

$1014 TIC3H $1034 spare<br />

$1015 TIC3L $1035 spare<br />

$1016 TOC1H $1036 spare<br />

$1017 TOC1L $1037 spare<br />

$1018 TOC2H $1038 spare<br />

$1019 TOC2L $1039 OPTION<br />

$101A TOC3H $103A spare<br />

$101B TOC3L $103B PPROG<br />

$101C TOC4H $103C HPRIO<br />

$101D TOC4L $103D INIT<br />

$101E TOC5H $103E TEST1<br />

5. Peripherie des Systems M68HC11 99


$101F TOC5L $103F CONFIG<br />

Im Rahmen dieser Vorlesung wird nur ein ausgewählter Teil dieser Register und ihrer Funktionen<br />

besprochen. Im folgenden werden einzelne Ports und die zugehörigen Register zur Sprache kommen.<br />

5.2 Parallele Schnittstellen<br />

Beim Informationsaustausch des Controllers mit der "Außenwelt" müssen spezielle Eigenschaften der<br />

Peripheriegeräte berücksichtigt werden. Insbesondere sind die Peripherieeinheiten gegenüber der<br />

Prozessorgeschwindigkeit recht langsam Die Schnittstellen müssen die ein- oder ausgehenden<br />

Daten zwischenspeichern. Zum anderen laufen CPU und Peripherie oft zeitlich asynchron. Eine<br />

weitere Aufgabe von Schnittstellen ist auch die Parallel-seriell-Wandlung (siehe Abschnitt 5.3).<br />

Allgemein gilt für alle Schnittstellen:<br />

• der Datenverkehr zwischen CPU und Schnittstelle läuft meist programmgesteuert (per Polling<br />

oder per Interrupt)<br />

• die "Datenbreite" ist durch den internen Datenbus vorgegeben (8 Bit)<br />

• die Eigenschaften der Schnittstellen lassen sich per Programm einstellen Schnittstelle<br />

programmierbar Initialisierung notwendig<br />

• jeder Schnittstelle sind einige der oben aufgeführten Register zugeordnet. Dabei handelt es<br />

sich um<br />

♦ Register zur Einstellung der Eigenschaften<br />

♦ Register zur Ein- und Ausgabe<br />

Der 68HC11 besitzt fünf parallele Schnittstellen, die Ports A bis E, welche mit unterschiedlichen<br />

Hardware-Eigenschaften ausgestattet sind. Im "expanded Mode" stehen die Ports B und C nicht zur<br />

Verfügung, weil sie für Adreß- und Datenleitungen verwendet werden. Durch einen<br />

Port-Expander-Baustein lassen sie sich aber wieder ergänzen.<br />

Eine kurze Übersicht der Ports:<br />

Mikrocomputertechnik<br />

• Port A: besitzt drei Eingänge vier Ausgänge und eine bidirektionale Leitung. Zusätzlich<br />

verarbeitet er die Signale des Timer-Systems und des Pulse-Akkumulators.<br />

Die Ports B und C werden zusammen mit den Handshakeleitungen STRA und STRB als Einheit<br />

betrachtet.<br />

• Port B: besitzt acht Ausgangsleitungen. Lesen auf Port B liefert die letzten<br />

hineingeschriebenen Daten.<br />

• Port C: hat acht bidirektionale Leitungen. Über ein Datenrichtungsregister kann für jede<br />

Leitung festgelegt werden, ob sie Eingang oder Ausgang sein soll. Ein zusätzliches Latch<br />

speichert den Eingangszustand von Port C bei jeder aktiven Signalflanke auf dem Anschluß<br />

STRA.<br />

• Port D: besitzt sechs bidirektionale Leitungen, die wie bei Port C per Datenrichtungsregister<br />

eingestellt werden können. Die Bits 0 und 1 von Port D werden auch von der seriellen<br />

Schnittstelle verwendet.<br />

• Port E: besitzt acht Eingangsleitungen, die alternativ als analoge Eingänge des<br />

A/D-Wandler-Systems verwendet werden. Beim DIL-Ghäuse stehen sogar nur vier Leitungen<br />

zur Verfügung.<br />

Den fünf Ports sind insgesamt 16 Register zugeordnet (Einstellung und E/A). Die jeweiligen Register<br />

werden bei der Besprechung der einzelnen Ports behandelt.<br />

5.1 Peripherie-Register 100


Port A<br />

Mikrocomputertechnik<br />

Ein- und Ausgabeport mit fester und für ein Bit variabler Datenrichtung.<br />

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:<br />

• Steuerbit PEAN = 0: "normale" parallele E/A (Betriebsart 1).<br />

• Steuerbit PEAN = 1: Impuls-Akkumulator (Betriebsart 2). Hier lassen sich entweder Impulse<br />

zählen (PMOD = 0) oder Impulsdauern messen (PMOD = 1).<br />

PAIF set by active edge on PAI, reset by writing a corresponding one to TFLG2<br />

PAOVF set by roll over of PACNT, reset by writing a corresponding one to TFLG2<br />

PAII set and reset by software, generate interrupt, if PAIF is set<br />

PAOVI set and reset by software, generate interrupt, if PAOVF is set<br />

Beim Event Counting Mode (PAMOD=0) werden am PAI Eingang (=PA7) eintreffende Impulse im<br />

pulse accu gezählt.<br />

Beim Gated Time Mode (PAMOD=1) wird die Zeit "gemessen", wie lange der PAI-Eingang im<br />

aktiven Zustand ist. Die Messdauer ergibt sich aus der Anzahl der gezählten Impulse, die aus dem<br />

Port A 101


durch 64 geteilten Systemtakt abgeleitet sind, d.h. die zeitliche Auflösung beträgt 32 ms.<br />

Der Port A bietet mit seinem Pin PAI (= PA7) außerdem die Möglichkeit, Programmunterbrechungen<br />

(Interrupts) auszulösen.<br />

Port B und STRB<br />

Ausgabeport mit fester Datenrichtung<br />

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:<br />

• Steuerbit HNDS = 0: "normale" parallele Ausgabe<br />

• Steuerbit HNDS = 1: full handshake mode<br />

Wird im Rahmen dieser Vorlesung nicht besprochen!<br />

Die Programmierung von Port B ist denkbar einfach. Jedes Schreiben auf die Adresse $2004 hat die<br />

Ausgabe des entsprechenden Bitmusters auf den Leitungen von Port B zur Folge.<br />

Port C und STRA<br />

Mikrocomputertechnik<br />

Ein/Ausgabeport mit bitweise wählbarer Datenrichtung. Das Datenrichtungs-"Register" DDRC<br />

(Adresse $1007) legt fest, ob die Bits von Port C Eingangs- oder Ausgangsbits sind (0 = Eingang, 1 =<br />

Ausgang). Daher ist eine Initia-lisierung des Ports durch belegen von DDRC notwendig. Die folgende<br />

Abbildung zeigt das Impulsdiagramm einer typischen Anwendung des STRA-Signals. In der<br />

Abbildung sind auch die Bedingungen beschrieben, die für die einzelnen Steuer- und Statusbits in<br />

PIOC gelten.<br />

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:<br />

• Steuerbit HNDS = 0: "normale" parallele Ein- oder Ausgabe<br />

Port B und STRB 102


• Steuerbit HNDS = 1: full handshake mode<br />

Wird im Rahmen dieser Vorlesung nicht besprochen!<br />

Die Leitung STRA wird über die Bits STAI und EGA in PIOC gesteuert. STAI gibt den Interrupt für<br />

die Leitung STRA frei (wird weiter unten behandelt). EGA legt fest, ob STRA auf eine steigende oder<br />

fallende Flanke reagiert. Wird beispielsweise eine Taste an STRA angeschlossen, wird durch deren<br />

Betätigung das Bit STAF in PIOC gesetzt und falls STAI = 1 ist, ein Interrupt ausgelöst. Das Bit<br />

STAF wird durch das Lesen der Adressen PIOC und PORTCL (in dieser Reihenfolge) zurückgesetzt.<br />

Impulsdiagramm einer typischen Anwendung des STRA-Signals<br />

Port D<br />

Mikrocomputertechnik<br />

Ein/Ausgabeport mit bitweise wählbarer Datenrichtung.<br />

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:<br />

• Steuerbits SPE = RE = TE = 0: "normale" parallele Ein- oder Ausgabe<br />

Port C und STRA 103


Port E<br />

• 2. Betriebsart: SPI = serial peripheral interface (synchronous) wenn SPE=1 ist oder SCI =<br />

serial communications interface (asynchronous) wenn RE=1 und/oder TE=1 sind.<br />

Wird unter 5.3 besprochen.<br />

Eingabeport mit fester Datenrichtung<br />

Der Port kann auf zwei verschiedene Betriebsarten gesetzt werden:<br />

• "normale" parallele Eingabe, kein Schreiben ins ADCTL-Register<br />

• A/D-Wandlung, Schreiben ins ADCTL-Register - siehe später.<br />

Programmbeispiele<br />

Beispiel 1<br />

Lesen 4 Bit linksbündig von Port C<br />

Ausgeben 4 Bit rechtsbündig auf Port C<br />

Ausgeben 4 Bit rechtsbündig auf Port B mit STRB (high pulse)<br />

Vereinbarungen:<br />

pcdr equ $1003<br />

pcdd equ $1007<br />

pbdr equ $1004<br />

pioc equ $1002<br />

Initialisierung<br />

init ldaa #$0F<br />

Mikrocomputertechnik<br />

Port D 104


Datenverkehr<br />

staa pcdd pc(3:0) = output<br />

ldaa #$01<br />

staa pioc STRB high active<br />

rts<br />

main ldaa pcdr<br />

lsra<br />

lsra<br />

lsra<br />

lsra<br />

staa pcdr<br />

staa pbdr<br />

bra main<br />

Beispiel 2<br />

Warten auf steigende Flanke am Eingang STRA<br />

Vereinbarungen:<br />

pioc equ $1002<br />

pcdl equ $1005<br />

Initialisierung<br />

init ldaa #$02<br />

staa pioc STRA rising edge expected<br />

rts<br />

Daten-Abfrage<br />

.<br />

.<br />

. Alternative<br />

wait ldaa pioc<br />

anda #$02 bita #$02<br />

beq wait beq wait<br />

ldaa pcdl clear STAF-flag<br />

.<br />

.<br />

.<br />

Beispiel 3<br />

Realisieren eines 8-Bit-Zählers auf Port B<br />

(Port B ist zwar ein reiner Ausgabeport, aber mit dem Befehl "inc pcdr" wird Port B erst gelesen und<br />

somit der vorherige Ausgabewert geliefert, dann der Wert erhöht und zurückgeschrieben).<br />

Vereinbarungen:<br />

pbdr equ $1004<br />

Programm:<br />

Mikrocomputertechnik<br />

init clr pbdr Port B = 0<br />

main inc pbdr Increment Port B<br />

ldx #$4000 Warteschleife<br />

delay dex X = X - 1<br />

bne delay solange X > 0 durchlaufe Schleife<br />

Programmbeispiele 105


Beispiel 4<br />

Vereinbarungen:<br />

bra main<br />

portc equ $1003<br />

pcdd equ $1007<br />

Programm:<br />

init ldaa #%11111111<br />

staa pcdd Port C auf Ausgabe setzen (0=in, 1=out)<br />

clra<br />

staa portc Port C = 0<br />

main inca<br />

staa portc hochzählen<br />

ldx #$4000 Warteschleife<br />

delay dex<br />

bne delay<br />

bra main<br />

Beispiel 5<br />

Lichtmuster ausgeben auf LEDs, die an Port C angeschlossen sind.<br />

Vereinbarungen:<br />

portc equ $1003<br />

pcdd equ $1007<br />

Programm:<br />

init ldaa #$FF<br />

staa pcdd Port C auf Ausgabe setzen (0=in, 1=out)<br />

top ldx #TABLE X verweist nun auf die Daten in TABLE<br />

loop ldaa 0,X Tabellenelement lesen<br />

beq top ist das Element 0 --> Tabellenende<br />

* wieder zum Tabellenanfang<br />

staa portc Tabellenelement ausgeben<br />

bsr delay Warteschleife aufrufen<br />

inx naechstes Tabellenelement<br />

bra loop usw.<br />

*<br />

delay ldx #$4000 Warteschleife, diesmal als Unterprogramm<br />

dela1 dex<br />

bne dela1<br />

rts<br />

*<br />

TABLE dc.b $01, $02, $04, $08, $10, $20, $40, $80<br />

dc.b $40, $20, $10, $08, $04, $02, $00<br />

Beispiel 6<br />

Lesen Port E, ausgeben auf Port B<br />

Vereinbarungen:<br />

pbdr equ $1004<br />

pedr equ $100A<br />

Mikrocomputertechnik<br />

Programmbeispiele 106


Programm:<br />

main ldaa pedr<br />

staa pbdr<br />

bra main<br />

5.3 Serielle Schnittstellen<br />

Die SCI-Schnittstelle (serial communication interface asynchronous) ist ein Port mit langsamer,<br />

asynchroner serieller Datenübertragung (bis etwa 100 kbit/s). Mit einem Pegelwandler kann sie als<br />

RS232-Schnittstelle verwendet werden. Sie entspricht in ihrer Funktion der seriellen Schnittstelle des<br />

PC.<br />

Die SPI-Schnittstelle ist eine synchrone serielle Peripherieschnittstelle (serial peripheral interface). Sie<br />

dient zum Datenaustausch mit einem anderen Mikrocontroller oder mit Peripheriebausteinen.<br />

Beide Schnittstellen verwenden einige Pins von Port D, die dann nicht mehr als Parallelport-Pins zur<br />

Verfügung stehen. Für eine allgemeine Einführung in die <strong>Assembler</strong>programmierung ist es nicht<br />

notwendig, alle Schnittstellen des 68HC11 zu besprechen. Daher wird nur die asynchrone serielle<br />

SCI-Schnittstelle behandelt.<br />

SCI (serial communication interface asynchronous)<br />

Port mit langsamer, asynchroner serieller Datenübertragung (bis etwa 100 kHz)<br />

Um die Schnittstelle mit der Außenwelt zu verbinden, werden die beiden niederwertigen Bits des<br />

Ports D verwendet. Für die Freigabe der Signale nach außen müssen im Register SCCR2 die Bits RE<br />

(Empfang) und TE (Senden) auf 1 gesetzt werden.<br />

Puffer und Statusbits<br />

Statusbits:<br />

Mikrocomputertechnik<br />

5.3 Serielle Schnittstellen 107


• RDRF (receive data register full): Wird gesetzt, wenn ein Zeichen vom<br />

Empfangsschieberegister ins Register SCDR übertragen wird. Wird zurückgesetzt durch<br />

Lesen von SCSR und danach Lesen von SCDR.<br />

• TDRE (transmit data register empty): Wird gesetzt, wenn ein Zeichen vom Register SCDR ins<br />

Sendeschieberegister übertragen wird. Wird zurückgesetzt durch Lesen von SCSR und danach<br />

Schreiben von SCDR.<br />

• TC (transmission complete): Wird gesetzt, wenn ein Zeichen komplett aus dem<br />

Sendeschieberegister herausgeschoben wurde. Wird zurückgesetzt durch Lesen von SCSR<br />

und danach Schreiben von SCDR.<br />

Empfangs-Funktion:<br />

Die Steuerungslogik erkennt ein seriell ankommendes Zeichen und schiebt es im eingestellten Takt ins<br />

Empfangs-Schieberegister (Receive Data Register, RDR). Sobald das Zeichen vollständig im<br />

Schieberegister steht, wird es parallel ins Empfangsregister kopiert; gleichzeitig wird im Statusregister<br />

(SCSR) das Bit 5 (Receive Data Register Full, RDRF) auf 1 gesetzt. Falls im Steuerregister (SCCR2)<br />

der Empfangsinterrupt zugelassen wurde (Receive Interrupt Enable, RIE), wird auch noch ein<br />

SCI-Interrupt erzeugt.<br />

Das sofortige Kopieren eines Zeichens vom Schieberegister ins Empfangsregister (SCDR) ist<br />

notwendig, damit ein eventuell unmittelbar nachfolgendes serielles Zeichen nicht das vorherige<br />

überschreibt. Allerdings muß das Empfangsregister bis spätestens unmittelbar vor dem nächsten<br />

Kopieren vom Prozessor gelesen werden, denn sonst geht dieses Zeichen durch Überschreiben<br />

verloren. Die Steuerung erkennt ein solches Überschreiben und setzt dann das Bit 3 im Statusregister<br />

(SCSR): Overrun Error (OR). Der Zeitabstand, in dem Zeichen eintreffen können, hängt von der<br />

Baudrate ab, z. B. beträgt der Zeichenabstand bei 9600 Baud ca. 1 ms.<br />

Sende-Funktion:<br />

Wird ein Zeichen ins Senderegister geschrieben, so prüft die Steuerlogik, ob das<br />

Sende-Schieberegister frei ist, um es dann dorthin zu kopieren und den Schiebevorgang zu starten.<br />

Damit ist das Senderegister wieder frei und es kann erneut per Store-Befehl beschrieben werden<br />

(nächstes Zeichen). Die Tatsache, daß dieses Schreiben erlaubt ist, signalisiert das Bit 8 (Transmit<br />

Data Register Empty, TDRE) des Statusregisters (SCSR) mit einer 1. Auch hier kann ein<br />

SCI-Interrupt ausgelöst werden, wenn im Steuerregister der Sende-Interrupt per TIE-Bit = 1 (Transmit<br />

Interrupt Enable) freigegeben ist. In manchen Fällen kann auch noch das tatsächliche Ende des<br />

Schiebevorgängs von Interesse sein (Transmission complete). Für diesen Zweck gibt es auch noch die<br />

Möglichkeit, diese Tatsache sowohl am entsprechenden Statusbit (TC) zu erkennen bzw. durch einen<br />

Interrupt melden zu lassen.<br />

Serielles Rahmenformat:<br />

Idle: Im Ruhezustand ist die Leitung auf auf 1-Pegel.<br />

Beim Datenformat von 9 Bit (M = 1) ist das neunte Bit im Register SCCR1 zu finden. Beim Wert M<br />

= 0 werden 8 Bit empfangen/gesendet (Normalfall).<br />

Setzen der Datenrate<br />

Mikrocomputertechnik<br />

Die Erzeugung der Datenrate erfolgt mehrstufig und ist daher etwas komplex. Es spielen dabei vier<br />

Teiler für die Taktfrequenz (in der Regel 8 MHz) zusammen (Register BAUD):<br />

SCI (serial communication interface asynchronous) 108


Der Takt gelangt erst in einen Prescaler mit vier möglichen Divisionsfaktoren (1, 3, 4, 13), dessen<br />

Output dann nochmals durch acht Divisoren geteilt werden kann. Bei einer Taktrate von 8 MHz lassen<br />

sich folgende Raten wählen (Einstellungen für das Praktikumssystem farbig hinterlegt):<br />

Neben den beiden schon erwähnten Bits TE und RE sind im Register SCCR2 die Steuerbits für die<br />

Interruptfreigabe enthalten.<br />

interrupt masks (set and reset by software)<br />

Mikrocomputertechnik<br />

• RIE receive interrupt enable, generate IRQ, if RDRF is set<br />

• TIE transmit interrupt enable, generate IRQ, if TDRE is set<br />

• TCIE tx complete interrupt enable, generate IRQ, if TC is set<br />

• ILIE idle-line interrupt enable, generate IRQ, if IDLE is set<br />

Das SCI-Statusregister SCSR liefert Informationen über den Ablauf der Kommunikation. Die<br />

Fehlerflags werden zurückgesetzt durch das Lesen von SCSR und SCDR.<br />

SCI (serial communication interface asynchronous) 109


error flags (set by hardware, reset by reading SCSR and SCDR)<br />

• OR overrun error char received and previously received char not yet read<br />

• NF noise flag data recovery logic detected noise during reception<br />

• FE framing error no logic high, when stop bit is expected<br />

SPI (serial peripherial interface synchronous)<br />

Port mit schneller, synchroner serieller Datenübertragung (bis etwa 2 MHz).<br />

Wird im Rahmen dieser Vorlesung nicht besprochen.<br />

Programmbeispiele<br />

Beispiel 1:<br />

Serielles Senden und Empfangen von Zeichen mit 9600 Bd<br />

Vereinbarungen:<br />

scdr equ $102F<br />

scsr equ $102E<br />

baud equ $102B<br />

sccr1 equ $102C<br />

sccr2 equ $102D<br />

Einstellungen:<br />

init ldaa #$30<br />

staa baud baudrate = 9600 bit/s<br />

ldaa #0<br />

staa sccr1<br />

ldaa #$0C<br />

staa sccr2 enable transmit & receive<br />

rts<br />

Datenverkehr:<br />

* Zeichen in Speichezelle "char" ausgeben<br />

chou ldaa char<br />

ldab scsr Sendereg. leer?<br />

andb #$80<br />

beq chou<br />

staa scdr transmit<br />

rts<br />

Mikrocomputertechnik<br />

* Zeichen nach Speicherzelle "char" einlesen<br />

chin ldab scsr Empfangsreg. leer?<br />

andb #$20<br />

SPI (serial peripherial interface synchronous) 110


Sendeschleife:<br />

beq chin<br />

ldaa scdr receive<br />

staa char<br />

rts<br />

main bsr init<br />

loop bsr chin "Schreibmaschine"<br />

bsr chout<br />

bra loop<br />

Beispiel 2:<br />

Serielles Senden von Zeichenketten mit 9600 Bd<br />

Vereinbarungen:<br />

scdr equ $102F<br />

scsr equ $102E<br />

baud equ $102B<br />

sccr1 equ $102C<br />

sccr2 equ $102D<br />

Einstellungen:<br />

init ldaa #$30<br />

staa baud baudrate = 9600 bit/s<br />

ldaa #0<br />

staa sccr1<br />

ldaa #$0C<br />

staa sccr2 enable transmit & receive<br />

rts<br />

Zeichen in Akku A ausgeben:<br />

chou ldab scsr Sendereg. leer?<br />

bpl chou<br />

staa scdr transmit<br />

rts<br />

Zeichenkette senden: Die Adresse der Zeichenkette wird in X übergeben, Ende der Zeichenkette wird<br />

durch ETX markiert definiert durch: ETX EQU 3.<br />

saus ldaa 0,x Zeichen holen<br />

cmpa #ETX ETX (3) ?<br />

beq saus_e dann fertig<br />

inx X inkrementieren<br />

bsr chou Zeichen senden<br />

bra saus und nächstes Zeichen<br />

saus_e rts<br />

Sendeschleife:<br />

Mikrocomputertechnik<br />

main bsr init<br />

loop ldx #TEXT<br />

bsr saus<br />

bra loop<br />

*<br />

TEXT dc.b 'Hello World' Meldungstext<br />

dc.b $0D,$0A,ETX Zeilenvorschub, ETX<br />

Programmbeispiele 111


Beispiel 3:<br />

Serielles Senden und Empfangen von Zeichenketten mit 9600 Bd<br />

Vereinbarungen: - siehe oben -<br />

Einstellungen: - siehe oben -<br />

Zeichen in Akku A ausgeben: - siehe oben -<br />

Zeichenkette senden: - siehe oben -<br />

Zeichen nach Akku A einlesen<br />

chin ldab scsr Empfangsreg. leer?<br />

andb #$20<br />

beq chin<br />

ldaa scdr receive<br />

rts<br />

Zeichenkette einlesen: Die Adresse eines Eingabepuffers wird in X übergeben. Das Eingabeende wird<br />

durch die Taste Carriage-Return (CR, $0D) signalisiert.<br />

sein bsr chin Zeichen einlesen<br />

cmpa #$0D Carriage Return?<br />

beq sein_e ja, Ende<br />

staa 0,x Zeichen im Puffer speichern<br />

inx X inkrementieren<br />

bra sein und nächstes<br />

sein_e ldaa #ETX ETX anhängen (CR wird nicht mit gesp.)<br />

staa 0,x<br />

rts<br />

Sendeschleife:<br />

main bsr init<br />

loop ldx #PUF<br />

bsr sein<br />

ldx #PUF<br />

bsr saus<br />

bra loop<br />

Irgendwo im Programm wird ein Puffer definiert, z. B.:<br />

org data<br />

PUF ds.b 80 80 Bytes Puffer reservieren<br />

Anmerkung: "sein" überprüft nicht, ob der maximale Pufferbereich überschritten wird und so<br />

eventuell andere Variablen überschrieben werden. Versuchen Sie, eine Begrenzung der Eingabe auf z.<br />

B. 80 Zeichen zu programmieren.<br />

Beispiel 4: Kommandoauswertung. Es wird ein Befehlsbuchstabe von der seriellen Schnittstelle<br />

eingelesen und verarbeitet. Es sind die Buchstaben 'a', 'b' und 'c' erlaubt - bei anderen Eingaben erfolgt<br />

eine Fehlermeldung. Als Pseudo-Aktion dient das Unterprogramm "doit", es gibt lediglich den<br />

eingegebenen Buchstaben als Grossbuchstaben aus.<br />

prog equ $8000<br />

data equ $2000<br />

stack equ $7FFF<br />

Mikrocomputertechnik<br />

Programmbeispiele 112


scdr equ $102f<br />

scsr equ $102e<br />

sccr1 equ $102c<br />

sccr2 equ $102d<br />

baud equ $102b<br />

reset equ $fffe<br />

cr equ 13<br />

lf equ 10<br />

org data<br />

buf ds.b 100 ; Eingabepuffer<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack ; Stackpinter setzen<br />

bsr sini ; Schnittstelle init.<br />

loop ldx #hello ; Prompt ausgeben<br />

bsr saus<br />

bsr chin ; Taste einlesen<br />

cmpa #'a' ; ist es 'a'?<br />

bne next1 ; nein, weiter<br />

bsr doit ; Dummy-Aktion<br />

bra loop ; und weiter<br />

next1 cmpa #'b' ; ist es 'b'?<br />

bne next2 ; wie oben<br />

bsr doit<br />

bra loop<br />

next2 cmpa #'c' ; ist es 'c'?<br />

bne next3 ; wie oben<br />

bsr doit<br />

bra loop<br />

next3 ldx #oops ; keine erlaubte Taste<br />

bsr saus ; Fehlermeldung ausgeben<br />

bra loop<br />

doit ; Dummy-Aktion<br />

psha ; Akku A retten<br />

ldx #k1 ; Text ausgeben<br />

bsr saus<br />

pula ; Akku wieder holen (eingeg. Zeichen)<br />

suba #$20 ; in Grossbuchstaben umwandeln<br />

bsr chou ; und ausgeben<br />

bsr crlf ; neue Zeile<br />

rts<br />

crlf ldaa #cr ; Carriage Return, Line Feed ausgeben<br />

bsr chou<br />

ldaa #lf<br />

bsr chou<br />

rts<br />

saus ldaa 0,x ; Stingausgabe, siehe oben<br />

beq sfin<br />

bsr chou<br />

inx<br />

bra saus<br />

sfin rts<br />

sini clr sccr1 ; Schnittstelle initialisieren, siehe oben<br />

ldaa #$0C<br />

staa sccr2<br />

ldaa #$30<br />

staa baud<br />

rts<br />

Programmbeispiele 113


chou ldab scsr ; Zeichen ausgeben, siehe oben<br />

bpl chou<br />

staa scdr<br />

rts<br />

chin ldab scsr ; Zeichen einlesen, siehe oben<br />

andb #$20<br />

beq chin<br />

ldaa scdr<br />

rts<br />

; Zeichenkettenkonstante<br />

hello dc.b 'Cmd: ' ; Kommandoprompt<br />

dc.b 0<br />

oops dc.b 'Oops!' ; Fehlermeldung<br />

dc.b cr,lf,0<br />

k1 dc.b 'Eingabe war ' ; fuer Dummy-Aktion<br />

dc.b 0<br />

5.4 Zähler<br />

org reset ; Reset-Vektor<br />

fdb main<br />

end<br />

Mikrocomputertechnik<br />

Das Timer-System steuert Funktionen, die einen Bezug zur Echtzeit benötigen, also unabhängig von<br />

Befehlsausführungszeiten sein sollen:<br />

• Der Real-Time-Interrupt (Echtzeitunterbrechung) dient dem Zweck, in genau periodischen<br />

Zeitabständen einen bestimmten Vorgang auszulösen.<br />

• Die drei Input-Capture-Funktionen (Zeiterfassungsfunktionen) IC1 bis IC3 dienen zur<br />

Zeitmessung von Eingangssignalen an den Eingangspins PA0 bis PA2.<br />

• Mit den vier Output-Compare-Funktionen (Zeitvergleichsfunktionen) OC1 bis OC4 können<br />

bei bestimmten Timer-Zählerständen 1-Pegel oder 0-Pegel an den Ausgangspins PA3 bis PA6<br />

ausgegeben werden.<br />

• Der COP-Watchdog-Timer sorgt dafür, dass die Programmlaufüberwachung innerhalb einer<br />

überwachungsperiode rechtzeitig zurückgesetzt wird. Im Fehlerfall wird ein Reset (Neustart)<br />

des Rechners veranlasst.<br />

Der 68HC11 hat eine recht komplexe Timer-Struktur, die mit Abstand die meisten Register im<br />

E/A-Bereich belegt. Entsprechend komplex ist seine Programmierung.<br />

5.4 Zähler 114


Basis des Timersystems ist ein konstant durchlaufender, nicht beeinflussbarer 16-Bit-Zähler, der im<br />

Register TCNT abgebildet ist. Das Timersystem leitet seinen Takt über Teiler vom Quarztakt ab<br />

(Abbildung 31). Die folgenden Zeitangaben beziehen sich auf eine Quarzfrequenz von 8 MHz, was<br />

einem CPU-Takt von 2 MHz entspricht. Der Vorteiler für den freilaufenden 16-Bit-Zähler wird durch<br />

die Bits PR0/PR1 im Register TMSK2 programmiert. Die folgende Tabelle zeigt, mit welchen<br />

Taktperioden der Zähler dann getriggert wird.<br />

Die beiden Vorteiler werden durch die Bits PR0/PR1 im Register TMSK2 und RTR0/RTR1 im<br />

Register PACTL programmiert. Nach einem RESET steht hier jeweils ein Wert von 0, so daß die<br />

höchste Taktrate ausgewählt ist. Diese beiden Bits können nur direkt nach einem RESET verändert<br />

werden, danach ist jeder weitere Zugriff gesperrt. Diese besondere Eigenschaft des Mikroprozessors<br />

68HC11 verhindert ungewollte Veränderungen an der Timer-Auflösung durch unzulässige Zugriffe,<br />

die während des Betriebs durch Störimpulse von außen ausgelöst werden könnten.<br />

PRn<br />

1 0<br />

division<br />

factor<br />

output<br />

period<br />

0 0 1 32.77<br />

ms<br />

0 1 4 131.07<br />

ms<br />

1 0 8 262.14<br />

ms<br />

1 1 16 524.29<br />

ms<br />

Mikrocomputertechnik<br />

RTRn<br />

1 0<br />

division<br />

factor<br />

output<br />

period<br />

0 0 1 4.096<br />

ms<br />

0 1 2 8.192<br />

ms<br />

1 0 4 16.384<br />

ms<br />

1 1 8 32.768<br />

ms<br />

5.4 Zähler 115


TOF timer overflow<br />

flag<br />

TOI timer overflow<br />

interrupt enable<br />

RTIF real time interrupt<br />

flag<br />

RTII real time interrupt<br />

enable<br />

Der Timer<br />

Wird gesetzt, wenn der frei laufende 16-Bit-Zähler von FFFF auf 0<br />

wechselt (Zählerüberlauf). Wird zurückgesetzt durch Schreiben einer 1<br />

in TOF.<br />

Interruptfreigabe für "Timer Overflow Interrupt", 0 = Interrupt gesperrt,<br />

1 = Interrupt freigegeben.<br />

Wird gesetzt, wenn der Realtime-Interrupt-Zähler auf 0 wechselt<br />

(Zählerüberlauf). Wird zurückgesetzt durch Schreiben einer 1 in RTIF.<br />

Interruptfreigabe für "Realtime Interrupt", 0 = Interrupt gesperrt, 1 =<br />

Interrupt freigegeben.<br />

Der Timer des 68HC11 besitzt eine Länge von 16 Bit. Aus diesem Grund muß er mit einem<br />

16-Bit-Ladebefehl gelesen werden, da nur dann die beiden Bytes des Ergebnisses wirklich zusammen<br />

gehören. Würden das obere und das untere Byte getrennt voneinander gelesen, bestände kein<br />

eindeutiger Zusammenhang.<br />

Nach einem Reset der CPU ist der Zählerstand des Timers 0. Es gibt keine Möglichkeit, den<br />

Zählerstand des Timers auf einen bestimmten Wert zu setzen. Direkt nach dem Reset beginnt der<br />

Timer aufwärts zu zählen. Bei jedem Überlauf von $FFFF auf $0000 wird das Überlauf-Bit TOF<br />

(Timer Overflow) im Register TFLG2 gesetzt, um diesen Zustand anzuzeigen. Die Anwendersoftware<br />

kann so auf einfache Weise eine Kaskadierung des Timers auf beliebige Wortlänge durchführen, da<br />

dieses Bit auch einen Interrupt auslösen kann.<br />

Für die meisten Anwendungsfälle ist es sinnvoll, die längste zu messende Zeit zu bestimmen und dann<br />

den Vorteiler so zu definieren, daß innerhalb dieser Zeit kein Timer-Überlauf auftreten kann. Alle<br />

Zeitpunktberechnungen können dann mit einfacher 16-Bit-Arithmetik durchgeführt werden. Man darf<br />

nicht übersehen, daß das Timer-System mit 16 Bit auflöst, der Fehler bezogen auf eine Periode ist<br />

1/65536 entsprechend 0,0015 %. Diese Genauigkeit ist für fast alle Anwendungen ausreichend. Erhöht<br />

man die Taktrate des Timer-Systems und arbeitet mit höherer Auflösung, dann addieren sich<br />

Software-Reaktionszeiten, was häufig zu wesentlich größeren Fehlern führen.<br />

Bei jedem Überlauf des Timers von $FFFF auf $0000 wird das Überlauf-Bit (TOF = Timer Overflow<br />

Flag) im TFLG2-Register gesetzt. Das TOF-Bit muß vom Anwenderprogramm gezielt wieder<br />

gelöscht werden. Wird das Auslösen eines Interrupts bei jedem Timer-Oberlauf gewünscht, dann kann<br />

das zum TOF-Bit korrespondierende TOI-Bit (Timer Overflow Interrupt) im TFLG2-Register auf 1<br />

gesetzt werden.<br />

Der frei laufende Timer<br />

Mikrocomputertechnik<br />

Der frei laufende Haupt-Timer des 68HC11 wird bei Reset auf 0 gesetzt und beginnt dann zu laufen.<br />

Derartige Timer findet man auch bei fast jedem anderen Controller. Der Zählerstand kann über ein<br />

16-Bit-Register auf den Adressen $100E und $100F ausgelesen werden. Wichtig ist hierbei, dass<br />

mittels einer 16-Bit-Operation gelesen wird (LDD). Würde man zwei aufeinander folgende<br />

8-Bit-Operationen zum Lesen nehmen (LDAA, LDAB), bekäme man einen "Versatz" von vier<br />

Taktzyklen, da die Ladeoperation so lange dauert.<br />

Der Haupt-Timer läuft nach dem Einschalten mit dem E-Takt der CPU. Der Takt kann noch durch<br />

einen Prescaler geteilt werden, wobei die Faktoren 1, 4, 8 oder 16 möglich sind. Der Teilfaktor wird<br />

über die Bits 0 und 1 des TMASK-Registers eingestellt. Das folgende Programm illustriert den<br />

Sachverhalt, indem der Timer ständig ausgelesen und auf den Ports B und C ausgegeben wird.<br />

Der Timer 116


data equ $2000 ; Datenbereich<br />

prog equ $8000 ; Programmbereich<br />

stack equ $7FFF ; Stackbereich<br />

tirqv equ $FFDE ; Adresse TOF-Vektor<br />

resetv equ $FFFE ; Adresse Reset-Vektor<br />

pcdd equ $1007 ; Adressen Port C<br />

pcdr equ $1003<br />

portb equ $1004 ; Adresse Port B<br />

pacr equ $1026 ; Pulse Akku Control<br />

tflag equ $1025 ; Timer Flag<br />

tmask equ $1024 ; Timer Mask<br />

tcnt equ $100e ; Timer Counter<br />

org data<br />

org prog<br />

main lds #stack ; Init Stack<br />

ldab #$FF ; Port C auf Ausgang<br />

stab pcdd<br />

ldab #$03 ; Timer-Prescaler / 16<br />

stab tmask ; --> 524,3 ms<br />

loop ldd tcnt ; Zaehler laden HIGH in A,<br />

; LOW in B<br />

staa portb ; ausgeben<br />

stab pcdr<br />

bra loop<br />

org resetv ; Reset-Vektor setzen<br />

fdb main<br />

Real-Time-Interrupt<br />

Häufig wird in einem Mikroprozessorprogramm eine feste Zeitbasis zur Steuerung bestimmter<br />

Abläufe benötigt. Dafür besitzt der 68HC11 einen speziellen Real-Time-Interrupt, der von den Bits<br />

RTII im Register TMSK2 und RTIF im Register TFLG2 gesteuert wird. Nach Ablauf einer<br />

vordefinierten Zeitspanne wird das Bit RTIF im TFLG2-Register gesetzt. Zur Auslösung eines<br />

Interrupts muß auch hier das korrespondierende RTII-Bit im TMSK2-Register auf 1 gesetzt sein. Das<br />

RTIF-Bit muß zwingend vom Interrupt-Programm durch Schreiben einer 1 an diese Stelle wieder<br />

gelöscht werden, da sonst sofort der nächste Interrupt ausgelöst würde. Die Periodendauer des<br />

Real-Time-Interrupts wird über zwei Bits im PACTL-Register vorgesehen (RTRO und RTR1)<br />

eingestellt.<br />

Beispiel: Uhrentakt mittels RTI<br />

(Quelle: Wallrabe: Mikrocontrollerpraxis, Hanser Verlag)<br />

Dazu gehen wir von der kürzesten Grundperiode 4,096 ms aus, da sie die feinste Stufung erlaubt. Als<br />

Anfangsstand des Zählers wählen wir 244. Die so erzeugte Periode dauert somit 244 - 4,096 ms =<br />

999,424 ms. An der genauen Sekunde fehlen 0,576 ms, ein Fehler, der toleriert werden kann. Nach<br />

diesen Vorgaben ist das folgende Beispiel aufgebaut, das, vom Anfangswert 244 ausgehend, nach<br />

jedem RTI-Interrupt die Variable RTIZaehl herunterzählt und bei Erreichen von 0 einen Sekunden-,<br />

Minuten- und Stundenzähler hochzählt.<br />

Die Zeitwerte sollen natürlich dezimal und nicht binär (hexadezimal) ausgegeben werden. Daher wird<br />

nach jedem Inkrementieren eines Zählers dessen Wert mit dem Befehl DAA sofort in einen<br />

BCD-Wert umgewandelt und auch so abgespeichert.<br />

Voraussetzung ist, daß im Hauptprogramm folgende RAM-Variablen vorab definiert und initialisiert<br />

worden sind:<br />

RTIZaehl = Adresse des RTI-Zählers<br />

SekZaehl = Adresse des Sekunden-Zählers<br />

Mikrocomputertechnik<br />

Der Timer 117


MinZaehl = Adresse des Minuten-Zählers<br />

StdZaehl = Adresse des Stunden-Zählers<br />

Sek_alt = Zwischenspeicher<br />

Mikrocomputertechnik<br />

UHR DEC RTIZaehl RTI-Zähler dekrementieren.<br />

BNE UHR_E<br />

LDAA #244 Wenn RTI-Zähler = 0:<br />

STAA RTIZaehl Neu mit Ausgangswert laden.<br />

LDAA SekZaehl Nach 1 Sekunde:<br />

INCA Sekundenzähler hochzählen,<br />

DAA in BCD-Zahl wandeln.<br />

STAA SekZaehl<br />

CMPA #$60<br />

BNE UHR_E<br />

CLRB Nach 60 Sekunden:<br />

STAB SekZaehl Sekundenzähler auf 0 setzen,<br />

LDAA MinZaehl Minutenzähler hochzählen,<br />

INCA<br />

DAA<br />

STAA MinZaehl<br />

CMPA #$60<br />

BNE UHR_E Nach 60 Minuten:<br />

STAB MinZaehl Minutenzähler auf 0 setzen,<br />

LDAA StdZaehl Stundenzähler hochzählen,<br />

INCA<br />

DAA<br />

STAA StdZaehl<br />

CMPA #$24<br />

BNE UHR_E Nach 24 Stunden:<br />

STAB StdZaehl Stundenzähler auf 0.<br />

UHR_E LDAA #$40 Rücksetzen des RTI-Flags.<br />

STAA TFLG2<br />

RTI<br />

Diese Uhr tickt unsichtbar und lautlos im Inneren des 68HC11. Daher wird das Unterprogramm zu<br />

einem kompletten lauffähigen Beispielprogramm erweitert, bei dem die Zeit über die serielle<br />

Schnittstelle an den PC gesendet und Monitor sichtbar gemacht wird. Das Programm beginnt mit<br />

einem Initialisierungsteil, in dem die serielle Schnittstelle und der RTI-Interrupt vorbereitet sowie die<br />

Variablen auf ihre Ausgangswerte gesetzt werden.<br />

VECRTI equ $FFEB Real Time Interrupt<br />

TMSK2 equ $1024 Timer Interrupt Mask Reg.2<br />

SCSR equ $102e SCI Status Reg.<br />

SCDR equ $102f SCI Data Reg.<br />

BSR INIT_SCI Schnittstelle Init, siehe 5.3<br />

LDD #UHR<br />

STD VECRTI ...RTI-Serviceroutine "UHR".<br />

LDAA #$40 RTI-Interrupt freigeben.<br />

STAA TMSK2 (4,096 ms ungeaendert wie Vorgabe).<br />

LDAA #244 RTI-Zaehler<br />

STAA RTIZaehl auf Ausgangswert setzen.<br />

CLRB Ebenso...<br />

STAB SekZaehl ...Sekunden-Zaehler<br />

STAB Sek_alt ...Sekunden-Vergleichszaehler<br />

STAB MinZaehl ...Minuten-Zaehler<br />

STAB StdZaehl ...Stunden-Zaehler<br />

CLI Interrupts aktivieren<br />

UhrStart LDAA SekZaehl Warten, bis Sekunde einen neuen...<br />

CMPA Sek_alt<br />

BEQ UhrStart ...Wert hat.<br />

STAA Sek_alt Neuen Wert in Vergleichszaehler<br />

Der Timer 118


LDAA StdZaehl Stunden ausgeben<br />

JSR Hex_Tx<br />

LDAA #":" Trennzeichen ":" ausgeben<br />

JSR Byte_Tx<br />

LDAA MinZaehl Minuten ausgeben<br />

JSR Hex_Tx<br />

LDAA #":"<br />

JSR Byte_Tx<br />

LDAA SekZaehl Sekunden ausgeben<br />

JSR Hex_Tx<br />

LDAA #$0D Carriage Return ausgeben<br />

JSR Byte_Tx<br />

BRA UhrStart<br />

* Ausgabe eines Bytes hexadezimal ueber die serielle Schnittstelle<br />

* Das zu sendende Byte muî im Akku A vorliegen.<br />

Hex_Tx PSHA Zu sendendes Byte retten.<br />

ANDA #$F0 Hw.-Nibble abtrennen<br />

LSRA und 4 Stellen nach rechts schieben,<br />

LSRA dabei Nullen nachziehen.<br />

LSRA<br />

LSRA<br />

CMPA #9 0 bis 9 oder A bis F ?<br />

BHI Buchst1<br />

Ziff1 ADDA #"0" 0 bis 9.<br />

JSR Byte_Tx Zum Sender.<br />

BRA Nibble2<br />

Buchst1 ADDA #"A" A bis F.<br />

JSR Byte_Tx<br />

Nibble2 PULA Byte wieder holen.<br />

ANDA #$0F Nw.-Nibble abtrennen.<br />

CMPA #9<br />

BHI Buchst2<br />

Ziff2 ADDA #"0"<br />

JSR Byte_Tx<br />

RTS<br />

Buchst2 ADDA #"A"<br />

JSR Byte_Tx<br />

RTS<br />

* Ausgabe eines Bytes ueber die serielle Schnittstelle<br />

* Das zu sendende Byte muî im Akku A vorliegen.<br />

Byte_Tx LDAB SCSR Statusregister TDRE abfragen, ob leer.<br />

ANDB #$80<br />

BEQ Byte_Tx Abfrage wiederholen, wenn nicht.<br />

STAA SCDR Byte ausgeben.<br />

RTS<br />

Input Capture und Output Compare<br />

Mikrocomputertechnik<br />

Der Zählerstand kann von drei Input-Capture-Registern zur exakten Bestimmung des Zeitpunktes<br />

einer extern erkannten Flanke und von fünf Output-Compare-Registern zur Erzeugung exakter<br />

Impulse und Kurvenformen ausgewertet werden.<br />

Der Timer 119


Mikrocomputertechnik<br />

• Input Capture: Der Zählerstand des freilaufenden 16-Bit-Zählers wird als Echtzeitreferenz<br />

betrachtet, jede von der entsprechend programmierten Prozessorhardware erkannte Flanke<br />

eines extemen Signals speichert den aktuellen Stand dieses Zählers und damit den genauen<br />

Zeitpunkt in einem der Input-Capture-Register. Auf diese Weise ist es möglich, aus zwei<br />

aufeinanderfolgenden Impulsflanken eines Signals die Periodendauer als Differenz der<br />

Zeitpunkte zu bestimmen. Impulsbreiten können durch Verändern der aktiven Flanke nach<br />

Eintreten des ersten Ereignisses bestimmt werden.<br />

Jede einzelne Input-Capture-Funktion beinhaltet ein 16-Bit-Latch, in dem der Zeitpunkt eines<br />

Ereignisses festgehalten werden kann. Die notwendige Synchronisation zwischen<br />

asynchronem externen Ereignis und internem E-Takt wird von der Prozessor-Hardware<br />

unsichtbar für den Anwender vorgenommen. Der hierdurch entstehende Fehler ist klein gegen<br />

die Timer-Auflösung.<br />

Der Transfer des Timer-Inhalts in eines der Input-Capture-Register erfolgt bei der<br />

nichtzählenden Flanke des Timer-Signals, so daß ein sicherer Wert auf jeden Fall garantiert<br />

werden kann. Die Hardware zur Übertragung des Timer-Inhaltes ist für jedes<br />

Input-Capture-Register getrennt vorhanden, so daß es erlaubt ist, alle drei<br />

Input-Capture-Eingänge gleichzeitig zu triggern. Das Auslesen eines der<br />

Input-Capture-Register T1C1 bis T1C3 muß mit einem 16-Bit-Zugriff erfolgen, da nur so<br />

gewährleistet ist, daß die beiden Bytes des Ergebnisses wirklich zusammengehören. Wird der<br />

Inhalt eines der Input-Capture-Register nicht gelesen und tritt dann ein weiteres Ereignis ein,<br />

so wird der alte Wert überschrieben. Der Inhalt dieser Register repräsentiert also immer das<br />

letzte aufgetretene Ereignis. Je ein Bit im TMSK1- und TFLG1-Register sind als Schnittstelle<br />

zum Anwenderprogramm vorgesehen.<br />

Der Timer 120


Die Bits IC1F bis IC3F werden vom Mikroprozessor gesetzt, wenn einer der drei<br />

Input-Capture-Kanäle ein Ereignis registriert. Die zugehörigen Bits IC1I bis IC3I sind jeweils<br />

zur Freigabe eines Interrupts als Reaktion vorgesehen und müssen vom Anwenderprogramm<br />

definiert werden.<br />

Jeder der drei Kanäle kann auf verschiedene Flanken programmiert werden. Dazu sind im<br />

Register TCTL2 jeweils 2 Bit pro Capture-Kanal vorgesehen:<br />

EDGxB EDGxA Aktivierte Flanke<br />

0 0 Keine, Kanal ausgeschaltet<br />

0 1 Ansteigende Flanke<br />

1 0 Abfallende Flanke<br />

1 1 Beide Flanken<br />

Das folgende Programm verwendet die Input-Capture-Register, im die Periodendauer eines<br />

Signals zu messen. Das Signal ist am niederwertigen Kanal 0 (IC1) angeschlossen. Das erste<br />

Beispiel arbeitet im Polling Mode: Es wird bei der Initialisierung festgelegt, ob auf steigende<br />

oder fallende Flanke reagiert werden soll - in diesem Fall wurde die steigende Flanke gewählt.<br />

Nun wartet das Programm auf die erste Flanke und speichert den aktuellen Timerwert. Danach<br />

wird auf die nächste Flanke gewartet und von dem nun gelesenen Timerwert der Timerstand<br />

bei der ersten Flanke abgezogen. Das Ergebnis wird als Periodendauer gespeichert.<br />

data equ $2000 ; Datenbereich<br />

prog equ $8000 ; Programmbereich<br />

stack equ $7FFF ; Stackbereich<br />

resetv equ $FFFE ; Adresse Reset-Vektor<br />

tic1 equ $1010 ; Zaehlerstand<br />

tflg1 equ $1023 ; Timer Flag<br />

tctl2 equ $1021 ; Timer Control<br />

org data<br />

edge1 ds.b 2 ; Zaehler<br />

period ds.b 2 ; Clock Flag<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack ; Init Stack<br />

ldab #$10 ; Flanke waehlen (fallend = 0, steigend = 1)<br />

stab tctl2 ; steigende Flanke an IC1<br />

loop ldab #$04<br />

stab tflg1 ; IC1F-Flag loeschen<br />

waitf1 ldab tflg1 ; auf erste Flanke warten<br />

andb #$04<br />

beq waitf1<br />

ldd tic1 ; akt. Zaehlerstand holen<br />

std edge1 ; und speichern<br />

ldab #$04<br />

stab tflg1 ; IC1F-Flag loeschen<br />

waitf2 ldab tflg1 ; auf zweite Flanke warten<br />

andb #$04<br />

beq waitf2<br />

ldd tic1 ; akt. Zaehlerstand holen<br />

subd edge1 ; ersten Zaehlerstand abziehen<br />

std period ; Periodendauer abspeichern<br />

*<br />

* restlicher<br />

* Programmcode<br />

*<br />

bra loop<br />

org resetv ; Reset-Vektor setzen<br />

fdb main<br />

Der Timer 121


Mikrocomputertechnik<br />

Statt wie oben im Hauptprogramm auf die beiden Flanken zu warten, kann auch hier wieder<br />

eine Interrupt-Service-Routine die Aufgabe übernehmen. Das folgende Programm zur<br />

Periodendauermessung ersetzt das Polling durch Interruptsteuerung. Die ISR speichert beim<br />

ersten Auftreten einer steigenden Flanke den aktuellen Zählerstand in der Variablen edge1<br />

und dekrementiert edgecnt. Bei der zweiten Flanke wird nur edgecnt dekrementiert, der<br />

daraufhin 0 ist und dem Hauptprogramm signalisiert, dass nun die Periodendauer wie beim<br />

vorhergehenden Programm berechnet werden kann.<br />

data equ $2000 ; Datenbereich<br />

prog equ $8000 ; Programmbereich<br />

stack equ $7FFF ; Stackbereich<br />

tirqv equ $FFEE ; Adresse Interrupt-Vektor<br />

resetv equ $FFFE ; Adresse Reset-Vektor<br />

tic1 equ $1010 ; Zaehlerstand<br />

tmsk1 equ $1022 ; Timer Mask<br />

tflg1 equ $1023 ; Timer Flag<br />

tctl2 equ $1021 ; Timer Control<br />

org data<br />

edgecnt ds.b 1 ; Flanken-Zaehler<br />

edge1 ds.b 2 ; Capture erste Flanke<br />

period ds.b 2 ; Clock Flag<br />

org prog<br />

main lds #stack ; Init Stack<br />

ldab #$10 ; Init Timer<br />

stab tctl2 ; steigende Flanke an IC1F<br />

ldab #$04<br />

stab tflg1 ; IC1F-Flag loeschen<br />

ldab #2 ; Flanken-Zaehler auf 2 setzen<br />

stab edgecnt<br />

ldab tmsk1 ; Interrupt freigeben<br />

orab #4<br />

stab tmsk1<br />

cli<br />

wait tst edgecnt ; warten, bis Flanken-Zahler = 0<br />

bne wait<br />

ldd tic1 ; akt. Zaehlerstand holen<br />

subd edge1 ; ersten Zaehlerstand abziehen<br />

std period ; Periodendauer abspeichern<br />

*<br />

* restlicher<br />

* Programmcode<br />

*<br />

bra wait<br />

* Interrupt-Service-Routine fuer Input Capture<br />

ic1_isr ldab #$04<br />

stab tflg1 ; IC1F-Flag loeschen<br />

dec edgecnt ; Flanken-Zaehler dekrementieren<br />

beq skip ; falls zweite Flanke, nichts tun<br />

ldd tic1 ; sonst akt. Zaehlerstand holen<br />

std edge1 ; und speichern<br />

skip rti<br />

org tirqv ; Reset-Vektor setzen<br />

fdb ic1_isr<br />

org resetv ; Reset-Vektor setzen<br />

fdb main<br />

Der Timer 122


•<br />

Mikrocomputertechnik<br />

Durch einige Modifikationen kann dies Programmschema auch verwendet werden, um<br />

anstelle der Periodendauer die Breite eines Impulses zu messen. Es wird dann wie oben bei<br />

der (ersten) steigenden Flanke der Zählerwert gespeichert und danach der Port so<br />

umkonfiguriert, dass nun auf eine fallende Flanke gewartet wird: in tflg1 wird anstelle von<br />

$10 nun $20 geschrieben. So wird als zweites Ereignis die fallende Flanke registriert.<br />

Der einzige Nachteil der obigen Input Capture-Programme liegt darin, dass sich nur Zeiten<br />

erfassen lassen, die im 16-Bit-Bereich liegen, also nicht größer als 32,761 ms sind. Um<br />

längere Perioden zu messen, kann man beispielsweise das Timer-Overflow-Flag in tmask2<br />

berücksichtigen und bei jedem Timer-überlauf einen weiteren Zähler inkrementieren. Auf<br />

diese Art und Weise kann so der hardwaremäßige 16-Bit-Zähler softwareseitig auf 32 oder<br />

mehr Bits erweitert werden.<br />

Output Compare: Jedes der fünf Output-Compare-Register wird laufend mit dem<br />

Zählerstand des freilaufenden Zählers verglichen. Bei Übereinstimmung wird dann exakt in<br />

diesem Moment die programmierte Reaktion ausgelöst, zum Beispiel die Ausgabe eines<br />

bestimmten Signals an einem Port. Auf diese Weise ist es möglich, ein Ausgangssignal mit<br />

der Genauigkeit und Auflösung des Timer-Systems zu einem gewünschten Zeitpunkt zu<br />

erzeugen, ohne dabei Fehler durch Software-Reaktionszeiten oder auch Verzögerungen durch<br />

Interrupt-Antwortzeiten zu haben.<br />

Insgesamt sind fünf Output-Compare-Funktionen vorhanden, die jeweils ein<br />

16-Bit-Vergleichsregister besitzen. Der Registerinhalt wird ständig mit dem Zählerstand<br />

verglichen. Bei Übereinstimmung wird das vorprogrammierte Ereignis ausgelöst. Auch hier<br />

ist je ein Bit im TMSK1- und TFLG1-Register als Schnittstelle zum Anwenderprogramm<br />

vorgesehen. Das jeweiling OCxF-Bit wird gesetzt, wenn Register und Zähler übereinstimmen.<br />

Mit den zugehörigen OCxI-Bit kann der Interrupt gesperrt oder freigegeben werden.<br />

Für die Kanäle 2 bis 5 kann im TCTL1-Register festgelegt werden, was mit dem zugehörigen<br />

Pin beim Eintreten eines Ereignisses geschehen soll:<br />

OMx OLx Reaktion<br />

0 0 Keine<br />

0 1 Polarität ändern (toggle)<br />

1 0 auf 0 setzen<br />

1 1 auf 1 setzen<br />

Mit dem Output Compare Register 1 kann man alle OC-Pins gleichzeitig manipulieren. Der<br />

OC-Pn 1 hat dabei Priorität über die anderen. Der OC1-Funktion sind zwei spezielle Register<br />

zugeordnet, OC1M und OC1D. Die Bits 3 bis 7 dieser Register entsprechen direkt den<br />

Leitungen von Port A, auf denen die OC-Werte ausgegeben werden. Für jede Leitung von<br />

Port A, die durch die OC-Funktion beinflußt werden soll, muß das entsprechende Bit in<br />

OC1M auf 1 gesetzt werden. Das Bitmuster für die Ausgabe wird dann in OC1D eingetragen.<br />

Auf diese Weise lassen sich fünf Pins exakt zeitgleich mit einem einzigen<br />

Output-Compare-Register beeinflussen.<br />

Das folgende Programm zeigt eine typische Anwendung: es wird ein Rechtecksignal von 1<br />

kHz auf OC2 erzeugt, wobei ein Tastverhältnis von 40% eingestellt wird. Die verwendeten<br />

Werte gelten wieder für 2 MHz Taktfrequenz und einen Prescaler-Faktor von 1. Zu Beginn<br />

wird PA6 auf 1 gesetzt und danach der Toggle-Modus festgelegt. Für die Frequenz von 1 kHz<br />

muss bei 2 MHz Prozessortakt die Summe von Low- und Highzeit 2000 E-Takt-Zyklen<br />

betragen. Für das gewünschte Tastverhältnis muss demnach die Low-Zeit 1200 Zyklen und<br />

die High-Zeit 800 Zyklen lang sein. Andere Tastverhältnisse lassen sich durch Ändern dieser<br />

Werte leicht bestimmen. Dass beim Initialisierten dreimal hintereinander der Wert $40<br />

verwendet wird, ist Zufall - bei anderen Ports sind die Werte unterschiedlich.<br />

data equ $2000 ; Datenbereich<br />

prog equ $8000 ; Programmbereich<br />

Der Timer 123


stack equ $7FFF ; Stackbereich<br />

resetv equ $FFFE ; Adresse Reset-Vektor<br />

porta equ $1000 ; Adresse Port A<br />

toc2 equ $1018 ; Output Compare Register<br />

tctl1 equ $1020 ; OC Control Register<br />

tflg1 equ $1023 ; Timer Flag<br />

tcnt equ $100e ; Timer Counter<br />

* Programmkonstante<br />

lotime equ 1200 ; 600 Mikrosekunden<br />

hitime equ 800 ; 400 Mikrosekunden<br />

org data<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack ; Init Stack<br />

ldaa #$40 ; OC2 auf high<br />

staa porta<br />

ldaa #$40 ; OC2F Flag loeschen<br />

staa tflg1<br />

ldaa #$40 ; toggle-Mode setzen<br />

staa tctl1<br />

; Rechteck startet mit high<br />

ldd tcnt ; Zaehlerstand laden<br />

addd #hitime ; high-delay addieren<br />

std toc2 ; im Vergleichsregister speichern<br />

high ldaa tflg1 ; Schleife bis Zeit erreicht ist<br />

anda #$40<br />

beq high<br />

ldaa #$40 ; OC2-Flag loeschen<br />

staa tflg1<br />

ldd toc2 ; naechster Zyklus mit low<br />

addd #lotime<br />

std toc2<br />

low ldaa tflg1 ; Schleife bis Zeit erreicht ist<br />

anda #$40<br />

beq low<br />

ldaa #$40 ; OC2-Flag loeschen<br />

ldd toc2 ; naechster Zyklus wieder mit high<br />

addd #hitime<br />

std toc2<br />

bra high<br />

org resetv ; Reset-Vektor setzen<br />

fdb main<br />

Legt man anstelle des Toggle-Mode bei der Initialisierung fest, dass der PA-Ausgang nach<br />

dem Zeitablauf auf 0 gesetzt wird, erhält man beispielsweise einen Monoflop-Timer.<br />

Selbstverständlich lässt sich das obige Programm auch wieder so modifizieren, dass die ganze<br />

Sache interruptgesteuert abläuft. Die Interrupt-Serviceroutine wird jedesmal angesprungen,<br />

wenn die Zeit abgelaufen ist, und übernimmt das Eintragen der High- und Low-Zeiten. Damit<br />

haben Sie dann einen im Hintergrund ablaufenden Rechteckgenerator, dessen Tastverhältnis<br />

Sie jederzeit ändern können (indem Sie Vari-ablen anstelle der Konstanten verwenden) - also<br />

eine Pulsweiten-Modulation.<br />

Der OC1 nimmt eine Sonderstellung ein. Er kann über die Register OC1M und OC1D bis zu<br />

fünf OC-Pins steuern. OC1M legt fest, welche Pins von Port A beeinflusst wer-den und OC1D<br />

bestimmt, ob das entsprechende Bit auf 0 oder 1 gesetzt werden soll. übrigens ist der Pin PA7<br />

bidirektional. Soll er von OC1 gesteuert werden, muss er als Ausgang programmiert werden.<br />

Der Timer 124


Das folgende Programm zeigt, wie man mithilfe von OC1 und OC2 ein Rechtecksignal mit<br />

variablem Tastverhältnis erhält, das unabhängig vom Hauptprogramm im Hintergrund erzeugt<br />

wird. Im Initialisierungsteil wird festgelegt, dass OC2 bei Zeitgeberstand von 0 den Ausgang<br />

PA6 auf 1 setzt. OC1 wird zusätzlich so programmiert, dass beim Zeitgeberstand TV (6553)<br />

der Ausgang wieder auf 0 gesetzt wird. Nach Abschluß der Initialisierung laufen OC1 und<br />

OC2 synchron zur Zeitgeberperiode.<br />

data equ $2000 ; Datenbereich<br />

prog equ $8000 ; Programmbereich<br />

stack equ $7FFF ; Stackbereich<br />

resetv equ $FFFE ; Adresse Reset-Vektor<br />

porta equ $1000 ; Adresse Port A<br />

toc1 equ $1016 ; Output Compare Register 1<br />

toc2 equ $1018 ; Output Compare Register 2<br />

tctl1 equ $1020 ; OC Control Register<br />

tflg1 equ $1023 ; Timer Flag<br />

tmsk2 equ $1024 ; Timer Mask Register<br />

oc1m equ $100c ; OC1M-Register<br />

oc1d equ $100d ; OC1D-Register<br />

tcnt equ $100e ; Timer Counter<br />

TV equ 6553 ; Tastverhaeltnis (2^16 Zehntel)<br />

org data<br />

org prog<br />

main lds #stack ; Init Stack<br />

ldaa #$03 ; Timer-Takt auf 8 Mikrosekunden<br />

staa tmsk2 ; --> 524,3 ms zwischen Ueberlaeufen<br />

ldaa #$C0 ; OC2 --> PA6 auf 1 setzen<br />

staa tctl1<br />

ldd #0 ; Zaehler auf Null<br />

std toc2<br />

ldaa #$40 ; OC1 --> PA6 auf 0<br />

staa oc1m ; Bit selektieren<br />

ldaa #$BF ; soll 0 werden<br />

staa oc1d<br />

ldd #TV ; Pulsdauer festlegen<br />

std toc1<br />

loop bra loop ; Hauptprogramm tut nicht<br />

org resetv ; Reset-Vektor setzen<br />

fdb main<br />

Experimentieren Sie ruhig mit verschiedenen Werten für TV. Selbst im Simulator lassen sich<br />

Unterschiede erkennen.<br />

Pulse-Akkumulator<br />

Mikrocomputertechnik<br />

Der Pulse-Akkumulator des 68HC1 ist ein 8-Bit-Zähler, der wahlweise als Ereigniszähler oder als<br />

Zeitzähler mit externer Gate-Funktion verwendet werden kann. Für beide Fälle wird der Anschluß<br />

Port A Bit 7 als Eingang für das externe Signal benutzt. Es sind zwei Möglichkeiten vorgesehen, einen<br />

Interrupt auszulösen: bei jeder aktiven Flanke dieses Eingangs oder bei Überlauf des Zählerstandes<br />

von $FF auf $00.<br />

Wird der Pulse-Akkumulator als Zeitzähler eingesetzt, dann verarbeitet er das durch 64 geteilte Signal<br />

des internen E-Takts. Die Auflösung beträgt damit bei einer Quarzfrequenz von 8 MHz exakt 32<br />

Mikrosekunden, die längste meßbare Periode somit 256 * 0,032 ms = 8,192 ms. Beim Einsatz als<br />

Ereigniszähler können maximal 256 Flanken gezählt werden, die zu verarbeitende Frequenz muß<br />

niedriger als der E-Takt des Mikroprozessors sein. Die für die Interruptauslösung des<br />

Der Timer 125


Pulse-Akkumulatorsystems zuständigen Konfigurations- und Flagbits sind zusammen mit anderen<br />

Funktionen im TMSK2- und TFLG2-Register untergebracht. Das PAOVF-Bit im TFLG2-Register<br />

wird immer dann gesetzt, wenn ein Überlauf des Zählers von $FF auf $00 eintritt. Durch Setzen des<br />

korrespondierenden Interrupt-Bits PAOVI im TMSK2-Register kann der Anwender bestimmen, ob<br />

durch dieses Ereignis ein Interrupt ausgelöst werden soll (0 = kein Interrupt). Der gleiche<br />

Mechanismus steuert mit den Bits PAIF und PAII einen möglichen Prozessor-Interrupt bei jeder<br />

aktiven Flanke am Eingang des Pulse-Akkumulators.<br />

• Damit das Pulse-Akkumulator-System überhaupt arbeiten kann, muß der externe Pin 7 von<br />

Port A als Eingang konfiguriert werden. Hierzu muß das Bit DDRA7 im PACTL-Register auf<br />

0 gesetzt werden.<br />

• Das Bit PAEN dieses Registers schaltet den Pulse-Akkumulator generell ein und aus, wobei<br />

der Zählerstand nach dem Ausschalten des Systems weiter erhalten bleibt und ausgewertet<br />

werden kann.<br />

• Das Bit PAMOD definiert die Betriebsart des Zählers: eine O macht ihn zum Ereigniszähler,<br />

eine 1 wählt die Zeitmessung.<br />

• PEDGE erlaubt die Wahl der aktiven Flanke. Eine 0 läßt den Zähler auf abfallende Flanken<br />

reagieren, in der Betriebsart Zeitzähler stoppt ein Low-Signal die Messung, eine 1 in PEDGE<br />

wählt die ansteigende Flanke und ein High-Signal als Sperre für die Betriebsart Zeitzähler.<br />

5.5 Geschützte Register<br />

(time protected control registers)<br />

Diese Register können nur während der ersten 64 Taktzyklen des E-Taktes nach einem RESET<br />

beschrieben werden.<br />

INIT bit 7-4: RAM3, RAM2, RAM1, RAM0<br />

position direct page at 4k-boundaries<br />

(default = 0000, RAM = $0000-$00FF)<br />

bit 3-0: REG3, REG2, REG1, REG0<br />

position Register block at 4k-boundaries<br />

(default = 0001, REG = $1000-$103F)<br />

TMSK2 bit 1-0: PR1, PR0<br />

prescaler of main timer<br />

(default = 00, ps = 1)<br />

OPTION bit 5: IRQE<br />

IRQ edge or level sensitive<br />

(default = 0, level sensitive)<br />

bit 4: DLY<br />

delay after coming out of STOP power saving mode<br />

(default = 1, wait 4000 cycles to stabilize crystal oscillator)<br />

bit 1-0: CR1, CR0<br />

COP timer rate on 2 15 base<br />

(default = 00, tr = 1)<br />

Mikrocomputertechnik<br />

5.5 Geschützte Register 126


5.6 Interrupts<br />

Mikrocomputertechnik<br />

Beim Daten-Verkehr zwischen Computer und der Außenwelt gibt es fast immer große und vor allem<br />

unregelmäßige Zeitabstände zwischen den Transfers. Zur Synchronisation dieser Ereignisse mit den<br />

Abläufen in einem Computer dienen Steuersignale der Peripherie, die zumindest als Status-Bits in<br />

einem Status-Register eines Peripheriebausteins erkennbar sind: im einfachsten Fall muss das<br />

Programm diese Status-Information regelmäßig abfragen, und zwar so häufig, dass kein Ereignis -<br />

auch bei maximaler Rate - "übersehen" wird.<br />

Dieser polling mode führt zu einer hohen Rechnerbelastung aufgrund von Abfragen, die auch fast<br />

immer negativ ausfallen. Alle modernen Mikroprozessoren besitzen deshalb Hardware- Mechanismen<br />

zur Programmunterbrechung durch solche Ereignisse. Das "Pollen" des Programms nach Ereignissen<br />

wird hier ersetzt durch einen von der Hardware (Ablaufsteuerung, Mikroprogramm) erzwungenen<br />

Unterprogrammsprung zu einem vorbereiteten Bearbeitungs-Programm, der sogenannten<br />

Interrupt-Service-Routine (ISR).<br />

Die ähnlichkeit des Interrupt mit einem Unterprogrammsprung (JSR) ist tatsächlich groß. Das<br />

Auftreten des Interrupt-Request-Signals auf dem Bus wird vom Mikroprogramm am Ende jedes<br />

Befehlszyklus geprüft und führt ggf. zu einem Sprung zum Beginn der ISR. (Genaugenommen ist das<br />

regelmäßige Abfragen nach externen Ereignissen nur ins Mikroprogramm der Ablaufsteuerung<br />

verlagert worden, jedoch mit sehr hoher Effizienz).<br />

Ein Interrupt kann - falls zugelassen - im Unterschied zu einem JSR prinzipiell nach jedem beliebigen<br />

Befehl des Programms wirksam werden, dementsprechend muss wie beim JSR der PC-Stand gerettet<br />

werden; auch das erledigt die Ablaufsteuerung bei der Annahme des Interrupt Request, genau wie<br />

beim JSR. Die Interrupt-Service-Routine wird mit einem ähnlichen Befehl wie ein Unterprogramm<br />

verlassen (RTI statt RTS), denn auch hier muss der Rücksprung wieder zur "Unterbrechungsstelle"<br />

zurückführen.<br />

Man unterscheidet beim 68HC11 Interrupts, die (extern!) von Hardwaresignalen ausgelöst werden<br />

(XIRQ, IRQ und RESET) und den internen Interruptquellen (interne Peripheriebausteine oder "illegal<br />

Operation"). Außerdem gibt es einem Befehl (SWI), der ebenfalls einen Interrupt auslöst. Ein weiteres<br />

Unterscheidungskriterium ist die Maskierbarkeit. Der normale Interrupt ist nur dann wirksam, wenn<br />

das entsprechende Maskenbit im CC-Register gelöscht ist (=0). Die Signale RESET und XIRQ sind<br />

nicht maskierbar, sie werden deshalb auch als "nicht maskierbare Interrupts" bezeichnet.<br />

Der XIRQ weist dabei noch eine Besonderheit auf: er ist nach einem RESET so lange gesperrt<br />

(maskiert), bis er durch Nullsetzen von Bit 6 im CC-Register zugelassen wird. Danach ist er nicht<br />

mehr sperrbar!<br />

Der 68HC11 verfügt über insgesamt 21 externe und interne Interruptquellen. Entsprechend komplex<br />

ist seine Interruptstruktur. Hier nochmals zur Erinnerung der Ablauf eines Interrupts:<br />

Nach einem Reset des Prozessors sind zunächst die beiden CC-Register-Flags X und I gesetzt und<br />

somit alle Interrupts gesperrt (= maskiert, disabled). Diese beiden Flags nennt man auch<br />

"Innensperren", denn mit ihnen kann im Prozessor verhindert werden, dass anstehende (pending)<br />

Interrupts tatsächlich den Programmablauf unterbrechen.<br />

5.6 Interrupts 127


Es ist wichtig, dass zunächst die Interrupts nicht zugelassen werden, denn erst wenn per Programm<br />

einige Vorbereitungen getroffen sind (Peripheriebausteine initialisieren, Stackpointer setzen, ) kann<br />

ein eintreffender Interrupt korrekt bedient werden.<br />

Die Interrupt-Sperren in den verschiedenen Peripherie-Bausteinen nennt man "Außensperren". Damit<br />

hat der Programmierer die Möglichkeit ganz gezielt Ereignisse sich entweder nur per Statusbit<br />

anzeigen zu lassen (polling mode) oder es sich per Interrupt melden zu lassen.<br />

Auslösen einer Unterbrechung<br />

Signal RESET Unbedinger Abbruch und Neustart<br />

Signal XIRQ und (X-Bit = 0) Unbedingte Unterbrechung (non maskable interrupt)<br />

Signal IRQ und (I-Bit = 0)<br />

Bedingte Unterbrechung (interrupt request)<br />

(kann auch interne Ursachen haben)<br />

Befehl SWI Befehlsgesteuerte Unterbrechung (software interrupt)<br />

Befehl Illegal Opcode Nicht implementierter Befehl<br />

Interrupt-Vektoren<br />

Mikrocomputertechnik<br />

Die Interrupt Service Routine (ISR) kann an beliebiger Stelle im Speicher abgelegt werden. Beim<br />

Eintreffen des Interrupts muss die ISR aufgerufen werden. Die ISR-Startadresse muss daher im<br />

Speicher bereitgestellt werden (Aufgabe des Programmierers!). Die Adressen des<br />

16-Bit-Speicherworts, in dem die Adressen der ISR abgelegt werden, liegen hardwaremäßig fest. Für<br />

jeden der verschiedenen Interrupts gibt es ein fest zugeordnetes Speicherwort (Interrupt-Vektor):<br />

Auslösen einer Unterbrechung 128


Mikrocomputertechnik<br />

Priorität Name Adresse Interrupt-Quelle<br />

21 SCIINT $FFD6 SCI serial system<br />

20 SPIINT $FFD8 SPI serial system<br />

19 PAIINT $FFDA Pulse Accumulator Input Edge<br />

18 PAOVINT $FFDC Pulse Accumulator Overflow<br />

17 TOINT $FFDE Timer Overflow<br />

16 TOC5INT $FFE0 Timer Output Compare 5<br />

15 TOC4INT $FFE2 Timer Output Compare 4<br />

14 TOC3INT $FFE4 Timer Output Compare 3<br />

13 TOC2INT $FFE6 Timer Output Compare 2<br />

12 TOC1INT $FFE8 Timer Output Compare 1<br />

11 TIC3INT $FFEA Timer Input Capture 3<br />

10 TIC2INT $FFEC Timer Input Capture 2<br />

9 TIC1INT $FFEE Timer Input Capture 1<br />

8 RTIINT $FFF0 Real Time Interrupt<br />

7 IRQINT $FFF2 IRQ External Interrupt<br />

6 XIRQINT $FFF4 XIRQ External Interrupt<br />

5 SWIINT $FFF6 Software Interrupt<br />

4 BADOPINT $FFF8 Illegal Opcode Trap Interrupt<br />

3 NOCOPINT $FFFA COP Failure (Reset)<br />

2 CMEINT $FFFC COP Clock Monitor Fail (Reset)<br />

1 RESETINT $FFFE RESET Interrupt<br />

Die nicht maskierbaren Interrupts wie RESET, CMF, COP, XIRQ, Ill. Opcode oder SWI haben eine<br />

feste Priorität. Bei den anderen Interrupts läßt sich die Priorität ändern. Die vier Bits PSEL0 bis<br />

PSEL3 im HPRIO-Register legen fest, welche Interruptquelle die höchste Priorität besitzen soll.<br />

Auslösen einer Unterbrechung 129


Mikrocomputertechnik<br />

PSEL3 PSEL2 PSEL1 PSEL0 Interrupt-Quelle<br />

0 0 0 0 Timer Overflow<br />

0 0 0 1 Pulse Accumulator Overflow<br />

0 0 1 0 Pulse Accumulator Input Edge<br />

0 0 1 1 SPI serial system<br />

0 1 0 0 SCI serial system<br />

0 1 0 1 Reserve<br />

0 1 1 0 IRQ External Interrupt<br />

0 1 1 1 Real Time Interrupt<br />

1 0 0 0 Timer Input Capture 1<br />

1 0 0 1 Timer Input Capture 2<br />

1 0 1 0 Timer Input Capture 3<br />

1 0 1 1 Timer Output Compare 1<br />

1 1 0 0 Timer Output Compare 2<br />

1 1 0 1 Timer Output Compare 3<br />

1 1 1 0 Timer Output Compare 4<br />

1 1 1 1 Timer Output Compare 5<br />

Eine besonders wichtige Rolle in jedem Mikroprozessorsystem spielen die nicht maskierbaren<br />

Interrupts. Sie sind speziell für das Auslösen lebenswichtiger Funktionen vorgesehen, wie zum<br />

Beispiel zur Erkennung eines Versorgungsspannungsausfalls. Da der Mikroprozessor 68HC11 über<br />

die Möglichkeit verfügt, seine interne Organisation zu modifizieren, ist für den externen nicht<br />

maskierbaren Interrupt XIRQ ein spezielles Bit im Condition-Code-Regisier vorgesehen, mit dem<br />

dieser direkt nach einem Reset-Vorgang maskiert wird. Dies ist kein Widerspruch, denn wenn das<br />

Anwenderprogramm die interne Organisation (Speicheraufteilung, Festlegung des Registerblocks,<br />

Initialisierung des Stackpointers) durchgeführt hat, kann dieses Bit nur ein einziges Mal auf 0 gesetzt<br />

werden. Ein erneutes Maskieren des XIRQ ist danach nicht mehr möglich, so daß man von diesem<br />

Zeitpunkt an von einem echten nicht maskierbaren Interrupt sprechen kann.<br />

Während der Organisationsphase ist es in jedem Fall zwingend notwendig, keinen Interrupt<br />

zuzulassen, denn ein während dieses Zeitraumes aufgerufenes Interrupt-Programm würde auf<br />

Resourcen zurückgreifen wollen, die unter Umständen noch nicht verfügbar sind.<br />

Eine zweite nicht maskierbare Interrupt-Quelle ist eine Erkennungsschaltung für illegale Befehlscodes<br />

(Illegal Opcode Trap). Da nicht alle möglichen Bitkombinationen mit gültigen Befehlen besetzt sind,<br />

besteht die Möglichkeit, daß die CPU durch einen Fehler im Programm oder durch einen Störimpuls<br />

von außen einen ungültigen Befehl bekommt. In einem solchen Fall wird ein spezieller Interruptvektor<br />

angesprungen, der auf eine Fehlerbehandlungsroutine zeigen sollte. Wird dieser Vektor nicht vom<br />

Anwender initialisiert, dann kann es passieren, daß er auf einen weiteren ungültigen Befehl zeigt und<br />

die CPU damit in eine Endlosschleife gerät.<br />

Eine ähnliche Funktion hat der Softwareinterrupt SWI, der häufig während der Test- und<br />

Emulationsphase eines Programms benutzt wird. Er stellt einen normalen gültigen Befehl der CPU<br />

dar. Der Software-Interrupt wird in erster Linie von Emulations-Systemen zur Manipulation des<br />

Zielprozessors benutzt. Man kann ihn aber auch für Sytemaufrufe verwenden, wenn im 68HC11 ein<br />

Mini-Betriebssystem implementiert wird.<br />

Alle weiteren Interrupt-Quellen des 68HC11 können durch das 1-Bit im Condition-Code-Register<br />

maskiert werden. Wenn dieses Bit gesetzt ist, sind alle diese Interrupt-Quellen gesperrt. Jeder<br />

Auslösen einer Unterbrechung 130


Reset-Vorgang setzt dieses Bit. Es ist Aufgabe des Anwenderprogramms, den Interrupt nach<br />

sinnvoller Initialisierung des Systems gezielt freizugeben.<br />

Jeder Eintritt in ein Interruptprogramm setzt das I-Bit, um eine weitere Unterbrechung durch einen<br />

neuen Interrupt zu verhindern. Nach Beendigung des Interruptprogramms durch einen RTI-Befehl<br />

wird es automatisch wieder gelöscht, so daß erneute Interrupts wieder zugelassen sind.<br />

Zur Erweiterung der Interrupt-Struktur steht der Eingang IRQ zur Verfügung. Hier können beliebig<br />

viele externe Interrupt-Quellen angeschlossen werden. Zu diesem Zweck ist dieser Pin nach einem<br />

Reset auf Pegelabhängigkeit geschaltet ( Möglichkeit des "wired or" mehrerer Interruptquellen), um<br />

mit externen Peripherie-ICs kompatibel zu sein. Die Konfiguration als flankenempfindlicher Eingang<br />

wird seltener angewendet, da sie nur mit einer einzigen externen Interrupt-Quelle zusammenarbeiten<br />

kann.<br />

Zusammenfassung der notwendigen Voraussetzungen zum Arbeiten mit Interrupts:<br />

1. Der IRQ-Ausgang eines externen Peripheriebausteins muß mit einem der<br />

Prozessor-Interrupt-Eingänge verbunden sein: IRQ, XIRQ, RESET (Hardware-Design).<br />

Interne Peripheriekomponenten sind natürlich schon verbunden.<br />

2. Der Stackpointer muß per LDS-Befehl gesetzt worden sein, damit die Register beim Interrupt<br />

in den beabsichtigten Stackbereich gerettet werden.<br />

3. Die Interrupt-Service-Routine muß programmiert sein.<br />

a. gegebenenfalls muß der Interrupt-Verursacher identifiziert werden, falls mehrere per<br />

"wired or" zusammengeschlossen sind.<br />

b. das IRQ-FF beim Interrupt-Verursacher muß darin gelöscht werden<br />

4. Die Startadresse der ISR muß in den entsprechenden Vektorzellen stehen. Initialsierung<br />

beispielsweise:<br />

5.<br />

6.<br />

Mikrocomputertechnik<br />

ORG $FFFE<br />

DC.W main<br />

Im Peripheriebaustein-Kontrollregister "interrupt enable" setzen (= Außensperre öffnen).<br />

im Prozessor (CC-Register) den entsprechenden Interrupt zulassen (= Innensperre öffnen).<br />

Im Praktikum geht es vor allem um die Aktionen 3, 4, 5, und 6.<br />

Beispiel 1: Bedingte Unterbrechung am Eingang PA7<br />

Am Eingang PA7 (Pulse Akku) ist ein Taster angeschlossen, mit dem eine bedingte Unterbrechung<br />

ausgelöst werden kann. Das Auftreten des Interrupts soll über eine Variable PFLAG signalisiert<br />

werden, die auch über Port C ausgegeben wird.<br />

Alle auszuführenden Schritte werden im Folgenden ausführlich beschrieben:<br />

• Setzen der Eigenschaften für PA7 im PACTL-Register:<br />

1. PA7 muss als Eingang konfiguriert werden. Die entsprechende Konfiguration findet<br />

per DDRA-Bit im Register PACTL statt: es muss auf 0 gesetzt werden.<br />

2. Eine Interrupt-Auslösung durch PA7 ist nur möglich, wenn sich der Port A im<br />

Betriebsmodus "Puls Accu Enable" befindet. Dazu muss im Register PACTL das Bit<br />

PAEN auf 1 gesetzt werden.<br />

3. Im Pulse-Accu-Betrieb muss noch unterschieden werden zwischen "Event Counting"-<br />

Auslösen einer Unterbrechung 131


und "Gated Time"- Mode. Da jedes Ereignis einen Interrupt auslösen soll, ist der<br />

"Event Counting Mode" zu wählen. Dazu muss im Register PACTL das Bit PAMOD<br />

auf 0 gesetzt werden (PAMOD = 0 -> "Event Counting Mode").<br />

4. Die steigende Impulsflanke wird durch Bit PEDGE im Register PACTL bestimmt:<br />

"Rising Edge" wird durch eine 1 gewählt.<br />

• Die ausgewählte Flanke am PA7-Pin führt somit zu einem Setzen des Statusbits PAIF im<br />

Register TFLG2. Somit könnte die Flanke auch an diesem gesetzten Bit durch Lesen des<br />

TFLG2-Registers erkannt werden ( regelmäßiges Auslesen = Polling Mode). Es soll jedoch<br />

per Interrupt gemeldet werden, deshalb muss noch der zugehörige Interrupt zugelassen<br />

werden. Erreicht wird dies durch Setzen des Bits PAII im Register TMSK2.<br />

• Schließlich ist noch eine Interrupt-Service Routine (ISR) nötig, die beim Auftreten des<br />

Interrupts die gewünschten Aktionen vornimmt (z. B. Lampe einschalten durch Ausgabe eines<br />

Bits an einem anderen Port). Unbedingt notwendig ist darin das Löschen des PAIF-Bits im<br />

Register TFLG2, denn sonst würden ständig weitere Interrupts ausgelöst! Löschen dieses Bits<br />

geschieht durch Schreiben einer 1 ins Bit PAIF!<br />

• Die Startadresse dieser ISR muss im zugehörigen Vektor abgelegt werden, damit beim<br />

Interrupt der Programcounter mit dieser Adresse geladen werden kann.<br />

• Zuletzt (als letzte Aktion der Initialisierung) muss der Interrupt ganz allgemein zugelassen<br />

werden. Dies erledigt der CLI-Befehl.<br />

Hier nun das vollständige Programm dazu:<br />

data equ $2000 Datenbereich<br />

prog equ $8000 Programmbereich<br />

stack equ $7FFF Stackbereich<br />

pirqv equ $FFDA Adresse PA-Vektor<br />

resetv equ $FFFE Adresse Reset-Vektor<br />

padr equ $1000 Adresse Port A<br />

pcdd equ $1007 Adressen Port C<br />

pcdr equ $1003<br />

pacr equ $1026 Pulse Akku Control<br />

tflag equ $1025 Timer Flag<br />

tmask equ $1024 Timer Mask<br />

org data<br />

pflag ds.b 1<br />

org prog<br />

main lds #stack Init Stack<br />

clr pflag Init Flag<br />

ldab #$FF Port C auf Ausgang<br />

stab pcdd<br />

ldab #$40 Init Interrupt<br />

stab pacr Pulse Akku enable<br />

ldab #$10<br />

stab tmask PA7 enable<br />

cli Interrupt freigeben<br />

loop ldab pflag Ausgabeschleife<br />

stab pcdr<br />

bra loop<br />

Mikrocomputertechnik<br />

pirq ldaa #$10 Interrupt Service Routine<br />

staa tflg<br />

com pflag toggle 0 - FF 0 - FF - ...<br />

rti<br />

org pirqv Interrupt-Vektor setzen<br />

dc.w pirq<br />

Auslösen einer Unterbrechung 132


org resetv Reset-Vektor setzen<br />

dc.w main<br />

Beispiel 2: Bedingte Unterbrechung am Eingang STRA<br />

Am Eingang STRA ist ein Taster angeschlossen, mit dem eine bedingte Unterbrechung ausgelöst<br />

werden kann. Das Auftreten des Interrupts soll über eine Variable TFLAG signalisiert werden, die<br />

auch über Port C ausgegeben wird. Das Verfahren für STRA ist nahezu identisch mit dem oben<br />

beschriebenen.<br />

• Setzen der Eigenschaften für STRA-Interrupt: Das Bit STAI in PIOC muss auf 1 gesetzt<br />

werden. Eine Flanke am STRA-Pin führt dann zu einem Auslösen des Interrupts und Setzen<br />

des STAF-Bits in PIOC.<br />

• Weiter ist noch eine Interrupt-Service Routine (ISR) nötig, die beim Auftreten des Interrupts<br />

die gewünschten Aktionen vornimmt. Unbedingt notwendig ist darin das Löschen des<br />

STAF-Bits im Register PIOC, denn sonst würden weitere Interrupts nicht erkannt! Löschen<br />

dieses Bits geschieht durch Lesen von PIOC und danach Lesen von PORTCL!<br />

• Die Startadresse dieser ISR muss im zugehörigen Vektor abgelegt werden, damit beim<br />

Interrupt der Programcounter mit dieser Adresse geladen werden kann.<br />

• Zuletzt (als letzte Aktion der Initialisierung) muss der Interrupt ganz allgemein zugelassen<br />

werden. Dies erledigt der CLI-Befehl.<br />

data equ $2000 Datenbereich<br />

prog equ $8000 Programmbereich<br />

stack equ $7FFF Stackbereich<br />

irqv equ $FFF2 Adresse IRQ-Vektor<br />

resetv equ $FFFE Adresse Reset-Vektor<br />

pioc equ $1002 Adressen Port C<br />

portcl equ $1005<br />

pcdd equ $1007<br />

pcdr equ $1003<br />

org data<br />

tflag ds.b 1<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack Init Stack<br />

clr tflag Init Flag<br />

ldab #$FF Port C auf Ausgang<br />

stab pcdd<br />

ldab #$40 Init Interrupt<br />

stab pioc STRA enable<br />

cli Interrupt freigeben<br />

loop ldab tflag Ausgabeschleife<br />

stab pcdr<br />

bra loop<br />

sirq ldaa pioc Interrupt Service Routine<br />

ldaa portcl<br />

com tflag toggle 0 - FF 0 - FF - ...<br />

rti<br />

org irqv Interrupt-Vektor setzen<br />

dc.w sirq<br />

org resetv Reset-Vektor setzen<br />

dc.w main<br />

Auslösen einer Unterbrechung 133


Beispiel 3: Timer-Unterbrechung<br />

Ein Binärzähler soll mit einer Frequenz von ca. 10 Hz betrieben werden. Seine aktuelle<br />

Stellung ist an Port C auszugeben. Als Taktquelle ist die bei Timerüberlauf auftretende<br />

Unterbrechung (Timer Overflow Interrupt) des freilaufenden 16-Bit-Zählers des 68HC11 zu<br />

verwenden. Da der Interrupt alle 32,77 ms auftritt, muss noch ein zusätzlicher<br />

Modulo-3-Zähler verwendet werden, um auf annähernd 100 ms zu kommen (genauer: 3 *<br />

32,77 ms = 98,31 ms).<br />

data equ $2000 Datenbereich<br />

prog equ $8000 Programmbereich<br />

stack equ $7FFF Stackbereich<br />

tirqv equ $FFDE Adresse TOF-Vektor<br />

resetv equ $FFFE Adresse Reset-Vektor<br />

padr equ $1000 Adresse Port A<br />

pcdd equ $1007 Adressen Port C<br />

pcdr equ $1003<br />

pacr equ $1026 Pulse Akku Control<br />

tflag equ $1025 Timer Flag<br />

tmask equ $1024 Timer Mask<br />

org data<br />

count ds.b 1 Zaehler<br />

cflag ds.b 1 Clock Flag<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack Init Stack<br />

clr count Init Flag<br />

ldab #$FF Port C auf Ausgang<br />

stab pcdd<br />

ldab #$80 Init Interrupt<br />

stab tmask TOF-Interrupt enable<br />

ldab #$40<br />

stab pacr<br />

cli Interrupt freigeben<br />

loop ldab cflag Ausgabeschleife<br />

cmpb #3 Trigger-Zeitpunkt?<br />

bne loop Nein<br />

clr cflag Gotcha!<br />

inc count Zaehler erhoehen<br />

ldab count ...und ausgeben<br />

stab pcdr<br />

bra loop<br />

tirq ldaa #$80 Interrupt Service Routine<br />

staa tflg<br />

inc cflag<br />

rti<br />

org tirqv Interrupt-Vektor setzen<br />

dc.w tirq<br />

org resetv Reset-Vektor setzen<br />

dc.w main<br />

Bei der Einstellung der Parameter für den Timer werden ebenso wie beim PA7-Interrupt die<br />

Register TMASK und TFLAG verwendet. Werden beide Interrupts kombiniert, muss man<br />

darauf achten, die entsprechenden Bits für beide gemeinsam zu setzen. Das folgende<br />

Programm zeigt die Kombination aller drei Interrupts: Der Timer steuert einen Zähler, der auf<br />

Auslösen einer Unterbrechung 134


Port B ausgegeben wird. Der STRA-Interrupt wechselt zwischen Auf- und Abwärtszähler und<br />

der PA7-Interrupt startet oder stoppt den Zähler.<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

pvec equ $FFDA ; vector pa7<br />

tvec equ $FFDE ; vector timer<br />

svec equ $FFF2 ; sirq vector<br />

rvec equ $FFFE ; reset vector<br />

pioc equ $1002 ; parallel i/o control<br />

pbdr equ $1004 ; port b data<br />

pcdl equ $1005 ; port c data latch<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

baud equ $102B ; SCI-baudrate<br />

sccr1 equ $102C ; SCI-control1<br />

sccr2 equ $102D ; SCI-control2<br />

scsr equ $102E ; SCI-status<br />

scdr equ $102F ; SCI-data<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

coun ds.b 1 ; counter<br />

cflg ds.b 1 ; clock flag<br />

updn ds.b 1 ; direction flag<br />

stop ds.b 1 ; stop flag<br />

***************************<br />

* program area *<br />

***************************<br />

org prog<br />

main lds #stak ; load stackpointer<br />

bsr init ; data init<br />

cli ; enable irq<br />

loop ldaa cflg ; get clock flag<br />

cmpa #20 ; trigger point?<br />

bne loop ; no, wait<br />

clr cflg ; yes, clear clock flag<br />

tst stop ; stop active?<br />

bne loop ; yes, wait<br />

bsr count ; update counter<br />

bra loop ; close main loop<br />

***************************<br />

* subroutines *<br />

***************************<br />

Mikrocomputertechnik<br />

count ldaa coun ; load counter<br />

adda updn ; inc/dec counter<br />

staa coun ; save counter<br />

staa pbdr ; display counter<br />

rts<br />

init clr coun ; counter default<br />

Auslösen einer Unterbrechung 135


clr cflg ; no clock seen<br />

clr stop<br />

ldaa #1<br />

staa updn ; default count up<br />

ldab #$40 ; enable STRA interrupt<br />

stab pioc<br />

ldab #$40 ; enable PA7 interrupt<br />

stab pacr ; enable pulse accu<br />

ldab #$90 ; $80 (Timer) + $10 (PA7)<br />

stab tmsk<br />

rts<br />

***************************<br />

* interrupt handler *<br />

***************************<br />

tirq ldaa #$80<br />

staa tflg ; clear interrupt<br />

inc cflg ; count interrupts<br />

rti<br />

sirq ldaa pioc<br />

ldaa pcdl ; clear interrupt<br />

neg updn ; toggle direction<br />

rti<br />

pirq ldaa #$10<br />

staa tflg ; clear interrupt<br />

com stop ; toggle stop flag<br />

rti<br />

***************************<br />

* vectors *<br />

***************************<br />

org pvec<br />

fdb pirq ; PA7 interrupt<br />

org tvec<br />

fdb tirq ; DE timer overflow<br />

org svec<br />

fdb sirq ; STRA<br />

org rvec<br />

fdb main ; FE reset<br />

end<br />

Beispiel 4: XIRQ und STOP<br />

Der nichtmaskierbare Interrupt XIRQ muss beim Programmstart einmal freigegeben werden<br />

und läßt sich dann nicht mehr zurücksetzen. Das folgende Beispiel hat die kürzeste aller<br />

möglichen Interrupt-Serviceroutinen für den XIRQ, nämlich nur ein "rti". Natürlich kann man<br />

hier auch beliebigen Code unterbringen. Insofern bietet der XIRQ eigentlich nichts Neues.<br />

Zusammen mit dem STOP-Befehl wird es aber interessant. Zur Erinnerung: Der STOP-Befehl<br />

stoppt den Takt und schaltet die CPU in den Standbymodus. Ein Aufwecken ist nur per XIRQ<br />

oder IRQ möglich. Im folgenden Programm steht der STOP-Befehl in der Zählschleife, so<br />

dass bei jedem XIRQ um 1 weitergezählt wird und dann die CPU wieder schlafen geht.<br />

data equ $2000 ; data area<br />

Mikrocomputertechnik<br />

Auslösen einer Unterbrechung 136


stak equ $7FFF ; stack area<br />

prog equ $8000 ; program area<br />

xvec equ $FFF4 ; xirq vector<br />

rvec equ $FFFE ; reset vector<br />

portb equ $1004 ; port b data<br />

portc equ $1003 ; port c data<br />

pcdd equ $1007 ; port c data direction<br />

org data<br />

coun ds.b 1 ; counter<br />

org prog<br />

main lds #stak ; load stackpointer<br />

clr coun<br />

tpa ; enable xirq, stop<br />

anda #%00111111<br />

tap<br />

loop stop ; go to sleep<br />

inc coun ; count up<br />

ldab coun<br />

stab portb ; display<br />

bra loop<br />

; xirq isr<br />

xirq rti<br />

org xvec<br />

fdb xirq<br />

org rvec<br />

fdb main<br />

end<br />

Zum vorhergehenden<br />

Abschnitt Zum Inhaltsverzeichnis<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 06. Mai 2012<br />

Mikrocomputertechnik<br />

Zum nächsten<br />

Abschnitt<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Auslösen einer Unterbrechung 137


6 Ausblick: andere Controller<br />

6.1 Atmel-Mikrocontroller<br />

Die Atmel AVR ist eine 8-Bit-Mikrocontroller-Familie des US-amerikanischen Herstellers Atmel. Die<br />

Controller dieser Familie sind wegen ihres einfachen Aufbaus und ihrer leichten Programmierbarkeit<br />

auch bei Hobby-Anwendern weit verbreitet. Die Typen unterteilen sich in die Gruppen<br />

• ATmega: "große" AVR-Controller mit bis zu 256 KB Flash-Speicher in 28- bis 100-poligen<br />

Gehäusen und mit integriertem Hardware-Multiplizierer.<br />

• ATtiny: kleinere AVR-Controller mit bis zu 16 KB Flash-Speicher in 6- bis 20-poligen<br />

Gehäusen.<br />

• AT90USB: ATmega mit integriertem USB-Controller<br />

• AT90CAN: ATmega mit CAN-Controller<br />

• Sondertypen: einige Spezialmodelle, z. B. zur Ansteuerung von Akku-Ladegeräten, Displays<br />

und für Steuerungen<br />

• AT90S: veraltete Typen, die "klassischen" AVRs<br />

Beispiel: Blockschaltung des ATTtiny<br />

6 Ausblick: andere Controller 138


Mikrocomputertechnik<br />

Die Atmel-Prozessoren besitzen eine RISC-Architektur und zeichen sich unter anderem durch eine<br />

relativ große Zahl von Universalregistern aus. Normalerweise wir ein Befehl in einem Taktzyklus<br />

ausgeführt. Je nach Typ besitzen sie<br />

• 32 größtenteils gleichwertige Register, davon lassen sich drei als Pointerregister<br />

(Indexregister) verwenden<br />

• ca. 70 bis 110 Befehle, die meist nur ein bis zwei Taktzyklen dauern<br />

• Taktfrequenz bis 20 MHz (intern erzeugt, extern oder mit Quarz)<br />

• Betriebsspannung von 1,8 bis 5,5 V<br />

• Speicher: 1 - 256 KByte Flash-ROM als Programmspeicher, 0 - 4 KByte EEPROM, 0 - 8<br />

KByte RAM<br />

• Peripherie: A/D-Wandler, 8- und 16-Bit-Timer mit PWM, SPI, I2C (TWI), UART,<br />

Analog-Komparator, Watchdog, externer SRAM<br />

• JTAG bei den größeren ATmegas, debugWire bei den neueren AVRs<br />

• Konfigurationswort (Wahl der Taktquelle usw.)<br />

Beispiel: Pins des ATtiny<br />

Beispiel: Pins des ATMega8<br />

Um einen AVR-Prozessor zu betreiben ist eigentlich nur die Stromversorgung nötig. Der Chip wird<br />

mit einer stabilen Versorgungsspannung (2,7 bis 5 Volt, je nach AVR und Taktfrequenz) versorgt und<br />

erhält den üblichen Stützkondensator (100 nF), der möglichst nahe am AVR angebracht wird.<br />

Weiterhin ist ein Pull-Up-Widerstand für den Resetpin nötig (man könnte ihn weglassen, aber dadurch<br />

würde der Reset-Eingang sehr anfällig für Störungen. Bei den AVR Typen mit<br />

Analog-Digital-Wandler muss man die Pins AVCC und AGND anschließen (auch wenn die<br />

Analog-Schnittstelle nicht verwendet wird), da es sonst zu Fehlfunktionen der entsprechenden Ports<br />

kommen kann. AREF und AVCC werden an die Versorgungsspannung geklemmt, AGND an Masse.<br />

Im Normalfall reicht der interne Oszillator für den Betrieb des AVR aus, lediglich wenn man eine<br />

höhere Taktfrequenz als 8 MHz oder eine größere Genauigkeit benötigt, muss ein Quarz<br />

angeschlossen werden. Die maximale Quarzfrequenz hängt auch von der Höhe der<br />

Versorgungsspannung ab.<br />

Beispiel: Blockschaltung des ATTtiny 139


Mikrocomputertechnik<br />

Die Harvard-/RISC-Architektur führt auch zu einer Speicheraufteilung, die sich vom bisher<br />

behandelten 68HC11 unterscheidet. Die ersten 32 Bytes des Speichers werden von den "General<br />

Purpose Working Registers" (GPWR) belegt. Der darauf folgende 64 Byte lange Speicherbereich<br />

enthält die Konfiguration der Peripherie und die "General Purpose Input Output Register"<br />

(GPIO-Register), was den Portadressen beim 68HC11 entspricht. Ab Adresse 0X0060 beginnt dann<br />

der eigentliche Arbeitsspeicher.<br />

Die Programmierung erfolgt in <strong>Assembler</strong> und C. Außerdem gibt es einen Basic-Dalekt (Bascom).<br />

Der <strong>Assembler</strong> kennt bis zu 120 Instruktionen (Rechnen, Sprünge, Bitmanipulation, Datentransfer,<br />

Kontroll-Funktionen).<br />

Die Prozessoren besitzen ein serielles Programmierinterface, wodurch die Programmierung in der<br />

Schaltung möglich ist (ISP, In System Programming). Verwendet werden drei Ports (z. B. PB0, PB1<br />

und PB2) sowie der Reset-Pin. Diese Ports und die zwei Betriebsspannungsanschlüsse wechseln beim<br />

Programmieren automatisch ihre Funktion und Richtung. Bei etlichen Type besteht die Wahl<br />

zwischen zwei Programmiermodi möglich (bei 12V am Reset-Eingang sind besondere Einstellungen<br />

zugänglich).<br />

Beim seriellen Programmieren werden die Programmbits nacheinander, gesteuert durch einen von<br />

außen angelegten Takt am Pin SCK, über den Pin MOSI in ein internes Schiebregister eingeschoben<br />

und von dort in den Flash-Speicher kopiert. Das Beobachten des Programmiervorgangs, ebenso das<br />

Verifizieren bzw. Lesen des Flash-Speichers erfolgt über den Datenausgang MISO. Beim<br />

Programmieren werden also drei Signalleitungen benötigt: der Takt SCK, die Eingabedaten MOSI und<br />

die Ausgabedaten MISO. Wie oben erwähnt, werden für die Programmierung drei Standard-Ports<br />

verwendet. Man kann also das Programmieren in der Anwender-Schaltung durchführen. Allerdings ist<br />

dabei zu beachten, dass die dafür drei benötigten Pins entweder<br />

• nur für diesen Zweck reserviert werden,<br />

• andernfalls die Beschaltung der Pins in Richtung Peripherie über Widerstände von mindestens<br />

1 Kiloohm erfolgt (Bild unten, linke Seite), oder<br />

• die Programmierports über eine Multiplexschaltung nur bei aktivem Reset mit dem<br />

Programmiersignal verbunden werden (Bild unten, rechte Seite).<br />

Die Atmel Controller besitzen zudem einen reservierten Speicherbereich in welchen ein eigener<br />

Bootloader geladen werden kann, der dann automatisch bei einem RESET des Controllers ausgeführt<br />

wird. Der Bootloader kann über die Konfigurationsbits des Controllers (Fusebits) eingestellt werden.<br />

Mit den beiden Fusebits BOOTSZ0 und BOOTSZ1 (für Bootsize) kann die Grösse des<br />

Bootloaderspeichers eingestellt werden und das Fusebit BOOTRST aktivoert die Bootladefunktion.<br />

Dementsprechend ändert sich auch der Startpunkt nach einem Reset. Um den Bootloader (und auch<br />

den Programmspeicher) vor ungewolltem Überschreiben zu schützen, sind vier Bootloader Lockbits<br />

(BLB) vorgesehen, die jeweils einen Speicherbereiche mit einem Schreib-/Leseschutz versehen. Diese<br />

Beispiel: Blockschaltung des ATTtiny 140


Mikrocomputertechnik<br />

Lockbits verhindern aber nicht das Auslesen oder Beschreiben über die ISP-Schnittstelle. Mittels<br />

Bootloader kann der AVR-Prozessor beispielsweise auch Programme über eine serielle Schnittstelle<br />

laden (fast wie beim 68HC11).<br />

Die Bedeutung der einzelnen Pins erschließt sich vollständig nur durch das Studium des Datenbuchs.<br />

An dieser Stelle soll jedoch eine kurze Zusammenfassung versucht werden. Dabei wird nur auf Pins<br />

mit speziellen Eigenschaften eingegangen, normale Ein- und Ausgänge werden nicht erwähnt. VCC,<br />

GND, AVCC und AREF dienen der Spannungsversorgung von Digital- und Analogteil des<br />

Controllers. Das Programmierinterface wird durch die Pins RESET, SS, MOSI, MISO und SCK<br />

gebildet. Diese Pins verbindet man mit dem Computer um ein Programm in den Controller zu laden.<br />

RXD und TXD betreffen die serielle Schnittstelle (USART). Die XTAL-Pins erlauben den Anschluss<br />

eines externen Quarzes oder sonstigen Taktgene-rators. Mit den OC-Pins kann ein<br />

pulsweitenmoduliertes Signal erzeugt werden. So kann man mit einem digitalen Pin analoge Signale<br />

erzeugen, indem ein Siebglied nachgeschaltet wird. Die ADC-Pins stellen die Eingänge des<br />

Analog-Digital-Wandlers dar.<br />

Beispiel ATtiny13, einer der kleinsten AVR-Prozessor<br />

• Zentraleinheit mit 32 Arbeitsregistern zu je 8 Bits, R0..R31, intern ca. 9 MHz Takt<br />

• Speicher: 512 Worte Programmspeicher (Flash), 64 Byte EEPROM, 64 Byte RAM<br />

• ein 8-Bit-Timer/Zähler, der Timer wird vom Taktoszillator über Vorteiler (durch<br />

1/8/64/256/1024) getaktet, im Zählermoduls erfolgt die Taktung durch ansteigende oder<br />

abfallende Signale am T0-Pin.<br />

• max. 6 Ein-/Ausgabe-Pins (I/O-Pins), deren Richtung als Ein- oder Ausgang programmierbar<br />

ist. Bei Eingängen sind Pull-Up-Widerstände zuschaltbar. Auslösung von Interrupts bei<br />

Eingang INT0 (PB1) programmierbar oder bei Pegelwechsel bei allen Pins wählbar, mit<br />

Maskierung der auslösenden Pins. Weiterhin enthält er einen zuschaltbarer Analogvergleich<br />

an den Pins AIN0 und AIN1 (PB0 und PB1) (Interrupt bei Wechsel).<br />

• Vier-Kanal AD-Wandler mit 10 Bit Auflösung. Interne Spannungsreferenz 1,1 V oder<br />

Betriebsspannung als Spannungsreferenz.<br />

Als Programmierbeispiel sollen hier die aus dem 68HC11-Praktikum bekannten Zeitschleifen dienen.<br />

Eine Zeitschleife mit einem 8-Bit-Register sieht in <strong>Assembler</strong> folgendermaßen aus:<br />

.equ c1 = 200 ; Anzahl Schleifendurchlaeufe<br />

ldi R16,c1 ; 1 Takt<br />

Loop: ; Schleifenbeginn<br />

nop ; 1 Takt<br />

nop ; 1 Takt<br />

dec R16 ; 1 Takt<br />

brne Loop ; 2 Takte wenn nicht Null, 1 Takt bei Null<br />

Man sieht auch, dass bei einer RISC-Architektur in der Regel jeder Befehl nur einen Takt lang dauert.<br />

Wenn's länger dauern soll, nimmt man eine Zeitschleife mit einem 16-Bit-Doppelregister:<br />

.equ c1 = 0 ; laengste Dauer 2^16 Durchlaeufe<br />

ldi R25,HIGH(c1) ; R25 laden, 1 Takt<br />

ldi R24,LOW(c1) ; 1 Takt<br />

Loop: ; Schleifenbeginn<br />

nop ; 1 Takt<br />

nop ; 1 Takt<br />

sbiw R24 ; 16-Bit-Dekrement, 2 Takte<br />

brne Loop ; 2 Takte wenn nicht Null, 1 Takt bei Null<br />

Damit sind wir beim beliebten "Hello World" für kleine Controller: Die im Sekundenrhytmus<br />

blinkenden LED an einem Port:<br />

.inc "tn13def.inc" ; Definitionen fuer einen ATtiny13<br />

Beispiel: Blockschaltung des ATTtiny 141


.equ c1 = 60000 ; Bestimmt die Blinkfrequenz<br />

sbi DDRB,0 ; Portbit als Ausgang programmieren<br />

Loop:<br />

sbi PORTB,0 ; Portbit auf high<br />

rcall Delay ; UP-Aufruf<br />

cbi PORTB,0 ; Portbit auf low<br />

rcall Delay ; UP-Aufruf<br />

rjmp Loop<br />

Delay: ; Unterprogramm fuer Warteschleife<br />

ldi R25,HIGH(c1) ; wie oben gezeigt<br />

ldi R24,LOW(c1)<br />

Delay1:<br />

nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

sbiw R24,1<br />

brne Delay1<br />

Von Atmel selbst wird eine komplette Entwicklungsplattform angeboten (<strong>Assembler</strong>, Simulator usw.),<br />

die man von der Atmel-Webseite herunterladen kann. Zusätzlich existiert eine komplette<br />

C-Entwicklungsplattform auf der Basis des GNU-Compilers (Open Source). Näheres dazu liefert der<br />

Link zu "tuxgraphics.org" unten. Des weiteren wird noch ein Compiler für einen Basic-Dialekt<br />

namens BASCOM-AVR angeboten, der aber nicht kostenlos ist.<br />

Für Einsteiger in den Bereich der Mikrocontroller und Elektronik ist besonders das Arduino-Projekt<br />

interessant, das eine günstige Entwicklungsplattform zur Verfügung stellt. Die Hardware-Seite besteht<br />

aus verschiedenen einfachen Controllermodulen, die über USB (Emulation einer seriellen<br />

Schnittstelle) mit dem PC kommunizieren. Die Softwareentwicklung erfolgt in einer integrierten<br />

Open-Source-Entwicklungumgebung, die bereits viele Bibliotheken für die Ansteuerung der Hardware<br />

mitbringt. Außerdem gibt es eine große Community, die dieses System einsetzt und unterstützt.<br />

Literatur<br />

Atmel-Webseite<br />

Günter Schmitt: Mikrocomputertechnik mit Controllern der Atmel-AVR-RISC-Familie, Oldenbourg<br />

Verlag<br />

Claus Kühnel: Programmieren der AVR-RISC-Mikrocontroller mit BASCOM-AVR, Skript Verlag<br />

Kühnel<br />

Weiterführende Links<br />

Mikrocomputertechnik<br />

http://www.atmel.com/products/avr/<br />

http://shop.avr-praxis.de/index.html<br />

http://tuxgraphics.org/electronics/200904/avr-c-programming.shtml<br />

http://imakeprojects.com/Projects/avr-tutorial/<br />

/http://www.avr-projekte.de/<br />

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial<br />

http://www.mcselec.com (Bascom und Demo)<br />

6.2 PIC-Microcontroller von Microchip<br />

Von Microchip werden inzwischen mehr als 400 unterschiedliche Flash-Controller angeboten, die im<br />

Baukastensystem aus einem Prozessorkern, Speicher und einigen Peripheriemodulen<br />

zusammengesetzt sind. Anhand des Prozessorkerns kann man fünf Familien unterscheiden:<br />

Beispiel: Blockschaltung des ATTtiny 142


• Controller mit 12-Bit-Kernel (PIC10Fxxx, PIC1xF50x) - Minmalsysteme,<br />

• Controller mit 14-Bit-Kernel (PIC16Fxxx, PIX12Fxxx), seit vielen Jahren in Verwendung,<br />

haben sich zu den Arbeitspferden entwickelt,<br />

• Controller mit 16-Bit-Kernel (PIC18Fxxx, PIC18FxxJxx, PIC18FxxKxx), räumen mit einigen<br />

Mängeln der 14-Bit-Kernel auf (linear adressierbarer großer Speicher),<br />

• Controller mit 24-Bit-Kernel (PIC24, dsPIC30Fxxx, dsPIC33Fxxxx), haben 16 Bit<br />

Datenworte, einige eignen sich für digitale Signalverarbeitung,<br />

• Controller mit 32-Bit-Kernel (PIC32MXxxx), haben einen MIPS32-Kern und sind<br />

dementsprechend rechenstark, mit den urspünglichen PIC-Microcontrollern haben sie außer<br />

dem Namen nichts mehr gemein.<br />

Die Bit-Angabe hat in diesem Fall ausnahmsweise nichts mit der Datenwortbreite des jeweiligen<br />

Controllers zu tun, sondern mit der Breite der Befehlsworte des PIC. Ein größerer Wert deutet also auf<br />

einen komplexeren Controller mit leistungsfähigerem Befehlssatz hin. Alle Typen der PIC16XX- und<br />

PIC18XX-Familien verfügen über einen sehr kompakten RISC-Befehlssatz, unterschiedlichste<br />

On-Chip Peripherie, verschieden ausgeführte Programm- und Datenspeicher sowie über<br />

Gehäuseausführungsvarianten. Die CPU dieser Mikrocontrollerfamilien zeichnet sich aus durch eine<br />

strikte Trennung von Programm- und Datenspeicher und durch die Möglichkeit, gleichzeitig auf diese<br />

Speicher über getrennte Busse zuzugreifen, (Harvard-Architektur). Die folgende Tabelle soll einen<br />

knappen Überblick aller PICs vermitteln:<br />

12-Bit-Kernel 14-Bit-Kernel 16-Bit-Kernel<br />

Datenwort 8 Bit<br />

Befehlswort 12 Bit<br />

256 ..<br />

Programmspeichergröße 2k<br />

Worte<br />

EEPROM-Größe 0<br />

16 ..<br />

RAM-Größe<br />

134<br />

Byte<br />

Stack-Tiefe 2<br />

Interrupts keine<br />

4 MHz<br />

max. Taktfrequenz .. 20<br />

MHz<br />

verschiedene Befehle ~33<br />

Hardwaremultiplikation nein<br />

klein, billig, leistungsschwach -<br />

geeignet, um alte PIC-Software<br />

(12-Bit-PICs ohne Flash) weiter<br />

zu nutzen.<br />

Mikrocomputertechnik<br />

Datenwort 8 Bit<br />

Befehlswort 14 Bit<br />

1 .. 8k<br />

Programmspeichergröße Worte -<br />

segmentiert<br />

EEPROM-Größe<br />

0 .. 256<br />

Byte<br />

RAM-Größe<br />

64 .. 368<br />

Byte<br />

Stack-Tiefe 8<br />

Interrupts einfach<br />

max. Taktfrequenz<br />

4 MHz .. 20<br />

MHz<br />

verschiedene Befehle ca. 35<br />

Hardwaremultiplikation nein<br />

Eingeführte Standardtypen, für die<br />

viele Anwendungen zur Verfügung<br />

stehen.<br />

Beispiel: Blockschaltung und Pins des PIC16F84<br />

Datenwort 8 Bit<br />

Befehlswort 16 Bit<br />

4k .. 128k<br />

Programmspeichergröße Byte -<br />

linear<br />

0 .. 1024<br />

EEPROM-Größe<br />

Byte<br />

256 ..<br />

RAM-Größe<br />

3936<br />

Byte<br />

Stack-Tiefe 31<br />

Interrupts priorisiert<br />

4 MHz ..<br />

max. Taktfrequenz<br />

40 MHz<br />

verschiedene Befehle ca. 75<br />

Hardwaremultiplikation ja 8 Bit<br />

Optimiert für den Einsatz von<br />

höheren Programmiersprachen.<br />

6.2 PIC-Microcontroller von Microchip 143


Mikrocomputertechnik<br />

Ähnlich wie bei den Atmel-Prozessoren ist auch bei den PICs die Taktung recht einfach. Der<br />

Controller kann seinen Takt von einer externen Quelle erhalten oder mit einem internen Oszillator<br />

erzeugen. Letzterer kann entweder extern beschaltet werden (RC-Glied oder Quarz) oder der Takt<br />

wird komplett intern erzeugt. Dabei bietet nicht jeder PIC-Typ alle Möglichkeiten.<br />

Wie man aus der Tabelle erkennen kann, gibt es für <strong>Assembler</strong>-Programmierer zwei<br />

Herausforderungen:<br />

• Die Stacktiefe und damit die Zahl der verschactelten Unterprogrammaufrufe ist<br />

hardwaremäßig begrenzt.<br />

• Bei etlichen Typen ist der Arbeitsspeicher segmentiert, d.h. in einzelne Speichersegmente<br />

bzw. -seiten unterteilt, was beispielsweise die Größe von Arrays begrenzt.<br />

Als Beispiel für den Aufbau des Prozessors soll hier der Type 16Fxx dienen, dessen Blockschaltung<br />

und Pinbelegung oben abgebildet sind. Die PIC16xx-Mikrocontroller haben einen RISC-Befehlssatz<br />

mit nur 35 Befehlen, so dass die maschinennahe Programmierung in <strong>Assembler</strong>syntax im Vergleich zu<br />

CPUs mit umfangreicheren Befehlssätzen relativ aufwendig ist. Alle Mitglieder der PIC16xx-Familie<br />

verfügen über Power-On Reset und Watchdog Timer. Unterschiede liegen vor allem in der<br />

verschiedenen Ausstattung mit On-Chip Peripheriekomponenten.<br />

Die Mikrocontroller der PIC16F8x-Gruppe und der PIC16C84 sind nur mit einer geringen Anzahl von<br />

On-Chip-Komponenten ausgestattet, die aber für viele typische Mikrocontolleranwendungen völlig<br />

ausreichend ist. Er verfügt über zwei Ports mit insgesamt 13 Pins, die jedoch über eine relativ große<br />

Beispiel: Blockschaltung und Pins des PIC16F84 144


Mikrocomputertechnik<br />

Treiberfähigkeit verfügen, so dass LEDs problemlos direkt angeschlossen werden können. Ein<br />

8-Bit-Timer mit programmierbarem Vorteiler (1:1, 1:2, 1:4 bis 1:256) kann für Zeitgeber bzw.<br />

Zählerfunktionen eingesetzt werden. Auch bei den PIC müssen On-Chip-Funktionen über ein<br />

Konfigurationswort definiert werden, welches beim Programmiervorgang des Zielcontrollers auf eine<br />

spezielle Speicherstelle geschrieben werden muss.<br />

Bei der Programmierung spielt ein dem Akkumulator ähnliches Arbeitsregister W eine wichtige Rolle,<br />

mit dem alle arithmetischen und logischen Operationen durchgeführt werden. Dabei erfolgt die<br />

Verarbeitung der Daten prinzipiell in drei Schritten:<br />

1. Hole ein Byte aus dem RAM in das Arbeitsregister W<br />

2. Führe die gewünschte Operation aus<br />

3. Lege das Ergebnis im RAM ab<br />

Neben einer direkten Datenadressierung im RAM und einer besonderen Adressierung von<br />

Tabellenelementen im Codespeicher gibt es noch eine indirekte Adressierungsart. Dazu wird in das<br />

FSR (File Select Register) die Adresse der entsprechenden RAM-Speicherzelle geschrieben. Über das<br />

IND-Register kann nun auf die RAM-Speicherzelle schreibend oder lesend zugegriffen werden. Der<br />

PIC 16F84 besitzt einen 13 Bit breiten Programmzähler, der einen Programmspeicher von 8k Worten<br />

adressieren könnte. Der Adressbereich 0x0000-0x03FF (1 K Worte) ist physikalisch implementiert.<br />

Der Resetvektor liegt auf der Adresse 0; der Interruptvektor auf der Adresse 4. Der Datenspeicher<br />

unterteilt sich in das RAM (68 x 8 Bit, Adressbereich von 0x0C 0x4F) und im unteren<br />

Speicherbereich (0x00 0x0B) die I/O-Register. Diese Register werden als Special-Function-Register<br />

(SFR) bezeichnet.<br />

Das RAM wird auch als General-Purpose-Register (GPR) bezeichnet. Der Speicher ist in zwei Seiten<br />

(Bank 0 und Bank 1) unterteilt, die durch das Statusregister auswählbar sind. Bank 1 enthält die<br />

gleiche Anzahl von Speicherstellen wie Bank 0, wobei die General-Purpose-Register aus Bank 0<br />

gespiegelt sind, also auf beiden Seiten erreichbar sind. Einige Register sind jedoch nur über eine<br />

Speicherbank zu erreichen. Dazu zählen das OPTION- und das TRIS-Register, die auf Bank 1 als<br />

normale Register zu erreichen sind.<br />

Der 64 x 8 Bit große EEPROM-Bereich hat die Adressen 0x00 0x3F und ist sowohl lesbar als auch<br />

beschreibbar. Es bietet sich an, wenn Daten zu speichern sind, die auch nach dem Abschalten der<br />

Betriebsspannung erhalten bleiben müssen (z.B. Kalibrierdaten). Auf das EEPROM kann nicht direkt<br />

zugegriffen werden, sondern der Zugriff erfolgt über vier spezielle Register: EECON1, EECON2,<br />

EEADR, EEDAT.<br />

Speicherbelegung des PIC16F84 (nach Microchip-Unterlagen)<br />

Beispiel: Blockschaltung und Pins des PIC16F84 145


Wie schon im Atmel-Abschnitt geschildert, verfügen auch die PIC-Prozessoren über die Möglichkeit<br />

der ISP-Programmierung. Dazu liefert Microchip eine passende Programmier-Hardware an. Derzeit<br />

aktuell ist der MPLAB PICkit 3 (weiterhin erhältlich ist der PICkit 2). Er ermöglicht das Debuggen<br />

und die Programmierung der PIC-Mikrocontroller mithilfe des MPLAB Integrated Development<br />

Environment (IDE). Der MPLAB PICkit 3 wird per USB-Schnittstelle am PC angeschlossen und<br />

verwendet zwei Portleitungen und den Reset-Anschluss zur Programmierung.<br />

Literatur<br />

Günter Schmitt: PIC-Mikrocontroller, Oldenbourg Verlag<br />

http://www.microchip.com/<br />

Weiterführende Links<br />

http://www.microchip.com/<br />

http://www.microchipdirect.com/<br />

http://www.olimex.com/<br />

http://www.sprut.de/electronic/pic/<br />

Mikrocomputertechnik<br />

Beispiel: Blockschaltung und Pins des PIC16F84 146


Mikrocomputertechnik<br />

6.3 MSP-430-Microcontroller von Texas Instruments<br />

Dies ist eine relativ neue 16-Bit Mikrocontrollerfamile, die speziell für Lowpower-Anwendungen<br />

entwickelt wurde. Es handelt sich um Controller mit:<br />

• 16-Bit Risc-Controllerkern<br />

• Einfacher Befehlssatz (nur 27 Befehle)<br />

• Takt: 8/16 MHz bei der MSP430F2xxx-Serie bzw. 25MHz bei der MSP430F5xxx-Serie<br />

• 1 KByte bis 256 KByte integrierter Flashspeicher<br />

• 256 Byte bis 16 KByte integriertes RAM<br />

• Peripherieeinheiten je nach Typ, z. B. USART, analoge Spannungskomparatoren,<br />

A/D-Wandler mit 10, 12 oder 16 Bit Auflösung, DA-Wandler, Timer<br />

• internes EEPROM<br />

• USB 2.0 Full Speed Interface<br />

• JTAG-Interface für Programmierung und Debugging<br />

• Betriebsspannung zwischen 1,8 und 3,6 V<br />

• Sehr geringe Stromaufnahme: 0.1 µA im Off-Modus, 0.8 µA im Standby und 250 µA / MIPS<br />

im Normalbetrieb<br />

Blockschema des MSP430<br />

Texas Instruments erweitert die Familie laufend, was auf einen großen Erfolg dieser Controllerlinie<br />

hindeutet. Der MSP430 besitzt eine Von-Neumann-Architektur. Die Größe des adressierbaren<br />

Speichers ist bei den meisten Typen auf 64 KByte limitiert. Je nach Modell können die<br />

Speichergrößen aber auch bis zu 256 KByte Flash und 16 KByte RAM umfassen. Bei allen<br />

Familienmitgliedern sind die untersten 2 KByte für interne Funktionen, z. B. einen Boot-Loader,<br />

reserviert. Seit 2007 wird auch eine Fami-lie mit der so genannten MSP430X-CPU angeboten. Deren<br />

Speichermodell kann bis zu 1 MByte Speicher adressieren (20 Bit Adressbus). Daher sind hier auch<br />

alle Register 20 Bit breit.<br />

Der Hardwaremultiplizierer erlaubt die Multiplikation von 8-Bit- und 16-Bit-Zahlen (mit/ohne<br />

Vorzeichen), wobei als Ergebnis eine bis zu 32 Bit große Zahl entsteht. Der jüngste Typ kann<br />

32-Bit-Operanden multiplizieren (64-Bit-Resultat). Er beherrscht weiterhin Multiplizieren und<br />

Addieren (MAC) wie ein DSP. In den untersten 16 Bytes sind spezielle Register (SFR, Special<br />

6.3 MSP-430-Microcontroller von Texas Instruments 147


Function Register) für die Interrupt- und "Modul"-Steuerung eingeblendet. Die Register der<br />

8-Bit-Peripherie belegen die folgenden Adressen ($010 bis $0FF). Die darauf folgenden 255 Bytes<br />

($100 bis $1FF) sind für 16-Bit-Peripherie reserviert (Speicherzugriff wortweise). Der<br />

Mikrocontroller verfügt über 16 Interrupt-Vektoren, welche zum Teil maskierbar sind. Beim MSP430<br />

sind nur die beiden höchsten Prioritäten nicht maskierbar, somit können nur diese beiden nicht in ihrer<br />

Funktion beeinflusst werden.<br />

Der Takt kann auf drei Arten erzeugt werden, die je nach Bedarf sehr geringen Stromverbrauch<br />

(32,768 kHz in Form eines Uhrenquarz), sehr schnelles Aufwachen nach einem Interrupt (interner<br />

RC-Oszillator) oder hohe Frequenz (bis zu 16 MHz) ermöglichen. Je nach Typ gibt es einem oder<br />

zwei Eingänge für Quarzoszillatoren sowie einen internen RC-Oszillator, dessen Frequenz in weiten<br />

Bereichen eingestellt werden kann. Die MSP430-Serie wurde konsequent für batteriebetriebene<br />

Lowpower-Anwendungen konzipiert. Typische Anwendungen sind Geräte mit Langzeitbatterie, wie<br />

zum Beispiel Energiezähler, Datenlogger oder auch Blutdruckmessgeräte. Die Peripherieeinheiten der<br />

Controller sind recht leistungsfähig und ihre Programmierung relativ einfach. Nachteilig für den<br />

Bastler ist lediglich die Tatsache, dass die Controller nur SMD-Bauformen (SO- oder TQFP-Gehäuse)<br />

erhältlich sind.<br />

Neben Parallel- und Seriellports sind die Mitglieder der MSP430-Familie (je nach Typ) mit<br />

Analogperipherie bestückt. Die Analog-Digital-Wandler haben eine Auflösung von 10, 12, 14 oder 16<br />

Bit, wobei je nach Typ des MSP430 als Wandlungsverfahren suk-zessive Approximation, Rampenoder<br />

Sigma-Delta-Verfahren eingesetzt wird. Die Digital-Analog-Wandler haben eine Auflösung von<br />

8 oder 12 Bit. Als Referenzspan-nung können hier wie bei den Komparatoren und A/D-Wandlern die<br />

internen oder externen Referenzen benutzt werden. Der Ausgangsverstärker kann automatisch<br />

kalib-riert werden, damit die Ausgangsspannung korrekt den digitalen Werten folgt. Der D/A-Wandler<br />

kann mit bis zu 550 kHz getaktet werden.<br />

Der MSP430 besitzt 16 Register, wobei vier von ihnen fest belegt sind. Register 0: Program-Counter,<br />

Register 1: Stack-Pointer, Register 2: Status-Register und Register 3: Constant-Generator. Diese vier<br />

Register haben spezielle Funktionen, sind aber wie alle anderen zwölf Register auch frei benutzbar.<br />

Der MSP430 beherrsch die komplette Palette der Adressierungsarten: Register-Adressierung,<br />

indizierte Adressierung, absolu-te Adressierung sowie indirekte Adressierung mit und ohne<br />

Autoinkrement. Der Befehlssatz beinhaltet 27 Grundbefehle und 24 "emulierte" Befehle, die aus den<br />

Grundbefehlen zusammengesetzt sind. Die Dauer der Befehlsabarbeitung dauert befehlsabhängig<br />

zwischen eins und sechs Taktzyklen. Der Prozessor ist in C und <strong>Assembler</strong> programmierbar. Für die<br />

Softwareentwicklung stehen verschiedene Compiler zur Ver-fügung. Auf der Website von TI gibt es<br />

eine auf 4 KByte begrenzte Version des IAR-C-Compilers (Kickstart-Version), der neben dem<br />

Compiler auch eine vollständige IDE mit Debugger usw. bietet. Seit einiger Zeit stellt TI auch eine<br />

vollständige Entwicklungsumgebung für den MSP430 auf Eclipse-Basis unter dem Namen<br />

"CCEssentials" zur Verfügung. Diese Entwicklungsumgebung enthält einen C-Compiler, der auf 16<br />

KByte begrenzt ist. Außerdem gibt es für die MSP430-Serie auch eine Version des GCC-Compilers<br />

inklusive Debugger für Linux und Windows.<br />

Literatur:<br />

Lutz Bierl: Das große MSP430 Praxisbuch, Franzis-Verlag<br />

Matthias Sturm: Mikrocontrollertechnik am Beispiel der MSP430-Familie, Hanser-Verlag<br />

Chris Nagy: Embedded Systems Design Using the TI MSP430 Series, Nownos<br />

Weiterführende Links<br />

Mikrocontroller-Net<br />

Entwicklungsboard für knapp 5 Euro<br />

University of Colorado<br />

Mikrocomputertechnik<br />

Blockschema des MSP430 148


http://www.olimex.com/<br />

6.4 8051-Microcontroller<br />

Mikrocomputertechnik<br />

Bei der 8051-Familie handelt es sich um 8-Bit-Mikrocontroller der ersten Generation (Anfang der<br />

1980er Jahre) von Intel. Trotzdem werden Prozessoren mit 8051-Kern nach wie vor von<br />

verschiedenen Herstellern produziert. Eigentlich ist der 8051 für heutige Verhältnisse zu langsam und<br />

nicht mehr zeitgemäß. Der große Vorteil der 8051-Familie begründet sich durch die große Auswahl an<br />

Controllern mit sehr unterschiedlicher Hardwareausstattung. So gibt es sie mit SPI-, I2C-, CAN-,<br />

USB-, RS232-, Profibus-, LIN- oder Ethernetschnittstelle, mit Analog-Digital- und<br />

Digital-Analogwandlern, Timern, Capture-and-Compare-Einheiten usw. Softwareseitig sind alle diese<br />

Controller kompatibel mit dem Ur-8051, solange die spezielle Erweiterungen der neueren Typen nicht<br />

verwendet werden. Aufgrund der unterschiedlichen Befehlslängen von einem bis zu drei Byte sowie<br />

den unterschiedlichen Ausführungszeiten für einen Befehl handelt es sich eindeutig um eine<br />

CISC-Architektur. Das folgende Bild zeigt die Blockschaltung des Prozessors und einige<br />

Erweiterungen.<br />

Blockschema des 8051<br />

Aktuellere Vertreter dieser Familie sind z. B. die MicroConverter von Analog Devices, die<br />

AT89-Familie von Atmel, die MSC12-Familie von Texas Instruments oder die DS89C430 von Maxim<br />

(Dallas). Allen Modellen ist gemeinsam:<br />

• 8-Bit Prozessorkern mit einheitlichem Befehlssatz<br />

• mindestens 128 Bytes internes RAM<br />

• externes RAM und ROM<br />

• ein einheitliches Adressierungsmodell für so genannte Special Function Register (SFR)<br />

• Full-Duplex-UART<br />

• 5 Interrupt-Quellen<br />

• 2 Interrupt-Prioritäten<br />

• diverse Timer<br />

Ein Befehlszyklus entspricht in der ursprünglich von Intel entwickelten Struktur einem bis drei<br />

Maschinenzyklen. Ein Maschinenzyklus entspricht 12 Taktzyklen. Heute übliche Varianten des 8051<br />

kommen hingegen meist mit nur zwei Taktzyklen pro Maschinenzyklus aus. Damit ist bei gleicher<br />

6.4 8051-Microcontroller 149


Taktfrequenz eine deutlich höhere Befehlsabarbeitung möglich. Eine Besonderheit dieses Prozessors<br />

ist der Bitprozessor, der eine schnelle und einfache Bitmanipulation erlaubt.<br />

Später wurde sogar eine Version des 8051 mit integriertem EEPROM und BASIC-Interpreter unter<br />

der Typenbezeichnung 8052AH angeboten, die es erlaubte über die serielle Schnittstelle zu<br />

kommunizieren und Programm einzugeben und diese dann im internen EEPROM abzulegen - fast wie<br />

bei den frühen Heimcomputern.<br />

Darüber hinaus gibt es von verschiedenen Firmen erweiterte MCS-51-Mikrocontroller, z. B. die von<br />

Infineon in NMOS-Technik produduzierten Modelle 80515 (8192 Bytes ROM, 256 Bytes RAM, drei<br />

16-Bit-Timer, UART, zwei externe Interruptquellen, PWM, 8-fach-A/D-Wandler) oder 80535<br />

(externes ROM/EEPROM, 256 Bytes RAM, drei 16-Bit-Timer, UART, zwei externe Interruptquellen,<br />

PWM, 8-fach-A/D-Wandler).<br />

Wegen der großen Verbreitung der 8051-Familie gibt es auch eine Vielzahl von synthetisierbaren<br />

MCS-51-Implementierungen. Diese sind als IP-Cores in einer Hard-warebeschreibungssprache wie<br />

beispielsweise VHDL verfügbar. Sie eignen sich für den Einsatz in FPGAs und<br />

anwendungsspezifischen integrierten Schaltungen (ASICs). Typische Anwendungsbeispiele sind<br />

USB-Controller, wie sie in Druckern oder Schnittstellenadaptern eingesetzt werden. In diese sind zur<br />

Steuerung der diversen Protokolle MCS-51-Mikrocontroller integriert.<br />

Literatur:<br />

Mikrocomputer SAB 8051 Befehlsliste. Hrsg. von der Siemens AG<br />

Andreas Roth: Das Microcontroller Kochbuch MCS51, mitp Verlag<br />

J. Walter: Mikrocomputertechnik mit der 8051-Controller-Familie, Springer 2008<br />

Weiterführende Links<br />

Wikipedia<br />

8051 Projects<br />

Paul's 8051 Tools, Projects and Free Code<br />

8051 Befehlsliste<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Blockschema des 8051 150


7 Anhang<br />

7.1 Literatur und Links<br />

Literatur<br />

Arnulf Wallrabe:<br />

Mikrocontrollerpraxis<br />

Einstieg mit dem 68HC11<br />

Hanser Verlag<br />

Dieses Buch beschreibt den Prozessor sehr viel ausführlicher als das Werk von Rose (s. u.) und bringt<br />

auch viele Beispiele. Dafür kommt hier die Beschreibung der einzelnen Befehle zu kurz. Aufgrund des<br />

Inhaltes und des Preises ist es nach meiner Ansicht noch am besten als Begleitung zur Vorlesung<br />

geeignet. Auch hier liegt eine Programmdiskette bei.<br />

Michael Rose:<br />

Mikroprozessor 68HC11<br />

Architektur und Applikation<br />

Hüthig Verlag<br />

Das Buch beschreibt den Befehlssatz recht ausführlich, aber es gibt kaum kleinen Beispiele zu den<br />

Befehlen. Die umfangreicheren Beispiele im letzten Drittel des Buchs beziehen sich auf ein<br />

bestimmtes System. Das Buch ist relativ teuer, da neben einer Programmdiskette auch eine Platine für<br />

den Aufbau des Mustersystems beiliegt.<br />

Ludwig Orgler:<br />

MC68HC11 Microcontroller<br />

Franzis Verlag<br />

Sehr Hardware- und Schaltungsorientierte Anleitung. Auch hier fehlt die Beschreibung der Befehle.<br />

Das Buch ist eher etwas für Praktiker, die schon erste Erfahrungen mit dem Prozessor gesammelt<br />

haben. Auch hier liegt eine Diskette bei.<br />

Rainer Bermbach:<br />

Embedded Controller<br />

Hanser Verlag<br />

Dieses Buch macht mit dem Aufbau von Embedded Controllern auf INTEL-Basis vertraut<br />

(80186-Familie). Eine recht ordentliche Einführung in die <strong>Assembler</strong>-Programmierung. Auf der<br />

CD-ROM zum Buch gibt es eine komplette Entwicklungsumgebung, ein Tutorial und Datenblätter.<br />

Rainer Kelch:<br />

Rechnergrundlagen - Von der Binärlogik zum Schaltwerk<br />

Fachbuchverlag Leipzig<br />

Rainer Kelch:<br />

Rechnergrundlagen - Vom Rechenwerk zum Universalrechner<br />

Fachbuchverlag Leipzig<br />

Beide Bücher fühen von der Digitaltechnik bis hin zum fertigen Prozessor und behandeln dabei auch<br />

Informationtheorie, Zahlendarstellung und binäres Rechnen. In jedem Buch steckt eine CD mit<br />

7 Anhang 151


weiteren Infos und Lernprogrammen.<br />

Ausserdem gibt es noch die englischen Referenz-Handbücher von Motorola, das nur von Motorola<br />

selbst bezogen werden kann:<br />

M68HC11 Reference Manual und M68HC11 Technical Data<br />

Das Reference-Manual ist hier abrufbar:<br />

68HC11 Reference Manual (PDF, 3 MByte) und<br />

68HC11 Reference Manual (PS, 0,9 MByte).<br />

68HC11 Links<br />

• The MIT Handy Board<br />

• Motorola Microcontollers<br />

• HC11 FAQ<br />

• Axiom Manufacturing<br />

• Technological Arts<br />

• Windows-based Simulator (THRSIM11)<br />

• Another Windows-based Simulators<br />

Latest version<br />

• Roger's Embedded Microcontrollers Home Page<br />

• Course Notes: Digital Logic and Computer Systems<br />

• Circuit Cellar, The Computer Applications Journal<br />

• The Magazine of Electronics Technology<br />

Freeware 68HC11 C Compilers<br />

• Small C - Small-C ported to the 68HC11 (includes C source code).<br />

• ICC11 - An older version (v0.50) of the ImageCraft 68HC11 C compiler.<br />

• gcc11 - A version of the GNU compiler for the 68HC11, ported by Coactive Aesthetics.<br />

• Interactive C - Originally developed for the MIT LEGO Robot (6.270) Contest, IC provides a<br />

subset of C in an integrated development environment.<br />

Commercial 68HC11 C Compilers<br />

Mikrocomputertechnik<br />

• ImageCraft - A low-cost but high-quality compiler, which includes an optimizer,<br />

floating-point support, assembler, linker, and librarian. Available in DOS command line<br />

($75), Windows IDE ($130), and Linux command line ($75) versions. The only major missing<br />

features are true 32-bit longs, and support for in-circuit emulators, though they offer the<br />

"NoICE" monitor/debugger for $30.<br />

• Dunfield - This reasonably-priced ($100) compiler includes an assembler, linker, librarian,<br />

library (with ASM source), monitor (with source), and various utilities and sample programs.<br />

It lacks intrinsic support for the "long" and "float" data types, doesn't support typedef's,<br />

enum's or bitfields, and only the first 15 characters of symbol names are significant. The<br />

documentation is decent, but you'll have to print it out yourself -- it's only supplied on disk.<br />

Dunfield also has low-cost compilers available for many other microcontrollers, including a<br />

freeware one for MS-DOS that produces very small and fast executables.<br />

• IAR Systems - It is also a high-end (starting at $1400) compiler, with good industry support.<br />

Documentation is fair -- good in spots, poor in others, with the most pronouced weakness<br />

being poor organization and indexes. ANSI compliance is excellent, as is optimization,<br />

especally with the most recent upgrade (v4.11). The only major omissions are lack of library<br />

source, and no in-line assembly (all ASM code must be in separate files).<br />

Literatur 152


Mikrocomputertechnik<br />

• Cosmic - This is a professional-level compiler (starting at about $1500) with support for most<br />

major emulators and debuggers. Documentation was voluminous, and poorly written, but<br />

adequate. Library source was included; however, the source comments were in French.<br />

Download their Evaluation Kit and try it out.<br />

• Introl - They have both hobbyist ($150) and professional ($2000) HC11 compilers, offering<br />

full ANSI compliance, library source, an assembler, a linker, and a debugger. They also have<br />

similar products for the entire Motorola line (6805, 6808, 6809, 68HC12, 68HC16, and 68300<br />

families). Demos are available for download.<br />

• Avocet - Avocet is a well-respected name in embedded development tools. They have two<br />

families of C compilers. AVCASE is $1595 and includes Avocet C, a macro assembler, a<br />

monitor debugger, and a simulator. They've also taken over the 2500 AD line of products,<br />

which includes a C compiler ($815), assembler ($415), and simulator ($365). Demos are<br />

available for download.<br />

• HI-Tech - A high-end compiler at a mid-range price (~$850), it boasts full ANSI C<br />

compilance, an optimizing compiler, assembler, linker, library with full source, and a<br />

source-level debug monitor.<br />

• Archimedes - A high-end ($1395 to $2995) HC11 compiler for Windows; also versions for<br />

other Motorola processors (HC12, HC16, and 683XX). 30-day money-back guarantee. Demo<br />

can be downloaded from web site.<br />

• Newton Labs - Makers of a commercial version of Interactive C, with prices ranging from $35<br />

to $100, and versions for Windows 95/Windows NT, Macintosh, and various Unix platforms.<br />

The commercial version includes support for more Standard C features, as well as a better<br />

integrated environment, extensive peripheral libraries, and professional documentation.<br />

7.2 Tips zur Programmierung<br />

Der eigentlichen Programmierung (=Codierung) geht eine Entwurfsphase voraus:<br />

• Konzeption des Programms<br />

Vorüberlegungen zum Programm: Aufgaben, Umfang, Wirtschaftlichkeitsbetrachtungen,<br />

Termine, Personal<br />

• Grobentwurf<br />

Lösungswege und Konzepte entwickeln, Aufgabenumfang festlegen, Randbedingungen<br />

prüfen (z.B. SPeicherplatz, Geschwindigkeit)<br />

• Detailentwurf, Modularisierung<br />

Genaue Definition von Programmeigenschaften und Benutzerschnittstelle, Anforderungen<br />

(z.B. Rechengenauigkeit, Fehlerbehandlung, Hardwareabhängigkeit, ....). Festlegen von<br />

Datenstrukturen und des Aufgabenumfangs der einzelnen Module.<br />

• Überprüfung des Entwurfs am Schreibtisch<br />

Möglichst durch jemand anderen den Entwurf überprüfen lassen.<br />

• Dann folgt Codierung und Test der Programmmodule und anschließend:<br />

♦ Integration der Module zum Programm<br />

♦ Test des Gesamtprogramms und Korrektur<br />

♦ Parallel zur Programmierung: Dokumentation und Bedienungshandbuch<br />

Durch Testen von Programmen kann man nur<br />

deren Fehlerhaftigkeit feststellen<br />

- aber niemals deren Korektheit!<br />

68HC11 Links 153


Grundlegende Prinzipien:<br />

Es ist unmöglich, ein Programm Narrensicher<br />

zu machen, weil Narren zu erfindungsreich sind!<br />

• In kleinen überschaubaren Schritten vorgehen. Nicht zuviel zur gleichen Zeit machen.<br />

• Große Projekte in kleine, logisch zusammengehörende Einheiten (Module) zerlegen. Die<br />

Module so autonom wie möglich auslegen und separat testen.<br />

• Ablauf so einfach wie möglich gestalten. Das macht die Programme leichter lesbar und<br />

durchschaubarer.<br />

• Beim Entwurf (und Dokumentation) grafische Möglichkeiten (Flußdiagramme,<br />

Struktogramme, etc.) und Pseudocode nutzen.<br />

• Den ersten Entwurf so klar und einfach wie möglich halten. Optimieren können Sie später<br />

(falls überhaupt nötig).<br />

• Systematisch vorgehen. Checklisten verwenden. Beim Test Grenzfälle beachten.<br />

• Keine Algorithmen verwenden, die man nicht verstanden hat.<br />

• Berücksichtigen Sie Debugging, Test und Wartung schon beim Erstellen des Programms (z.<br />

B. Ausgabeanweisungen und Überwachungsprozeduren, die später auskommentiert werden).<br />

• Fangen Sie mit dem Kodieren erst an, wenn der Entwurf komplett steht.<br />

• Schreiben Sie Programme so, daß Änderungen leicht möglich sind. Vermeiden Sie<br />

Seiteneffekte in Unterprogrammen oder Sprünge aus Unterprogrammen in andere (weil da<br />

zufällig Code steht, der "passt").<br />

• Behalten Sie trotz Modularisierung das Gesamtprogramm im Auge. Testen Sie die Interaktion<br />

zwischen Modulen gleich und nicht erst bei der Gesamtintegration.<br />

• Bei komplexen Daten ist das Design von Datenstrukturen genauso wichtig, wie das<br />

Programmdesign.<br />

• Versuchen Sie nicht, neu entwickelte Hardware und die Software dazu gleichzeitig zu testen.<br />

Programm-Dokumentation<br />

Mikrocomputertechnik<br />

Die Programmdokumentation besteht nicht nur aus dem kommentierten Listing, sondern aus:<br />

• Beschreibung der grundsätzlichen Wirkungsweise des Programms oder des Unterprogramms<br />

(benutzerbezogen)<br />

• Ausführlicher Bedienungsanleitung<br />

♦ Beschreibung sämtlicher Programmfunktionen<br />

♦ Grenzen für Eingabewerte (Wertebereich)<br />

♦ Fehlermeldungen und die Benutzerreaktion auf die Fehler<br />

♦ Beispiel(e) für jede Programmfunktion<br />

♦ Besonderheiten, die beim Einsatz zu beachten sind<br />

• programmiererbezogene Programmbeschreibung<br />

♦ verwendete Algorithmen und deren Implementierung<br />

♦ Hinweise über Seiteneffekte einzelner Unterprogramme<br />

♦ Wartungs-Historie (Dok. von Änderungen/Erweiterungen)<br />

♦ mögliche Fehlersituationen und Reaktion des Programms darauf<br />

♦ alle "trickreichen" Programmsequenzen<br />

♦ Datenstrukturen<br />

• Ablaufpläne (Flußdiagramme, Struktogramme, Datenfluß)<br />

• kommentiertes Programmlisting<br />

• Programmversion und Erstellungs-/Änderungs-Datum auf Listing<br />

7.2 Tips zur Programmierung 154


7.3 ASCII-Tabelle<br />

ASCII Tabelle (sedezimal)<br />

| 00 nul| 01 soh| 02 stx| 03 etx| 04 eot| 05 enq| 06 ack| 07 bel|<br />

| 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si |<br />

| 10 dle| 11 dc1| 12 dc2| 13 dc3| 14 dc4| 15 nak| 16 syn| 17 etb|<br />

| 18 can| 19 em | 1a sub| 1b esc| 1c fs | 1d gs | 1e rs | 1f us |<br />

| 20 sp | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' |<br />

| 28 ( | 29 ) | 2a * | 2b + | 2c , | 2d - | 2e . | 2f / |<br />

| 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 |<br />

| 38 8 | 39 9 | 3a : | 3b ; | 3c < | 3d = | 3e > | 3f ? |<br />

| 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G |<br />

| 48 H | 49 I | 4a J | 4b K | 4c L | 4d M | 4e N | 4f O |<br />

| 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W |<br />

| 58 X | 59 Y | 5a Z | 5b [ | 5c \ | 5d ] | 5e ^ | 5f _ |<br />

| 60 ` | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g |<br />

| 68 h | 69 i | 6a j | 6b k | 6c l | 6d m | 6e n | 6f o |<br />

| 70 p | 71 q | 72 r | 73 s | 74 t | 75 u | 76 v | 77 w |<br />

| 78 x | 79 y | 7a z | 7b { | 7c | | 7d } | 7e ~ | 7f del|<br />

ASCII Tabelle (oktal)<br />

|000 nul|001 soh|002 stx|003 etx|004 eot|005 enq|006 ack|007 bel|<br />

|010 bs |011 ht |012 nl |013 vt |014 np |015 cr |016 so |017 si |<br />

|020 dle|021 dc1|022 dc2|023 dc3|024 dc4|025 nak|026 syn|027 etb|<br />

|030 can|031 em |032 sub|033 esc|034 fs |035 gs |036 rs |037 us |<br />

|040 sp |041 ! |042 " |043 # |044 $ |045 % |046 & |047 ' |<br />

|050 ( |051 ) |052 * |053 + |054 , |055 - |056 . |057 / |<br />

|060 0 |061 1 |062 2 |063 3 |064 4 |065 5 |066 6 |067 7 |<br />

|070 8 |071 9 |072 : |073 ; |074 < |075 = |076 > |077 ? |<br />

|100 @ |101 A |102 B |103 C |104 D |105 E |106 F |107 G |<br />

|110 H |111 I |112 J |113 K |114 L |115 M |116 N |117 O |<br />

|120 P |121 Q |122 R |123 S |124 T |125 U |126 V |127 W |<br />

|130 X |131 Y |132 Z |133 [ |134 \ |135 ] |136 ^ |137 _ |<br />

|140 ` |141 a |142 b |143 c |144 d |145 e |146 f |147 g |<br />

|150 h |151 i |152 j |153 k |154 l |155 m |156 n |157 o |<br />

|160 p |161 q |162 r |163 s |164 t |165 u |166 v |167 w |<br />

|170 x |171 y |172 z |173 { |174 | |175 } |176 ~ |177 del|<br />

7.4 I/O-Register<br />

Mikrocomputertechnik<br />

The following quick-reference table shows all control registers and bits. The addresses are those<br />

resulting from a hardware reset. The registers are generally grouped according to the device they are<br />

associated with. Some registers are input/output registers while other perform only control functions.<br />

Reference appropriate text material before using these registers.<br />

19881019/wj van ganswijk<br />

1000 porta<br />

1001 reserved<br />

1002 pioc<br />

w 1....... staf: strobe a flag, set at active edge of stra pin/inactive<br />

w .1...... stai: hardware interrupt request when STAF=1<br />

w ..1..... cwom: port c open-drain<br />

w ...1.... hnds: handshake/simpel strobe mode<br />

w ....1... oin: output/input handshake select<br />

w .....1.. pls: STRB pulse/level active<br />

w ......1. ega: rising/falling edge select for STRA<br />

w .......1 invb: STRB active high/low<br />

1003 portc<br />

1004 portb<br />

7.3 ASCII-Tabelle 155


Mikrocomputertechnik<br />

1005 portcl<br />

1006 reserved<br />

1007 ddrc: data direction register for port c (1=output)<br />

1008 portd (b0..b5)<br />

rw 1....... mode0 or boot: strb<br />

rw 1....... mode1 or test: r/w<br />

rw .1...... mode0 or boot: stra<br />

rw .1...... mode1 or test: as<br />

rw ..1..... pd5/ss*<br />

rw ...1.... pd4/sck<br />

rw ....1... pd3/mosi<br />

rw .....1.. pd2/miso<br />

rw ......1. pd1/txd<br />

rw .......1 pd0/rxd<br />

1009 ddrd: data direction register for port d (1=output) (b0..b5)<br />

100a porte: port e data register<br />

100b cforc: timer compare force register<br />

w 1....... foc1<br />

w .1...... foc2<br />

w ..1..... foc3<br />

w ...1.... foc4<br />

w ....1... foc5<br />

w 11111111 force compare(s)<br />

w .....xxx reserved<br />

100c oc1m: set bits to enable oc1 to control corresponding pin(s) of port a<br />

w 1....... oc1m7<br />

w .1...... oc1m6<br />

w ..1..... oc1m5<br />

w ...1.... oc1m4<br />

w ....1... oc1m3<br />

w .....xxx reserved<br />

w 11111111 force compare(s)<br />

100d oc1d: if oc1mx is set, data in oc1dx is output to port a bit-x<br />

on successful oc1 compares<br />

w 1....... oc1d7<br />

w .1...... oc1d6<br />

w ..1..... oc1d5<br />

w ...1.... oc1d4<br />

w ....1... oc1d3<br />

w .....xxx reserved<br />

w 11111111 force compare(s)<br />

100e tcnt: timer counter register<br />

1010 tic1: timer input capture register<br />

1012 tic2: timer input capture register<br />

1014 tic3: timer input capture register<br />

1016 toc1: timer output compare register<br />

1018 toc2: timer output compare register<br />

101a toc3: timer output compare register<br />

101c toc4: timer output compare register<br />

101e toc5: timer output compare register<br />

1020 tctl1: timer control register 1<br />

w 1....... om2<br />

w .1...... ol2<br />

w ..1..... om3<br />

w ...1.... ol3<br />

w ....1... om4<br />

w .....1.. ol4<br />

w ......1. om5<br />

w .......1 ol5<br />

for all pairs:<br />

w 00...... timer disconnected from output pin logic<br />

w 01...... ocx output line: toggle<br />

w 10...... ocx output line: 0<br />

w 11...... ocx output line: 1<br />

1021 tctl2: timer control register 2<br />

w xx...... reserved<br />

w ..1..... edg1b<br />

7.4 I/O-Register 156


Mikrocomputertechnik<br />

w ...1.... edg1a<br />

w ....1... edg2b<br />

w .....1.. edg2a<br />

w ......1. edg3b<br />

w .......1 edg3a<br />

for all pairs:<br />

w ..00.... capture: disabled<br />

w ..01.... capture: on rising edge only<br />

w ..10.... capture: on falling edge only<br />

w ..11.... capture: on any edge<br />

1022 tmsk1: main timer interrupt mask reg 1<br />

w 1....... oc1l: output compare 1 interrupt enable<br />

w .1...... oc2l: output compare 2 interrupt enable<br />

w ..1..... oc3l: output compare 3 interrupt enable<br />

w ...1.... oc4l: output compare 4 interrupt enable<br />

w ....1... oc5l: output compare 5 interrupt enable<br />

w .....1.. ic1l: input compare 1 interrupt enable<br />

w ......1. ic2l: input compare 2 interrupt enable<br />

w .......1 ic3l: input compare 3 interrupt enable<br />

1023 tflg1: main timer interrupt flag reg 1<br />

w 1....... oc1f: clear output compare flag 1<br />

w .1...... oc2f: clear output compare flag 2<br />

w ..1..... oc3f: clear output compare flag 3<br />

w ...1.... oc4f: clear output compare flag 4<br />

w ....1... oc5f: clear output compare flag 5<br />

w .....1.. ic1f: clear input capture flag 1<br />

w ......1. ic2f: clear input capture flag 2<br />

w .......1 ic3f: clear input capture flag 3<br />

1024 tmsk2: misc timer interrupt mask reg 2<br />

w 1....... toi: timer overflow interrupt enable<br />

w .1...... rtii: interrupt enable<br />

w ..1..... paovi: pulse accumulator overflow interrupt enable<br />

w ...1.... paii: pulse accumulator input interrupt enable/disable<br />

w ....xx.. reserved<br />

w ......00 pr1,pr0: timer prescale factor 1<br />

w ......01 pr1,pr0: timer prescale factor 4<br />

w ......10 pr1,pr0: timer prescale factor 8<br />

w ......11 pr1,pr0: timer prescale factor 16<br />

1025 tflg2: misc timer interrupt flag reg 2<br />

w 1....... tof: clear timer overflow flag<br />

w .1...... rtif: clear real time (periodic) interrupt flag<br />

w ..1..... paovf: clear pulse accumulator overflow flag<br />

w ...1.... paif: clear paif pulse accumulator input edge flag<br />

w ....xxxx reserved<br />

1026 pactl: pulse accumulator control register<br />

w 1....... ddra7: data direction for port a bit7 is output/input<br />

w .1...... paen: enable/disable pulse accumulator system enable<br />

w ..1..... pamod: pulse acc mode: gated time accumulation/event counter<br />

w ...1.... pedge: pulse acc edge ctrl: rising/falling edges<br />

w ....xx.. reserved<br />

w ......00 rtr1,rtr0: interrupt rate divide by 2^13<br />

w ......01 rtr1,rtr0: interrupt rate divide by 2^14<br />

w ......10 rtr1,rtr0: interrupt rate divide by 2^15<br />

w ......11 rtr1,rtr0: interrupt rate divide by 2^16<br />

1027 pacnt: pulse accumulator count register<br />

1028 spcr: spi control register<br />

w 1....... spie: spi interrupt enable<br />

w .1...... spe: spi system enable<br />

w ..1..... dwom: port d: open-drain/normal<br />

w ...1.... mstr: master/slave mode<br />

w ....1... cpol: clock polarity<br />

w .....1.. cpha: clock phase<br />

w ......00 spr1,spr0: spi e-clock divided by 2<br />

w ......01 spr1,spr0: spi e-clock divided by 4<br />

w ......10 spr1,spr0: spi e-clock divided by 8<br />

w ......11 spr1,spr0: spi e-clock divided by 16<br />

1029 spsr: spi status register<br />

7.4 I/O-Register 157


Mikrocomputertechnik<br />

r 1....... spif: spi interrupt request<br />

r .1...... wcol: write collision status flag<br />

r ...1.... modf: spi mode error interrupt status flag<br />

r ..x.xxxx reserved<br />

102a spdr: spi data register<br />

102b baud: sci baud rate control register<br />

w 1....... tclr: clear baud counter chain (test only)<br />

w .x...... reserved<br />

w ..00.... scp1,scp0: serial prescaler select: divide e-clock by 1<br />

w ..01.... scp1,scp0: serial prescaler select: divide e-clock by 2<br />

w ..10.... scp1,scp0: serial prescaler select: divide e-clock by 4<br />

w ..11.... scp1,scp0: serial prescaler select: divide e-clock by 13<br />

w ....1... rckb: sci baud rate clock test (test only)<br />

w .....000 scr2,scr1,scr0: prescaler output divide by 1<br />

w .....001 scr2,scr1,scr0: prescaler output divide by 2<br />

w .....010 scr2,scr1,scr0: prescaler output divide by 4<br />

w .....011 scr2,scr1,scr0: prescaler output divide by 8<br />

w .....100 scr2,scr1,scr0: prescaler output divide by 16<br />

w .....101 scr2,scr1,scr0: prescaler output divide by 32<br />

w .....110 scr2,scr1,scr0: prescaler output divide by 64<br />

w .....111 scr2,scr1,scr0: prescaler output divide by 128<br />

102c sccr1: sci control register 1<br />

w 1....... r8: receive bit 8<br />

w .1...... t8: transmit bit 8<br />

w ...1.... m: ninth data bit<br />

w ....1... wake: wake up by address mark/idle line (msb/no low)<br />

w ..x..xxx reserved<br />

102d sccr2: sci control register 2<br />

w 1....... tie: transmit interrupt enable<br />

w .1...... tcie: transmit complete interrupt enable<br />

w ..1..... rie: receiver interrupt enable<br />

w ...1.... ilie: enable/disable idle line interrupts<br />

w ....1... te: transmitter enable (toggle to queue idle character)<br />

w .....1.. re: receiver enable on/off<br />

w ......1. rwu: receiver asleep/normal<br />

w .......1 sbk: send break<br />

102e scsr: sci status register<br />

r 1....... tdre: transmit data register empty flag<br />

r .1...... tc: transmit complete flag<br />

r ..1..... rdrf: receive data register full flag<br />

r ...1.... idle: idle line detected flag<br />

r ....1... or: over-run error flag<br />

r .....1.. nf: noise error flag<br />

r ......1. fe: framing error flag<br />

r .......x reserved<br />

102f scdr: sci data register<br />

1030 adctl: a/d control/status register<br />

r 1....... ccf: conversions complete flag (sets after fourth conversion)<br />

rw .x...... reserved<br />

w ..1..... scan: convert continuously/4 conversions and stop<br />

w ...1.... mult: convert four channel group/single channel<br />

rw ....0000 cd,cc,cb,ca: ad0 port e bit0<br />

rw ....0001 cd,cc,cb,ca: ad1 port e bit1<br />

rw ....0010 cd,cc,cb,ca: ad2 port e bit2<br />

rw ....0011 cd,cc,cb,ca: ad3 port e bit3<br />

rw ....0100 cd,cc,cb,ca: ad4 port e bit4<br />

rw ....0101 cd,cc,cb,ca: ad5 port e bit5<br />

rw ....0110 cd,cc,cb,ca: ad6 port e bit6<br />

rw ....0111 cd,cc,cb,ca: ad7 port e bit7<br />

rw ....10xx cd,cc,cb,ca: reserved<br />

rw ....1100 cd,cc,cb,ca: Vref hi<br />

rw ....1101 cd,cc,cb,ca: Vref low<br />

rw ....1110 cd,cc,cb,ca: Vref hi/2<br />

rw ....1111 cd,cc,cb,ca: test/reserved<br />

1031 adr1<br />

1032 adr2<br />

1033 adr3<br />

7.4 I/O-Register 158


Mikrocomputertechnik<br />

1034 adr4<br />

1035 reserved<br />

1036 reserved<br />

1037 reserved<br />

1038 reserved<br />

1039 option: system configuration options<br />

w 1....... adpu: a->d system powered up/down<br />

w .1...... csel: a->d and ee use an internal-r-c/system-e clock<br />

w ..1..... irqe: irq configured for falling edges/low level<br />

w ...1.... dly: enable/disable oscillator start-up delay (from stop)<br />

w ....1... cme: slow or stopped clocks cause reset/disabled<br />

w .....x.. reserved<br />

w ......00 cr1,cr0: e/2^15 divided by 1<br />

w ......01 cr1,cr0: e/2^15 divided by 4<br />

w ......10 cr1,cr0: e/2^15 divided by 16<br />

w ......11 cr1,cr0: e/2^15 divided by 64<br />

103a coprst: arm/reset cop timer circuitry,<br />

write $55 and $aa to reset cop watchdog timer<br />

103b pprog: eeprom programming register<br />

w 1....... odd: program odd rows in half of eeprom (test only)<br />

w .1...... even: program even rows in half of eeprom (test only)<br />

w ..x..... reserved<br />

w ...1.... byte: erase only one byte/row or all of eeprom<br />

w ....1... row: erase only one 16 byte row/all 512 bytes of eeprom<br />

w .....1.. erase: erase/normal read of program mode<br />

w ......1. eelat: eeprom busses configured for program or erase/read<br />

w .......1 eepgm: program or erase power switched on/off<br />

to program eeprom:<br />

- set eelat<br />

- write data to desired address<br />

- set eepgm for the required programming time<br />

to erase eeprom:<br />

- select row = 1/0<br />

- select byte = 1/0<br />

- set erase and eelat = 1<br />

- write to an eeprom address to be erased<br />

- set eepgm for the required erase time period<br />

103c hprio: highest priority interrupt and misc.<br />

w 1....... rboot: boot rom enabled/not in map (normal)<br />

w .00..... smod,mda: single chip mode<br />

w .01..... smod,mda: expanded multiplexed mode<br />

w .10..... smod,mda: special bootstrap<br />

w .11..... smod,mda: special test<br />

w ...1.... irv: data from internal reads visible/not<br />

on external bus<br />

reset to in test/boot mode: 1, in normal modes: 0<br />

r ....0000 psel3,2,1,0: timer overflow<br />

r ....0001 psel3,2,1,0: pulse accum. overflow<br />

r ....0010 psel3,2,1,0: puls accum. input edge<br />

r ....0011 psel3,2,1,0: spi serial xfer complete<br />

r ....0100 psel3,2,1,0: sci serial system<br />

r ....0101 psel3,2,1,0: reserved (default to irq)<br />

r ....0110 psel3,2,1,0: irq (ext pin or parallel i/o<br />

r ....0111 psel3,2,1,0: real time interrupt<br />

r ....1000 psel3,2,1,0: timer input capture 1<br />

r ....1001 psel3,2,1,0: timer input capture 2<br />

r ....1010 psel3,2,1,0: timer input capture 3<br />

r ....1011 psel3,2,1,0: timer output compare 1<br />

r ....1100 psel3,2,1,0: timer output compare 2<br />

r ....1101 psel3,2,1,0: timer output compare 3<br />

r ....1110 psel3,2,1,0: timer output compare 4<br />

r ....1111 psel3,2,1,0: timer output compare 5<br />

103d init: ram and i/o mapping register<br />

w xxxx.... ram3,2,1,0: ram block position (x000..x0ff)<br />

w ....xxxx reg3,2,1,0: register block position (x000..x03f)<br />

00000001 at reset<br />

103e test1: factory test register<br />

7.4 I/O-Register 159


w 1....... tilop: test illegal opcode<br />

w .x...... reserved<br />

w ..1..... occr: output condition code register status to timer port<br />

w ...1.... cbyp: timer divider chain bypass<br />

w ....1... disr: disable resets from cop and clock monitor<br />

w .....1.. fcm: force clock monitor failure<br />

w ......1. fcop: force cop watchdog failure<br />

w .......1 tcon: test configuration<br />

103f config: configuration control register<br />

w ....1... nosec: dis/enable security mode<br />

(security only if mask option)<br />

w .....1.. nocop: dis/enable cop system<br />

w ......1. romon: en/disable rom at $e000..$ffff<br />

w .......1 eeon: en/disable eeprom at $b600..$b7ff<br />

note: The bits of this register are implemented with eeprom cells.<br />

programming and erasure follow normal eeprom procedures.<br />

The erased state of this location is $0f. A new value<br />

programmed into this register is not readable until after a<br />

subsequent reset sequence.<br />

7.5 Interrupt-Adressen<br />

SCIINT EQU $FFD6 ; SCI serial system<br />

SPIINT EQU $FFD8 ; SPI serial system<br />

PAIINT EQU $FFDA ; Pulse Accumulator Input Edge<br />

PAOVINT EQU $FFDC ; Pulse Accumulator Overflow<br />

TOINT EQU $FFDE ; Timer Overflow<br />

TOC5INT EQU $FFE0 ; Timer Output Compare 5<br />

TOC4INT EQU $FFE2 ; Timer Output Compare 4<br />

TOC3INT EQU $FFE4 ; Timer Output Compare 3<br />

TOC2INT EQU $FFE6 ; Timer Output Compare 2<br />

TOC1INT EQU $FFE8 ; Timer Output Compare 1<br />

TIC3INT EQU $FFEA ; Timer Input Capture 3<br />

TIC2INT EQU $FFEC ; Timer Input Capture 2<br />

TIC1INT EQU $FFEE ; Timer Input Capture 1<br />

RTIINT EQU $FFF0 ; Real Time Interrupt<br />

IRQINT EQU $FFF2 ; IRQ External Interrupt<br />

XIRQINT EQU $FFF4 ; XIRQ External Interrupt<br />

SWIINT EQU $FFF6 ; Software Interrupt<br />

BADOPINT EQU $FFF8 ; Illegal Opcode Trap Interrupt<br />

NOCOPINT EQU $FFFA ; COP Failure (Reset)<br />

CMEINT EQU $FFFC ; COP Clock Monitor Fail (Reset)<br />

RESETINT EQU $FFFE ; RESET Interrupt<br />

7.6 Das Motorola-S-Format<br />

Mikrocomputertechnik<br />

Eine Datei im Motorola-S-Format ist eine Textdatei mit beliebig vielen Zeilen, die Sedezimalziffern in<br />

ASCII-Darstellung enthalten. Die Zeilen werden mit CR, LF abgeschlossen. Diese Datei enthält<br />

Binärcode in ASCII-Form.<br />

Die Datei kann (muß aber nicht) mit einer Einleitungszeile beginnen, dem Sign-On-Record. Man<br />

erkennt ihn am einleitenden S0 (Ziffer Null). Er enthält einen Kommentar, z. B. den Programmnamen<br />

(im Beispiel unten "DATA I/O"). S-Records enthalten pro Zeile eine Adresse, an der die Daten<br />

abgelegt werden sollen.<br />

Jede Datenzeile beginnt mit zwei Startzeichen "S" und einer Ziffer. Die nächsten beiden Zeichen<br />

geben die hexadezimale Anzahl der Datenbytes in der Zeile an, wobei auch die Adreßangabe (2 Bytes)<br />

und die Prüfsumme mitgezählt werden (also Zahl der "echten" Datenbytes + 3). Darauf folgen vier<br />

Zeichen, welche die hexadezimale Adresse des ersten Bytes des Datenrecords angeben. Nun folgen<br />

7.5 Interrupt-Adressen 160


die Datenbytes zweistellig hexadezimal. Leerzeichen werden überlesen. Zum Schluß folgt ein Byte<br />

Prüfsumme (zweistell. Hex.). Die Prüfsumme ist das Einerkomplement aus der Summe von<br />

Längenangabe, Adresse und Datenbytes. Der Typ des Records wird durch eine Ziffer bezeichnet:<br />

• 0: Startrecord (siehe oben)<br />

• 1,2,3: Datenrecord<br />

• 7,8,9: Enderecord<br />

Der Typ sorgt für die Unterscheidung der Adreßlänge:<br />

• Bei Typ 0 is die Adresse immer $0000 und 16-Bit (4 Ziffern) lang<br />

• Bei Typ 1 oder 9 is die Adresse 16-Bit (4 Ziffern) lang<br />

• Bei Typ 2 oder 8 is die Adresse 24-Bit (6 Ziffern) lang<br />

• Bei Typ 3 oder 7 is die Adresse 32-Bit (8 Ziffern) lang<br />

Die letzte Zeile der Datei beginnt mit den Startzeichen "S" und der Ziffer 9, 8 oder 7. Er bildet den<br />

End-Of-File-Record. Ein Enderecord enthält keine Daten, aber die Adresse in diesem Record stellt die<br />

Startadresse des Programms dar.<br />

Beispiel:<br />

S0 0B 0000 44 41 54 41 20 49 2F 4F F4 <br />

S1 13 0000 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FC <br />

S1 13 0010 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF EC <br />

S1 13 0020 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF DC <br />

S1 13 0030 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF CC <br />

S1 13 0040 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF BC <br />

S9 03 0000 FC ¦<br />

¦ ¦ ¦ ¦ ¦<br />

¦ ¦ ¦ Datenbytes Prüfsumme<br />

¦ ¦ Adresse<br />

¦ Längenangabe (Datenbytes + 3)<br />

Record-Markierung<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

7.6 Das Motorola-S-Format 161


Programmbeispiel-Sammlung<br />

Den folgenden "Programmschnipseln" fehlt noch das "Drumrum"<br />

(Definitionen von Variablen, Hauptprogramm, usw.). Sie dienen der<br />

Illustration verschiedener Programmiertechniken in <strong>Assembler</strong>.<br />

Allgemeiner Vorspann für's Praktikum<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

rvec equ $FFFE ; reset vector<br />

pioc equ $1002 ; parallel i/o control<br />

portb equ $1004 ; port b data<br />

portcl equ $1005 ; port c data latch<br />

portc equ $1003 ; port c data reg.<br />

ddrc equ $1007 ; portc data dir. reg.<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

baud equ $102B ; SCI-baudrate<br />

sccr1 equ $102C ; SCI-control1<br />

sccr2 equ $102D ; SCI-control2<br />

scsr equ $102E ; SCI-status<br />

scdr equ $102F ; SCI-data<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

***************************<br />

* program area *<br />

***************************<br />

org prog<br />

main lds #stak ; load stackpointer<br />

***************************<br />

* Nachspann: Vektoren *<br />

***************************<br />

org reset<br />

fdb main<br />

end<br />

Speicherbereich Kopieren<br />

* Parameter: A Länge (Anzahl Bytes), X Quelle, Y Ziel<br />

move pshb<br />

mov1 ldab 0,x ; hole Quellbyte<br />

stab 0,y ; speichern im Zielbereich<br />

inx ; Adressen erhöhen<br />

iny<br />

deca ; runterzählen bis 0<br />

bne mov1<br />

pulb<br />

rts<br />

Programmbeispiel-Sammlung 162


Die größere von zwei Zahlen finden<br />

Vergleichen ($40) und ($41), Ergebnis in $42<br />

LDAA $40 ; 1. Zahl holen<br />

CMPA $41 ; 2. Zahl größer?<br />

BHS WEITER ; 1. Zahl ist größer<br />

LDAA $41 ; 2. Zahl laden<br />

WEITER STAA $42 ; Abspeichern<br />

16-Bit-Addition (Prüfsumme)<br />

Addition eines Feldes von 8-Bit-Werten. Die Anzahl der Werte steht in Speicherbyte $42, die zu<br />

addierenden Werte folgen ab Adresse $43. Das 16-Bit-Ergebnis wird in $40 (MSB) und $41 (LSB)<br />

abgelegt.<br />

CHECKSUM CLRA ; Summe in A und B, Register<br />

CLRB ; zuerst mal löschen<br />

LDX #$0043 ; Adresse erster Summand (Feldanfang)<br />

CSUM ADDB ,X ; Feldelement addieren<br />

ADCA #0 ; Übertrag im MSB aufaddieren<br />

INX ; X inkrementieren<br />

DEC $42 ; Elementezähler vermindern<br />

BNE CSUM ; Wiederholen, solange Zähler > 0 ist<br />

STD $40 ; Checksumme speichern<br />

RTS<br />

Quadrate von 0 - 15 über Tabelle ermitteln<br />

Wert in $41, Ergebnis in $42<br />

LDAB $41 ; Operanden holen<br />

LDX #TABELLE ; X-Register auf Tabellenanfang<br />

ABX ; X und B addieren<br />

LDAA 0,X ; B-ten Eintrag aus Tabelle holen<br />

STAA $42 ; und abspeichern<br />

TABELLE DC.B 0,1,4,9,16,25,36,49,64,81,100<br />

DC.B 121,144,169,196,225<br />

Addieren von 24-Bit-Zahlen<br />

org data<br />

eins dc.b 04,82,40 ; 1. Summand<br />

zwei dc.b 02,37,98 ; 2. Summand<br />

drei dc.b $00,$00,$00 ; Ergebnis<br />

org prog<br />

.<br />

.<br />

.<br />

ldaa eins+2<br />

adda zwei+2<br />

staa drei+2<br />

ldaa eins+1<br />

adca zwei+1<br />

staa drei+1<br />

ldaa eins+0<br />

adca zwei+0<br />

staa drei+0<br />

.<br />

.<br />

.<br />

Mikrocomputertechnik<br />

Allgemeiner Vorspann für's Praktikum 163


Addition von 8-stelligen BCD-Zahlen<br />

Die 1. Zahl belegt den Speicherbereich $41 - $44 (LSB zuerst)<br />

Die 2. Zahl -"- $51 - $54 -"-<br />

Das Ergebnis wird auf die erste Zahl gespeichert<br />

LDAB #4 ; Zahlen sind 4 Byte lang = 8 Stellen<br />

LDX #$41 ; 1. Operand<br />

LDY #$51 ; 2. Operand<br />

CLRA ; Akku A (und Carry-Flag) löschen<br />

BCDADD LDAA 0,X ; zwei Ziffern des 1.Operanden holen<br />

ADCA 0,Y ; zwei Ziffern des 2.Operanden addieren<br />

INY<br />

DAA ; Dezimalkorrektur für BCD<br />

STAA 0,X ; Ergebnis abspeichern<br />

INX<br />

DECB<br />

BNE BCDADD ; solange, bis alle Stellen bearbeitet<br />

Zählen der negativen Elemente in einem Feld<br />

ANZAHL EQU 20 ; z.B. 20 Feldelemente<br />

FELD DS.B 20 ; Platz für 20 Werte<br />

COUNT DS.B 1 ; 1 Byte Zähler<br />

.<br />

.<br />

.<br />

CLRB ; Zähler für neg. Elemente löschen<br />

LDX #FELD ; X auf Feldanfang<br />

LDAA ANZAHL<br />

STAA COUNT ; Zähler setzen<br />

LOOP LDAA 0,X ; nächstes Feldelement<br />

BPL WEITER ; wenn positiv weiter<br />

INCB ; negative Elemente zählen<br />

WEITER INX<br />

DEC COUNT<br />

BNE LOOP ; bis alle Elemente getestet sind<br />

STAB COUNT ; Ergebnis in COUNT speichern<br />

Ein- und Ausgabe auf Ports<br />

Mikrocomputertechnik<br />

Das folgende Programm liest die unteren 4 Bits von Port C ein und gibt sie auf Port B wieder aus,<br />

gleichzeitig blinken die oberen 4 Bits von Port C.<br />

.<br />

.<br />

.<br />

clr portb ; Portb auf 0 setzen<br />

ldab #%1010 ; Register B setzen<br />

ldaa #%11110000 ; Port C Richtungsregister setzen:<br />

staa ddrc ; Bits 0-3 Eingabe, 4-7 Ausgabe<br />

loop ldaa portc ; Port C lesen<br />

anda #$0F ; untere 4 Bits ausmaskieren<br />

staa portb ; auf Port B ausgeben<br />

stab portc ; Register B ausgeben<br />

eorb #%11110000 ; und Bits 4-7 invertieren<br />

bsr delay ; 0,5 s warten (siehe unten)<br />

jmp loop ; endlosschleife<br />

.<br />

.<br />

.<br />

Allgemeiner Vorspann für's Praktikum 164


Taste an PA7 einlesen<br />

prog equ $8000<br />

data equ $2000<br />

stack equ $7FFF<br />

pioc equ $1002 ; parallel i/o control<br />

portb equ $1004 ; port b data<br />

portc equ $1005 ; port c data latch<br />

portcl equ $1005 ; port c data latch<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

baud equ $102B ; SCI-baudrate<br />

sccr1 equ $102C ; SCI-control1<br />

sccr2 equ $102D ; SCI-control2<br />

scsr equ $102E ; SCI-status<br />

scdr equ $102F ; SCI-data<br />

reset equ $fffe<br />

org data<br />

key ds.b 1<br />

org prog<br />

main lds #stack ; load stackpointer<br />

clr key<br />

ldaa #%01010000 ; pa7 freigabe pos. flanke<br />

staa pacr<br />

clra<br />

loop bsr taste<br />

ldaa key<br />

staa portb<br />

bra loop<br />

taste psha<br />

ldaa tflg ; taste gedrueckt?<br />

anda #$10<br />

beq tend ; nix gewesen<br />

ldaa #$10<br />

staa tflg ; Anforderung loeschen<br />

com key ; Ereignis melden<br />

tend pula<br />

rts<br />

org reset<br />

fdb main<br />

end<br />

Mikrocomputertechnik<br />

16-Bit Schieberegister, Richtung per PA7-Taste umschaltbar<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

rvec equ $FFFE ; reset vector<br />

pioc equ $1002 ; parallel i/o control<br />

portb equ $1004 ; port b data<br />

portcl equ $1005 ; port c data latch<br />

portc equ $1003 ; port c data reg.<br />

ddrc equ $1007 ; portc data dir. reg.<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pactl equ $1026 ; pulse accu control<br />

baud equ $102B ; SCI-baudrate<br />

Allgemeiner Vorspann für's Praktikum 165


sccr1 equ $102C ; SCI-control1<br />

sccr2 equ $102D ; SCI-control2<br />

scsr equ $102E ; SCI-status<br />

scdr equ $102F ; SCI-data<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

flag ds.b 1<br />

shift ds.b 2<br />

***************************<br />

* program area *<br />

***************************<br />

org prog<br />

main lds #stak ; load stackpointer<br />

clr flag<br />

ldaa #%01010000 ; pa7 Eingang, Freigabe, pos. Flanke<br />

staa pactl<br />

ldaa #$FF ; portc als Ausgabe<br />

staa ddrc<br />

clr shift ; Schieberegister mit 1 laden<br />

ldab #1<br />

stab shift+1<br />

loop bsr taste ; Tastenstatus abfragen<br />

ldaa flag ; flag = 0 - links, flag = ff - rechts<br />

bne rechts<br />

links ldd shift ; nach links schieben<br />

lsld<br />

bne raus ; falls 0, neu laden mit 1 im LSB<br />

ldab #1<br />

bra raus ; zur Ausgabe<br />

rechts ldd shift ; rechts schieben<br />

lsrd<br />

bne raus ; falls 0 mit 1 laden im MSB<br />

ldaa #$80<br />

raus std shift ; akt. Wert speichern<br />

staa portb ; und ausgeben (auf zwei 8-Bit-Ports)<br />

stab portc<br />

bsr delay<br />

bra loop<br />

rts<br />

taste psha ; Akku retten<br />

ldaa tflg ; Taste gedrueckt?<br />

anda #$10<br />

beq tend ; nix gewesen<br />

ldaa tflg<br />

oraa #$10<br />

staa tflg ; Anforderung loeschen<br />

com flag ; Ereignis melden<br />

tend pula ; Akku restore<br />

rts<br />

delay ldy #$ffff<br />

dely1 nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

Mikrocomputertechnik<br />

Allgemeiner Vorspann für's Praktikum 166


nop<br />

nop<br />

dey<br />

bne dely1<br />

rts<br />

***************************<br />

* vectors *<br />

***************************<br />

org rvec<br />

fdb main ; FFFE reset<br />

end<br />

Auf-/Abwärtszähler, Taste an STRA<br />

Der folgende Zähler zählt abhängig von der Variablen "tflag" aufwärts oder abwärts. Die Zählrichtung<br />

wird durch eine Taste am Eingang STRA umgeschaltet.<br />

; Vereinbarungen<br />

prog equ $8000<br />

data equ $2000<br />

stack equ $7FFF<br />

portb equ $1004<br />

portc equ $1003<br />

portcl equ $1005<br />

pioc equ $1002<br />

ddrc equ $1007<br />

reset equ $fffe<br />

.<br />

.<br />

org data ; Datenbereich<br />

tflag ds.b 1<br />

.<br />

.<br />

Mikrocomputertechnik<br />

org prog ; Programmbereich<br />

main lds #stack ; Stackpointer laden<br />

clr portb ; Ports/Variablen init.<br />

ldaa #1 ; tflag = 1<br />

staa tflag<br />

loop bsr count ; Hauptschleife, nur zwei UP-Aufrufe<br />

bsr taste ; Taste abfrage<br />

jmp loop ; auf/ab zaehlen<br />

; Zaehl-Unterprogramm<br />

; tflag wird addiert (tflag kann 1 oder -1 sein)<br />

count adda tflag ; zaehlen<br />

staa portb ; ausgeben<br />

bsr delay ; 0,5 s warten (siehe unten)<br />

rts<br />

; Tasten-Abfrage-UP<br />

; bei jedem Tastendruck wird tflag negiert (+1 -1, -1 +1)<br />

taste psha ; Akku A retten<br />

ldaa pioc ; Taste gedrueckt<br />

bpl njet ; nein fertig<br />

ldaa portcl ; dummy-read zum Ruecksetzend es Tastenbits in pioc<br />

neg tflag ; tflag negieren<br />

njet pula ; Akku A restaurieren<br />

rts<br />

.<br />

.<br />

.<br />

Allgemeiner Vorspann für's Praktikum 167


Alternativlösung mit bedingter Verzweigung<br />

loop bsr delay<br />

tst updn<br />

bne decr<br />

inc count<br />

ldaa count<br />

cmpa #$FF<br />

bne endf<br />

com updn<br />

bra endf<br />

decr dec count<br />

ldaa count<br />

tsta<br />

bne endf<br />

com updn<br />

endf ldaa count<br />

staa portb<br />

jmp loop<br />

BCD-Zähler mit Rücksetzen per STRA<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

rvec equ $FFFE ; reset vector<br />

pioc equ $1002 ; parallel i/o control<br />

portb equ $1004 ; port b data<br />

portcl equ $1005 ; port c data latch<br />

portc equ $1003 ; port c data reg.<br />

ddrc equ $1007 ; portc data dir. reg.<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

baud equ $102B ; SCI-baudrate<br />

sccr1 equ $102C ; SCI-control1<br />

sccr2 equ $102D ; SCI-control2<br />

scsr equ $102E ; SCI-status<br />

scdr equ $102F ; SCI-data<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

flag ds.b 1<br />

***************************<br />

* program area *<br />

***************************<br />

org prog<br />

main lds #stak ; load stackpointer<br />

clra<br />

clr flag<br />

bsr init<br />

schl adda #1 ; BCD hochzaehlen<br />

daa<br />

anda #$0F<br />

bsr taste ; Taste abfragen<br />

psha ; a auf den stack<br />

lsla ; 4 x schieben<br />

Mikrocomputertechnik<br />

Allgemeiner Vorspann für's Praktikum 168


lsla<br />

lsla<br />

lsla<br />

staa portc ; ausgeben<br />

pula ; a restore<br />

ldab flag ; Tastendruck bearbeiten<br />

stab portb ; auf Port B ausgeben<br />

bne weiter ; wenn nicht 0<br />

clra ; Zaehler loeschen<br />

com flag ; flag wieder setzen -> sonst "haengt" es<br />

weiter bsr delay<br />

bra schl<br />

init ldaa #$02 ; hands=0, raising edge 00000010<br />

staa pioc<br />

ldaa #%11110000<br />

staa ddrc<br />

rts<br />

delay ldy #$ffff<br />

dely1 nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

dey<br />

bne dely1<br />

rts<br />

taste psha<br />

ldaa pioc ; taste gedrueckt (Bit 7)?<br />

bpl tend ; nix gewesen<br />

ldaa portcl ; dummy read --> Reset STAF<br />

com flag ; ereignis melden<br />

tend pula<br />

rts<br />

***************************<br />

* vectors *<br />

***************************<br />

org rvec<br />

fdb main ; FE reset<br />

end<br />

Software-Uhr<br />

Eine Software-Uhr wird in der Regel durch einen periodischen Interrupt (z. B. vom Timer) unterstützt.<br />

Bei jedem Interrupt wird ein Zähler incrementiert. Die Zählung erfolgt in Sekunden, Minuten und<br />

Stunden. Das im Vordergrund arbeitende Programm kann auf die Zeitinformation zugreifen.<br />

Die Bedienung des Timer-Interrupts wird hier nur angedeutet (da noch nicht behandelt). Der<br />

CLOCK-Interrupt wird im Beispiel alle 100 ms ausgelöst = 10 Tics/s.<br />

ZEHNTEL DS.B 1 ; 1/10 Sekunden<br />

SEKUNDEN DS.B 1 ; Sekunden<br />

MINUTEN DS.B 1 ; Minuten<br />

STUNDEN DS.B 1 ; Stunden<br />

.<br />

.<br />

.<br />

Mikrocomputertechnik<br />

Allgemeiner Vorspann für's Praktikum 169


CLOCK<br />

* An dieser Stelle muß die<br />

* Timer-Hardware bedient werden<br />

INC ZEHNTEL ; 1/10 Sekunden erhöhen<br />

LDAA #10<br />

CMPA ZEHNTEL ; Sekunde erreicht?<br />

BNE ENDCLOCK ; nein - fertig<br />

CLR ZEHNTEL ; sonst 1/10 Sekunden auf 0 setzen<br />

INC SEKUNDEN ; und Sekunden erhöhen<br />

LDAA #60<br />

CMPA SEKUNDEN ; Minute erreicht?<br />

BNE ENDCLOCK ; nein - fertig<br />

CLR SEKUNDEN ; sonst Sekunden auf 0 setzen<br />

INC MINUTEN ; und Minuten erhöhen<br />

CMPA MINUTEN ; Stunden erreicht?<br />

BNE ENDCLOCK ; nein - fertig<br />

CLR MINUTEN ; sonst Minuten auf 0 setzen<br />

INC STUNDEN ; und Stunden erhöhen<br />

LDAA #24<br />

CMPA STUNDEN ; Tageswechsel?<br />

BNE ENDCLOCK ; nein - fertig<br />

CLR STUNDEN ; sonst Stunden auf 0 setzen<br />

ENDCLOCK RTI ; Rücksprung<br />

Die Dauer der ISR beträgt im schlechtesten Fall weniger als 150 Taktzyklen. Da die ISR nur alle 100<br />

ms ausgelöst wird, ist die zusätzliche Belastung des Systems relativ gering (ca. 0,1%).<br />

Nützliche Unterprogramme<br />

Mikrocomputertechnik<br />

Die folgenden Unterprogramme lassen sich in eigenen Programmen verwenden.<br />

Ergänzen eines ASCII-Codewortes auf gerade Parität<br />

EVENPAR PSHB ; Codewort zwischenspeichern<br />

CLRA ; Zaehler = 0<br />

ZHL LSRB ; naechstes Bit ins Carry holen<br />

ADCA #0 ; Carry zu A ddieren<br />

TSTB ; Restwort = 0?<br />

BNE ZHL ; nein, weiter<br />

PULB ; Codewort holen<br />

ASLB ; links schieben<br />

LSRA ; Parity-Bit ins Carry<br />

RORB ; Parity-Bit ins MSB vom Codewort<br />

RTS<br />

Nützliche Unterprogramme 170


Binärwert (0 - 15) zu ASCII konvertieren<br />

Unterprogramm zur Konvertierung eines Binärwertes (0 - 15) in die ASCII-Darstellung (z.B. für die<br />

Ausgabe am Terminal). Der Wert wird in Register A an das UP übergeben und das entsprechende<br />

ASCII-Zeichen wird vom UP wieder in A zurückgegeben.<br />

Der Abstand zwischen der Ziffer "9" und dem Buchstaben "A" beträgt im ASCII-Zeichensatz 7<br />

Zeichen, weshalb zwischen den Eingangswerten 0 - 9 und 10 - 15 unterschieden werden muss. Bei<br />

Werten größer 10 muss daher 7 addiert werden.<br />

*<br />

* Konvertierung Binär zu ASCII<br />

* Parameter in Akku A<br />

*<br />

BINASC ANDA #0F ; auf Werte zwischen 0 und 15 begrenzen<br />

CMPA #9 ; Wert 0 bis 9 ?<br />

BLS ZIF ; ja, dann direkt umwandeln<br />

ADDA #7 ; "A" - "9" - 1 = $41 - $39 - 1 = 7<br />

ZIF ADDA #$30 ; $30 = "0" (ASCII-Wert)<br />

RTS<br />

ASCII-Zeichen zu Binär konvertieren<br />

Mikrocomputertechnik<br />

Unterprogramm zur Konvertierung eines ASCII-Zeichens (0 - 9, A - F) in einen Binärwert, z.B. bei<br />

der Eingabe von Zahlen über das Terminal. Das Zeichen wird in Akku A übergeben und der Wert<br />

wieder in A zurückgegeben. Das UP arbeitet invers zum obigen UP. Bei Fehleingabe (keine Ziffer)<br />

wird Akku A auf $FF gesetzt.<br />

*<br />

* Unterprogramm ASCII-Binär-Konvertierung (0 - 9, A - F)<br />

* Parameter in A<br />

*<br />

ASCBIN SUBA #$30 ; $30 = ASCII "0"<br />

BLO FEHL ; Erg. negativ keine Ziffer<br />

CMPA #9 ; kleiner oder gleich 9?<br />

BLS DONE ; dann fertig<br />

SUBA #7 ; "A" - "F" 10 - 15<br />

CMPA #10 ; kleiner als 10?<br />

BLO FEHL ; dann Fehler<br />

CMPA #15 ; größer 15?<br />

BLS DONE ; nein, fertig<br />

FEHL LDAA #$FF ; Fehlerflag setzen<br />

DONE RTS<br />

Binär zu ASCII-Decodierung (1, 2 oder 4 Stellen)<br />

Im Speicher liegen die Werte bekanntermaßen binär vor. Um einen Speicherinhalt oder eine Adresse<br />

auf der seriellen Schnittstelle (Terminal) oder einem LC-Display ausgeben zu können, müsen die<br />

Werte als ASCII-Zeichen dargestellt werden.<br />

Die folgenden vier miteinander verbundenen Unterprogramme erweitern das Beispiel oben und<br />

wandeln einen 16-Bit-Wert, einen 8-Bit-Wert (Byte) oder einen 4-Bit-Wert (Nibble) in eine<br />

Hexadezimalzahl in ASCII-Darstellung um (4, 2, oder 1 Stelle):<br />

• hx4a wandelt den Inhalt von Akku D in vier ASCII-Zeichen, die in einem 4 Byte langen<br />

Puffer abgelegt werden. Beim Unterprogrammaufruf muß das Indexregister Y auf die letzte<br />

Stelle des Puffers zeigen.<br />

• hx2a wandelt den Inhalt von Akku B in zwei ASCII-Zeichen, die in einem 2 Byte langen<br />

Puffer abgelegt werden. Beim Unterprogrammaufruf muß das Indexregister Y auf die letzte<br />

Stelle des Puffers zeigen.<br />

Nützliche Unterprogramme 171


Mikrocomputertechnik<br />

• hx1a wandelt den Inhalt von Akku B (Bits 0-3) in ein ASCII-Zeichen, das in einem 1 Byte<br />

langen Puffer abgelegt wird. Beim Unterprogrammaufruf muß das Indexregister Y auf den<br />

Puffers zeigen.<br />

Diese Unterprogramme werden beim vierten Praktikumstermin benötigt.<br />

hx4a psha ; Akku A auf dem Stack ablegen<br />

bsr hx2a ; Akku B umwandeln (Stelle 3 und 4)<br />

pulb ; Akku A vom Stack holen, in Akku B ablegen<br />

; Nun einfach in hx2a fallen und Akku B<br />

; umwandeln (Stelle 1 und 2)<br />

hx2a pshb ; Akku B aud dem Stack sichern<br />

bsr hx1a ; Bits 0-3 von Akku B umwandeln<br />

pulb ; Original-Akku B wieder holen<br />

lsrb ; viermal schieben (Bits 4-7 --> 0-3)<br />

lsrb<br />

lsrb ; und nun die obere Haelfte umwandeln<br />

lsrb ; indem einfach in hx1a gefallen wird<br />

; Nun wird die eigentliche Arbeit gemacht:<br />

hx1a andb #$0F ; die oberen 4 Bita ausmaskieren<br />

addb #48 ; ASCII-Wert von "0" addieren<br />

cmpb #57 ; groesser als "9"?<br />

bls hx1b ; nein, dann speichern<br />

addb #7 ; sonst die Distanz zwischen "9" und "a" addieren<br />

hx1b stab 0,y ; Im Speicher ablegen, auf den Y zeigt<br />

dey ; Y zeigt jetzt auf die Stelle davor<br />

rts ; und weg<br />

Überlesen von Leerzeichen am Anfang einer Zeichenkette<br />

Nach Ausführung zeigt X auf das erste Zeichen != ' '. Der String muß mit einem Zeichen != '<br />

' abgeschlossen sein.<br />

LDX #STRING ; Beginn der Zeichenkette<br />

CHECK LDAA 0,X ; Zeichen lesen<br />

INX ; X erhoehen<br />

CHECK CMPA #$20 ; Leerzeichen?<br />

BEQ CHECK ; Ja, weiter testen<br />

DEX ; nein, Zeiger korrigieren<br />

.<br />

.<br />

.<br />

STRING DC.B ' Zeichenkette mit 4 Leerzeichen am Anfang'<br />

DC.B 0 Abschlußzeichen<br />

Beispiel: Vergleich zweier Zeichenketten (Strings)<br />

Die Adressen der beiden Zeichenketten werden in X und Y übergeben. Als Ergebnis wird Akku A<br />

verwendet - 0: Strings sind ungleich, FF: Strings sind gleich<br />

; Vergleich zweier Strings, Anfangsadressen in X und Y<br />

; Ergebnis wird in Akku A zurueckgegeben (0: ungleich, FF: gleich)<br />

vergl ldaa 0,X ; Zeichen aus String 1 vergleichen<br />

cmpa 0,Y ; mit Zeichen aus String 2<br />

bne ver0 ; Strings ungleich, fertig<br />

cmpa #0 ; Stringende<br />

beq ver1 ; Strings sind gleich, fertig<br />

inx ; naechstes Zeichen<br />

iny<br />

bra vergl<br />

ver1 ldaa #$ff<br />

rts<br />

Nützliche Unterprogramme 172


ver0 clra<br />

rts<br />

Delay-Routine<br />

Das folgende Unterprogramm erlaubt längere Verzögerungszeiten als das in Kapitel 3 vorgestellte, da<br />

hier das 16-Bit-Register X verwendet wird. "delay" dauert 4 + 3 + $f422*16 + 4 + 5 + 5 Taktzyklen,<br />

was einer Wartezeit von 8,5 + $f422*8 µs = 499992,5 µs entspricht - also ungefähr 0,5 s.<br />

delay pshx ; Register x retten, 4 cycl<br />

ldx #$f211 ; Anfangswert laden, 3 cycl<br />

delay1 nop ; 5 x nop = 10 cycl<br />

nop<br />

nop<br />

nop<br />

nop<br />

dex ; X runterzaehlen, 3 cycl<br />

bne delay1 ; 3 cycl<br />

pulx ; Register restaurieren, 5 cycl<br />

rts ; 5 cycl<br />

Delay-Routine - Angabe der Frequenz<br />

Die Frequenz wird in Akku B übergeben (Werte zwischen 1 und 15).<br />

delay clra ; Akku D: Akku A = 0, Akku B = Wert<br />

andb #$0F<br />

beq del_end ; Division durch 0 verhindern<br />

ldx #$FF00 ; Wert fuer 1 Hz --> X<br />

xgdx ; Schalter in X, 1-Hz-Wert in D<br />

idiv ; D/X<br />

delay1 nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

dex<br />

bne delay1<br />

del_end rts<br />

Demo 16-Bit-Tabellenzugriff<br />

Die Variablen sek und zsek werden gemeinsam aus einer Tabelle belegt. Die Auswahl des<br />

Tabellenelementes erfolgt über 4 Schalter an Port C.<br />

org data<br />

sek ds.b 1<br />

zsek ds.b 1<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack ; Initialisierung<br />

clr portb<br />

ldaa #%11110000 ; Bits 0-3 als Eingang<br />

staa ddrc<br />

loop ldab portc ; Schalter einlesen<br />

andb #$0F<br />

lslb ; Akku B * 2, weil 16-Bit-Zugriff<br />

; (jeweils 2 Byte)<br />

ldx #tabelle ; Tabellenzugriff: X zeigt aus Tab.-Anfang<br />

Nützliche Unterprogramme 173


abx ; aktuelle Position: B + X<br />

ldd 0,X ; Wert laden<br />

std sek ; Sekunden in sek, 1/10 in zsek<br />

jmp loop<br />

* 0 1 2 3 4 5 6 7<br />

tabelle dc.b 0,0, 2,5, 4,0, 10,0, 15,5, 20,0, 25,3, 31,4,<br />

* 8 9 10 11 12 13 14 15<br />

dc.b 40,0, 51,2, 60,0, 65,8, 72,4, 80,1, 85,7, 95,3<br />

Zufallszahlen<br />

Bei C gibt es in der Regel eine Random-Funktion, die Pseudo-Zufallszahlen liefert. In <strong>Assembler</strong><br />

muss man, sofern es keine passende Bibliothek gibt, selbst eine entsprechende Funktion<br />

programmieren. Im Folgenden wird eine typische Form der Implementierung verwendet, um<br />

8-Bit-Zufallszahlen zu generieren. Es handelt sich um die 16-Bit-Variante der klassischen Formel S' =<br />

S * M + A. Als Zufallswert wird das Highbyte der 16-Bit-"Seed" des Zufallsgenerators im Akku A<br />

zurückgegeben. Für die Konstanten werden die Werte M = 181 und A = 359 aus folgenden Gründen<br />

gewählt:<br />

• Beide Werte sind Primzahlen.<br />

• Die Gleichung durchläuft mit diesem Werten alls 65 536 möglichen Werte für die "Seed".<br />

• Es gibt keine Wiederholungen von Sequenzen mit 4 oder mehr Werten<br />

• Die Random-Werte sind relativ gleichverteilt<br />

Die Funktion benötigt wenig Speicherplatz und nur 4 Byte RAM. Mit dem Unterprogramm RndInit<br />

wird der Anfangswert der "Seed" auf Null gesetzt. Sie können aber auch jeden beliebigen<br />

Anfangswert verwenden - etwa den Eingangswert eines A/D-Wandler-Ports.<br />

data equ $2000 ; Datenbereich<br />

prog equ $8000 ; Programmbereich<br />

stack equ $7FFF ; Stackbereich<br />

resetv equ $FFFE ; Adresse Reset-Vektor<br />

pcdd equ $1007 ; Adressen Port C<br />

pcdr equ $1003<br />

* Random-Constants:<br />

RndMult equ 181 ; Multiplikationsfaktor<br />

RndAdd equ 359 ; zu addierender Offset<br />

org data<br />

RndSeed ds.b 2 ; 2 Byte Random Seed<br />

RndTmp ds.b 2 ; temporaerer Speicher<br />

org prog<br />

main lds #stack ; Init Stack<br />

ldaa #$FF<br />

staa pcdd ; Port C als output<br />

clr pcdr<br />

bsr RndInit ; Seed = 0<br />

loop bsr Random ; A = random number<br />

staa pcdr ; A -> Port C<br />

bsr Delay ; wait<br />

bra loop<br />

* Initialize the random number generator<br />

RndInit clr RndSeed<br />

clr RndSeed+1<br />

rts<br />

Mikrocomputertechnik<br />

Nützliche Unterprogramme 174


* Return the next 8-bit pseudo random number<br />

* Berechnet SEED = SEED * 181 + 359<br />

* return high byte of the new SEED in A<br />

* Return value: The A register.<br />

Random pshb ; save B<br />

* scratch = seed * RndMult<br />

ldaa #RndMult ; A = #181<br />

ldab RndSeed+1 ; B = low byte of the seed<br />

mul ; D = A x B<br />

std RndTmp ; scratch = D<br />

ldaa #RndMult ; A = #181<br />

ldab RndSeed ; B = high byte of the seed<br />

mul ; D = A x B<br />

* low byte of mult. result is added to the high byte of scratch<br />

addb RndTmp ; B = B + scratch_high<br />

stab RndTmp ; scratch = seed * 181<br />

ldd RndTmp ; D = scratch<br />

addd #RndAdd ; D = D + 359<br />

std RndSeed ; save new seed value<br />

* A holds RndSeed from addition<br />

pulb ; retore B<br />

rts<br />

* Delay wie ueblich ...<br />

Delay LDX #$FFFF<br />

LoopX DEX<br />

BNE LoopX<br />

RTS<br />

org resetv ; Reset-Vektor setzen<br />

dc.w main<br />

Komplette Programmbeispiele<br />

Die folgenden Programme sind vollständig und lassen sich direkt assemblieren, simulieren und im<br />

Zielsystem ausführen.<br />

Ausgabe beliebiger Bitmuster<br />

Mikrocomputertechnik<br />

Es wird ein Array mit Bitmustern angelegt ("muster"), die nacheinander auf Port B ausgegeben<br />

werden. Ein Nullbyte markiert das Ende des Arrays. Wenn dies erreicht ist, beginnt die Ausgabe<br />

wieder beim ersten Element. Das Array ist beliebig erweiterbar.<br />

prog equ $8000 ; Vereinbarungen<br />

data equ $2000<br />

stack equ $7FFF<br />

portb equ $1004<br />

reset equ $fffe<br />

org prog<br />

main lds #stack<br />

ldx #muster ; X verweist auf das erste Feldelement<br />

loop ldaa 0,x ; erstes Feldelement laden<br />

bne ausg ; wenn nicht 0, ausgeben<br />

ldx #muster ; sonst wieder zum ersten Element<br />

bra loop ; ohne Ausgabe<br />

ausg staa portb ; Bitmuster ausgeben<br />

jsr delay ; 0,5 s warten<br />

inx ; naechstes Element<br />

bra loop<br />

delay pshx ; Delay, siehe oben<br />

ldx #$f422<br />

delay1 nop<br />

Komplette Programmbeispiele 175


nop<br />

nop<br />

nop<br />

nop<br />

dex<br />

bne delay1<br />

pulx<br />

rts<br />

muster dc.b %11110000, %01111000, %00111100, %00011110<br />

dc.b %00001111, %00011110, %00111100, %01111000<br />

dc.b %0<br />

org reset ; Reset-Vektor setzen<br />

fdb main<br />

end<br />

Dezimal zu Siebensegment Codierung<br />

Der Inhalt von Akkumulator B soll in die Siebensegmentdarstellung gemäß untenstehender Abbildung<br />

umcodiert werden. Der erzeugte Code wird ebenfalls in Akku B zurückgegeben. Bei Werten größer 9,<br />

soll B mit $FF besetzt werden.<br />

prog equ $8000<br />

data equ $2000<br />

stack equ $7FFF<br />

portb equ $1004<br />

reset equ $fffe<br />

org data<br />

count ds.b 1<br />

Mikrocomputertechnik<br />

org prog<br />

main lds #stack<br />

clr count ; Speicher loeschen<br />

loop ldab count ; Schleifenbeginn, count mod 16 hochzaehlen<br />

incb<br />

andb #$0F<br />

stab count<br />

bsr umco ; Count in Akku B wird umcodiert, Ergebnis in Akku B<br />

stab portb ; und ausgeben<br />

jsr delay ; 0,5 s warten<br />

bra loop<br />

; Umcodierung binaer --> 7-Segment, eingabe und Ausgabe in Akku B<br />

umco ldx #umcotab ; Tabellenadresse laden<br />

andb #$0F ; fuer B nur Werte 0 - F zulassen<br />

abx ; X = X + B<br />

ldab 0,x ; 7-Sement-Wert holen, Adressierung durch X-Register<br />

rts<br />

Komplette Programmbeispiele 176


delay pshx ; Delay, siehe oben<br />

ldx #$f422<br />

delay1 nop<br />

nop<br />

nop<br />

nop<br />

nop<br />

dex<br />

bne delay1<br />

pulx<br />

rts<br />

; Siebensegment-Tabelle (Segmentanordnung: -abcdefg)<br />

; Die Ziffern "0" bis "9" sind decodiert, fuer "A" bis "F"<br />

; wird nur ein "-" angezeigt --> noch zu ergaenzen<br />

umcotab dc.b %01111110, %00110000, %01101101, %01111001<br />

dc.b %00110011, %01011011, %01011111, %01110000<br />

dc.b %01111111, %01111011, %00000001, %00000001<br />

dc.b %00000001, %00000001, %00000001, %00000001<br />

org reset<br />

fdb main<br />

end<br />

Serielle Eingabe mit Backspace und Ignorieren von Zeichen < " "<br />

gets stx pufanf<br />

gets0 bsr recv<br />

cmpb #cr<br />

beq gets1<br />

cmpb #bs<br />

beq gets2<br />

cmpb #' ' ; Zeichen < ' ' ignorieren<br />

blo gets0<br />

bsr send<br />

stab 0,x<br />

inx<br />

bra gets0<br />

gets1 clrb ; Newline - Eingabeende<br />

stab 0,x ; Nullbeit als Abschluss<br />

bsr crlf ; cr + lf ausgeben<br />

rts<br />

gets2 cpx pufanf ; Backspace<br />

beq gets0 ; nur bis Pufferanfanng zurück<br />

dex<br />

ldab #bs ; BS , Leer, BS ausgeben<br />

bsr send<br />

ldab #' '<br />

bsr send<br />

ldab #bs<br />

bsr send<br />

bra gets0<br />

; cr+lf ausgeben<br />

crlf ldab #cr<br />

bsr send<br />

ldab #lf<br />

bsr send<br />

rts<br />

Mikrocomputertechnik<br />

Komplette Programmbeispiele 177


Kommandoeingabe über die serielle Schnittstelle<br />

; Vereinbarungen<br />

prog equ $8000<br />

data equ $2000<br />

stack equ $7FFF<br />

portb equ $1004<br />

portc equ $1003<br />

portcl equ $1005<br />

pioc equ $1002<br />

ddrc equ $1007<br />

scdr equ $102f<br />

scsr equ $102e<br />

sccr1 equ $102c<br />

sccr2 equ $102d<br />

baud equ $102b<br />

reset equ $fffe<br />

; ASCII-Zeichen<br />

cr equ 13<br />

lf equ 10<br />

org prog<br />

main lds #stack ; Initialisierungen<br />

bsr sini<br />

loop ldx #cmd ; Prompt ausgeben<br />

bsr ssend<br />

bsr recv ; Befehl (1 Zeichen) einlesen<br />

cmpa #'a' ; ist es 'a'?<br />

bne next1 ; nein, weiter<br />

bsr doit ; Kommando 'a' verarbeiten<br />

bra loop<br />

next1 cmpa #'b' ; ist es 'b'?<br />

bne next2 ; nein, weiter<br />

bsr doit ; Kommando 'b' verarbeiten<br />

bra loop<br />

next2 cmpa #'c' ; ist es 'c'?<br />

bne next3 ; nein, weiter<br />

bsr doit ; Kommando 'c' verarbeiten<br />

bra loop<br />

next3 ldx #oops ; falsche Eingabe: "Oops" ausgeben<br />

bsr ssend<br />

bra loop<br />

; Kommandobearbeitungsroutine, hier als Dummy<br />

doit psha ; Kommandobearbeitung, erst Akku A retten<br />

ldx #k1 ; Text "Eingabe war" ausgeben<br />

bsr ssend<br />

pula ; Akku A wiederherstellen<br />

suba #$20 ; Kleinbuchstaben in Grossbuchstaben wandeln<br />

bsr send ; ausgeben<br />

bsr crlf ; "neue Zeile" ausgeben<br />

rts<br />

; Carriage Return und Line Feed ausgeben<br />

crlf ldaa #cr<br />

bsr send<br />

ldaa #lf<br />

bsr send<br />

rts<br />

Mikrocomputertechnik<br />

; String ausgeben (ohne cr/lf am Ende), Stringadresse (erstes Zeichen)<br />

Komplette Programmbeispiele 178


; muss in Register X uebergeben werden (siehe Kapitel 5)<br />

ssend ldaa 0,x<br />

beq sfin<br />

bsr send<br />

inx<br />

bra ssend<br />

sfin rts<br />

; serielle Schnittstelle initialisieren (siehe Kapitel 5)<br />

sini clr sccr1<br />

ldaa #$0C<br />

staa sccr2<br />

ldaa #$30<br />

staa baud<br />

rts<br />

; Zeichen seriell ausgeben (siehe Kapitel 5)<br />

send ldab scsr<br />

bpl send<br />

staa scdr<br />

rts<br />

; Zeichen seriell empfangen (siehe Kapitel 5)<br />

recv ldab scsr<br />

andb #$20<br />

beq recv<br />

ldaa scdr<br />

rts<br />

; String-Konstanten (Strings werden durch ein 0-Byte abgeschlossen)<br />

cmd dc.b 'Kommando: '<br />

dc.b 0<br />

oops dc.b 'Oops!'<br />

dc.b cr,lf,0<br />

k1 dc.b 'Eingabe war '<br />

dc.b 0<br />

org reset ; Reset-Vektor setzen<br />

fdb main<br />

end<br />

Demo für den Timer-Interrupt<br />

Das Programm zählt eine Variable "count" interruptgesteuert hoch.<br />

prog equ $8000<br />

data equ $2000<br />

stack equ $7FFF<br />

portb equ $1004<br />

portc equ $1003<br />

ddrc equ $1007<br />

reset equ $fffe<br />

tvec equ $FFDE ; interrupt vector of timer<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

org data<br />

count ds.b 1<br />

cflg ds.b 1<br />

org prog<br />

main lds #stack ; init variables<br />

clr portb<br />

Mikrocomputertechnik<br />

Komplette Programmbeispiele 179


clr count<br />

clr cflg<br />

ldab #$40 ; enable PA7 interrupt<br />

stab pacr ; enable pulse accu<br />

ldab #$80<br />

stab tmsk<br />

cli ; enable interrupts<br />

loop ldaa cflg ; get clock flag<br />

cmpa #20 ; trigger point?<br />

bne loop ; no, wait<br />

clr cflg ; yes, clear clock flag<br />

inc count ; count up<br />

ldaa count<br />

staa portb ; display counter<br />

bra loop<br />

; interrupt service routine<br />

tirq ldaa #$80<br />

staa tflg ; clear interrupt<br />

inc cflg ; count interrupts<br />

rti<br />

org tvec ; set interrupt vector<br />

fdb tirq ; DE timer overflow<br />

org reset ; set reset vector<br />

fdb main<br />

end<br />

Demo für Interrupt an STRA<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

pvec equ $FFDA ; vector pa7<br />

tvec equ $FFDE ; vector timer<br />

svec equ $FFF2 ; sirq vector<br />

rvec equ $FFFE ; reset vector<br />

pioc equ $1002 ; parallel i/o control<br />

pbdr equ $1004 ; port b data<br />

portcl equ $1005 ; port c data latch<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

flag ds.b 1 ; irq flag<br />

***************************<br />

* program area *<br />

***************************<br />

org prog<br />

main lds #stak ; load stackpointer<br />

bsr init ; data init<br />

cli ; enable irq<br />

loop ldaa flag<br />

Mikrocomputertechnik<br />

Komplette Programmbeispiele 180


staa pbdr ; display<br />

bra loop ; close main loop<br />

***************************<br />

* subroutines *<br />

***************************<br />

init clr flag<br />

ldab #$40 ; enable STRA interrupt<br />

stab pioc<br />

rts<br />

***************************<br />

* interrupt handler *<br />

***************************<br />

sirq ldaa pioc ; stra isr<br />

ldaa portcl ; clear interrupt<br />

com flag<br />

rti<br />

***************************<br />

* vectors *<br />

***************************<br />

org svec<br />

fdb sirq ; STRA<br />

org rvec<br />

fdb main ; FE reset<br />

end<br />

Demo für Interrupts an STRA und PA7<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

pvec equ $FFDA ; vector pa7<br />

tvec equ $FFDE ; vector timer<br />

svec equ $FFF2 ; sirq vector<br />

rvec equ $FFFE ; reset vector<br />

pioc equ $1002 ; parallel i/o control<br />

pbdr equ $1004 ; port b data<br />

pcdl equ $1005 ; port c data latch<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

baud equ $102B ; SCI-baudrate<br />

sccr1 equ $102C ; SCI-control1<br />

sccr2 equ $102D ; SCI-control2<br />

scsr equ $102E ; SCI-status<br />

scdr equ $102F ; SCI-data<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

flag ds.b 1 ; irq flag<br />

***************************<br />

* program area *<br />

***************************<br />

Mikrocomputertechnik<br />

Komplette Programmbeispiele 181


org prog<br />

main lds #stak ; load stackpointer<br />

bsr init ; data init<br />

cli ; enable irq<br />

loop ldaa flag<br />

staa pbdr ; display<br />

bra loop ; close main loop<br />

***************************<br />

* subroutines *<br />

***************************<br />

init clr flag<br />

ldab #$40 ; enable STRA interrupt<br />

stab pioc<br />

ldab #$40 ; enable PA7 interrupt<br />

stab pacr<br />

ldab #$10<br />

stab tmsk<br />

rts<br />

***************************<br />

* interrupt handler *<br />

***************************<br />

sirq ldaa pioc ; stra isr<br />

ldaa pcdl ; clear interrupt<br />

ldaa flag<br />

eora #$0F ; toggle lower nibble<br />

staa flag<br />

rti<br />

pirq ldaa #$10 ; pa7 isr<br />

staa tflg ; clear interrupt<br />

ldaa flag<br />

eora #$F0 ; toggle upper nibble<br />

staa flag<br />

rti<br />

***************************<br />

* vectors *<br />

***************************<br />

org pvec<br />

fdb pirq ; PA7 interrupt<br />

org svec<br />

fdb sirq ; STRA<br />

org rvec<br />

fdb main ; FE reset<br />

end<br />

Demo für Interrupts an STRA, PA7 und Timer<br />

data equ $2000 ; data area (e-ram)<br />

stak equ $7FFF ; stack area (e-ram)<br />

prog equ $8000 ; programm area (e-eerom)<br />

pvec equ $FFDA ; vector pa7<br />

tvec equ $FFDE ; vector timer<br />

svec equ $FFF2 ; sirq vector<br />

rvec equ $FFFE ; reset vector<br />

Mikrocomputertechnik<br />

Komplette Programmbeispiele 182


pioc equ $1002 ; parallel i/o control<br />

pbdr equ $1004 ; port b data<br />

pcdl equ $1005 ; port c data latch<br />

tmsk equ $1024 ; timer mask<br />

tflg equ $1025 ; timer flag<br />

pacr equ $1026 ; pulse accu control<br />

***************************<br />

* data area *<br />

***************************<br />

org data<br />

coun ds.b 1 ; counter<br />

cflg ds.b 1 ; clock flag<br />

updn ds.b 1 ; direction flag<br />

stop ds.b 1 ; stop flag<br />

***************************<br />

* program area *<br />

***************************<br />

org prog<br />

main lds #stak ; load stackpointer<br />

bsr init ; data init<br />

cli ; enable irq<br />

loop ldaa cflg ; get clock flag<br />

cmpa #20 ; trigger point?<br />

bne loop ; no, wait<br />

clr cflg ; yes, clear clock flag<br />

tst stop ; stop active?<br />

bne loop ; yes, wait<br />

bsr count ; update counter<br />

bra loop ; close main loop<br />

***************************<br />

* subroutines *<br />

***************************<br />

count ldaa coun ; load counter<br />

adda updn ; inc/dec counter<br />

staa coun ; save counter<br />

staa pbdr ; display counter<br />

rts<br />

init clr coun ; counter default<br />

clr cflg ; no clock seen<br />

clr stop<br />

ldaa #1<br />

staa updn ; default count up<br />

ldab #$40 ; enable STRA interrupt<br />

stab pioc<br />

ldab #$40 ; enable PA7 interrupt<br />

stab pacr ; enable pulse accu<br />

ldab #$90 ; $80 (Timer) + $10 (PA7)<br />

stab tmsk<br />

rts<br />

***************************<br />

* interrupt handler *<br />

***************************<br />

Mikrocomputertechnik<br />

Komplette Programmbeispiele 183


tirq ldaa #$80 ; timer isr<br />

staa tflg ; clear interrupt<br />

inc cflg ; count interrupts<br />

rti<br />

sirq ldaa pioc ; stra isr<br />

ldaa pcdl ; clear interrupt<br />

neg updn ; toggle direction<br />

rti<br />

pirq ldaa #$10 ; pa7 isr<br />

staa tflg ; clear interrupt<br />

com stop ; toggle stop flag<br />

rti<br />

***************************<br />

* vectors *<br />

***************************<br />

org pvec<br />

fdb pirq ; PA7<br />

org tvec<br />

fdb tirq ; timer overflow<br />

org svec<br />

fdb sirq ; STRA<br />

org rvec<br />

fdb main ; FE reset<br />

end<br />

Zum vorhergehenden Abschnitt Zum Inhaltsverzeichnis Zum nächsten Abschnitt<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 02. Jul 2012<br />

Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate, Prof. Peter Schwalb<br />

Komplette Programmbeispiele 184


Praktikum Mikrocomputer<br />

Allgemeines<br />

Im Rahmen dieses Praktikums sollen einfache Programme in Maschinensprache erstellt und auf dem<br />

Mikrocomputer PS11 erprobt werden. Dabei werden neben dem Einüben des Befehlsvorrats eines<br />

typischen Mikroprozessors die Problematiken der Unterprogrammtechnik, Stackbehandlung,<br />

Unterbrechungsbehandlung und Behandlung von parallelen und seriellen Schnittstellen untersucht.<br />

Ergänzende Zusatzschaltungen werden in TTL-Technik aufgebaut.<br />

Der Mikrocomputer PS11 baut auf dem Mikrocontroller M68HC11 (8MHz) von Motorola auf. Er<br />

wird im expanded mode betrieben und ist mit einer PRU M68HC24, 32kByte RAM und 32 kByte<br />

EEPROM als externen Komponenten versehen. Die Programmentwicklung erfolgt auf einem PC unter<br />

Verwendung eines unter Windows XP laufenden Programmpakets (Integrated Development<br />

Environment for M68HC11). Dieses ermöglicht das Editieren, Assemblieren, Simulieren und<br />

Bereitstellen von Programmen für den M68HC11. Der Datentransfer zwischen PC und Zielrechner<br />

erfolgt über eine serielle Schnittstelle (COM-Port COM1 mit 9600 Baud).<br />

Die Angaben zu den einzelnen Versuchen sind als thematischer Rahmen zu sehen. Die<br />

Aufgabenstellung kann durch den betreuenden Dozenten jederzeit modifiziert werden. Im Verlauf des<br />

Versuchs ist auf eine vernünftige Dokumentation zu achten.<br />

Installation der IDE-Software<br />

Die Programme des Pakets HC11-IDE.zip benötigen keine spezielle Installation, sondern laufen unter<br />

Windows (ab XP) wie sie sind. Um sich das Leben zu erleichtern, können Sie das Paket jedoch in die<br />

übliche Windows-Umgebung einbinden:<br />

• Unter C:\Programme (bzw. C:\Program Files) legen Sie ein Verzeichnis namens<br />

"HC11-IDE" an.<br />

• Entpacken Sie alle Programme der ZIP-Datei in dieses Verzeichnis. Das war's eigentlich<br />

schon.<br />

• Erzeugen Sie sich eine Verknüpfung des Programms scite.exe auf dem Desktop für den<br />

schnellen Zugriff. Wer will, kann auch noch eine Verknüpfung in der Taskleiste anlegen.<br />

• Unter Windows 7 erhalten Sie beim Beenden des Simulators eine Fehlermeldung. Das<br />

Problem kann behoben werden, indem Sie auf die Datei wookie182upx.exe mit der rechten<br />

Maustaste klicken und im Menü dann "Behandeln von Kompatibilitätsproblemen" klicken -<br />

Windows erledigt den Rest.<br />

• Anstelle des Windows Hyperterminals kann auch das Programm PuTTY für die serielle<br />

Kommunikation auf der PC-Seite verwendet werden. Sie erhalten die aktuelle Version unter<br />

http://www.putty.org/. Auch dieses Programm benötigt keine spezielle Installation.<br />

Einschalten und Starten<br />

Der Arbeitsplatz ist über den Sicherungsautomaten, der PC über den Netz-Taster am PC-Gehäuse und<br />

das Testobjekt mittels seines Netzschalters in der Rückwand einzuschalten. Achtung: Zum<br />

Ausschalten dient der kleine rechteckige, rote Knopt am Sicherungsautomaten, nicht der<br />

Not-Aus-Taster! Nach dem Start von Windows XP sind Benutzername und Kennwort einzugeben.<br />

Benutzername (user): ide11<br />

Kennwort (password): ide11<br />

Praktikum Mikrocomputer 185


Das Programm HC11-IDE11 wird durch klicken auf das entsprechende Icon gestartet. Wenn Sie<br />

IDE11 mehr als einmal starten, verweigern alle Inkarnationen des Programms den Kontakt zum<br />

M68HC11. In diesem Fall sind alle laufenden Versionen zu schließen und das Programm einmal neu<br />

zu starten.<br />

Programm-Namen und Ordner SAVE<br />

Quellprogramme (Sourcecodes) sind immer mit der Kennung (Extension) ".a" zu versehen (z. B.<br />

"versuch1_1.a"), da Editor und <strong>Assembler</strong> des Systems diese Kennung erwarten.<br />

Die im Laufe eines Praktikums-Versuchs erstellten (name.a) oder erzeugten (name.lst) Dateien sind<br />

über den Ordner (Directory) Eigene Dateien verfügbar. Sie können von dort aus auf Diskette oder<br />

einem USB-Massenspeicher abgespeichert werden. Wenn Sie vorbereitete Programme auf Diskette<br />

oder USB-Massenspeicher mitbringen, dann speichern Sie diese auch immer in diesem Ordner ab.<br />

Beenden und Abschalten<br />

Mikrocomputertechnik<br />

Wurde IDE11 versehentlich beendet, kann es über Doppelklicken des Symbols (Icon) des<br />

Arbeitsplatzes (Desktop) wieder gestartet werden.<br />

Der Praktikumsrechner PS11 ist nicht auszuschalten, sondern nur herunterzufahren:<br />

(START Wurde HC11-IDE11 versehentlich beendet, kann es über Doppelklicken des Symbols (Icon)<br />

des Arbeitsplatzes (Desktop) wieder gestartet werden. Der Praktikumsrechner PS11 ist nicht<br />

auszuschalten, sondern nur herunterzufahren: (START → Computer ausschalten).<br />

Bearbeiten eines Quellprogramms<br />

Einschalten und Starten 186


File → New<br />

Erzeugt ein leeres Editorfenster mit dem Namen "Untitled". Beim ersten Speichern wird ein SAVE AS<br />

ausgeführt.<br />

File → Open<br />

Eine Datei (Quellprogramm) kann aus dem Arbeitsverzeichnis ausgewählt und geöffnet werden. Für<br />

die Bearbeitung der Datei mittels Tasten und Maus (Markieren, Kopieren, Verschieben, etc.) gelten<br />

die üblichen Regeln. Weitere Funktionen werden im Menue "EDIT" angeboten. Es können auch<br />

mehrere Fenster geöffnet werden. Die Bearbeitungsvorgänge beziehen sich immer auf das aktive<br />

(oben liegende) Fenster.<br />

File → Save<br />

Speichert den Inhalt des aktiven (oben liegenden) Editorfensters als Textdatei. Ist der Dateiname noch<br />

nicht festgelegt, wird ein "SAVE AS"-Befehl ausgeführt und der Dateiname erfragt.<br />

File → Save As<br />

Mikrocomputertechnik<br />

Erfragt den gewünschten Dateinamen und speichert den Inhalt des aktiven (oben liegenden) Fensters<br />

als Textdatei (name.a).<br />

Erst nachdem die Datei mit der Erweiterung .a abgespeichert wurde wird das Syntax Highlighting<br />

aktiviert:<br />

Übersetzen eines Quellprogramms (source code)<br />

Bearbeiten eines Quellprogramms 187


Tools → Assemble<br />

Der Start des <strong>Assembler</strong>s erfolgt über das Menü "Tools" im Editor. Ein neues oder verändertes<br />

Quellprogramm im aktiven Fenster wird abgespeichert und anschließend übersetzt. Bei fehlerfreiem<br />

Ablauf der Übersetzung werden ein Zielprogramm (name.s19) und ein Programmlisting (name.LST)<br />

erzeugt. Eine gegebenenfalls erzeugte Fehlerliste wird im Ausgabe-Fenster (unterhalb des<br />

Editor-Fensters) angezeigt. Durch Doppelklick auf den angezeigten Fehler (Error: xxxxx) wird im<br />

Quellprogamm die fehlerhafte Zeile markiert.<br />

Anmerkung: Lassen Sie sich nicht durch die letzte Ausgabezeile des Editors ( → Exit-Code: 0)<br />

täuschen, diese besagt nur, dass das <strong>Assembler</strong>programm nicht abgestürzt ist.<br />

Simulieren eines Zielprogramms (object code)<br />

Tools → Simulate<br />

Mikrocomputertechnik<br />

Der Start des Simulators erfolgt ebenfalls über das Menü "Tools" im Editor. Das Zielprogramm wird<br />

in den Simulator geladen. Hier kann das Programm in einem simulierten PS11 System erprobt werden.<br />

Übersetzen eines Quellprogramms (source code) 188


Mikrocomputertechnik<br />

Der Simulator ist nicht in der Lage, alle Eigenschaften des 68HC11 exakt nachzubilden. So müssen<br />

Sie auf manche Interrupts und einiges andere verzichten. So ist derzeit keine umfassende Simulation<br />

der seriellen Schnittstelle möglich.<br />

Bei der Simulation des STRA-Eingangs mit dem Button [STRA = 0] ist folgendes zu beachten:<br />

• Mit jedem Anklicken wechselt der Zustand der (virtuellen) STRA-Eingansleitung zwischen 0<br />

und 1.<br />

• Um eine Flanke zu erzeugen, wie es der Taster auf dem Steckbrett bewirkt, muss deshalb<br />

zweimal auf den Button geklickt werden.<br />

Ähnlich verhält es sich beim Eingang PA7. Hier holen Sie sich den Port A auf die Arbeitsfläche des<br />

Simulators und klicken auf das höchstwertige Bit (7). Auch hier muss, um eine Flanke zu erzeugen,<br />

wie es der Taster auf dem Steckbrett bewirkt, zweimal auf das Bit geklickt werden.<br />

Je nach verwendetem PC-Modell kann es auch vorkommen, dass Zeitschleifen im Simulator schneller<br />

ablaufen, als dies bei einem realen Prozessor der Fall wäre.<br />

Beachten Sie auch, dass die Simulation des seriellen Terminals sehr einfach gehalten ist. So werden<br />

zum Beispiel alle Zeichen bei der Eingabe geechot, was im realen Betrieb nicht der Fall sein muss.<br />

Zum Starten eines Programms klicken Sie auf "Reset" und dann auf den "Start"-Button, der daraufhin<br />

grün wird. Im gestoppten Zustand kann das Programm im Einzelschritt-Modus durchlaufen werden. In<br />

diesem Fall öffnen Sie durch Klicken auf die entsprechenden Buttons die Fenster mit der<br />

Quellcodeanzeige ("View Code") und der Registeranzeige ("MC68HC11 CPU"). Die gerade<br />

Simulieren eines Zielprogramms (object code) 189


earbeitet <strong>Assembler</strong>zeile wird dann farbig unterlegt und Sie können die aktuellen Registerinhalte<br />

sehen (oder auch ändern). Mit "Browse Memory" werden Sie in die Lage versetzt, Speicherinhalte<br />

anzusehen und zu ändern.<br />

Die zusätzlich zur Binäranzeige vorhandene Siebensegmentanzeige für die Ports B und C bietet eine<br />

undecodierte Anzeige für Port B (alle Segmente einzeln ansteuerbar) und eine decodierte zweistellige<br />

Anzeige für Port C.<br />

Tools → Load in Target<br />

Das Zielprogramm, das zu dem im aktiven Fenster angezeigten Quellprogramm gehört, wird in den<br />

Speicher des Zielrechners übertragen (aber nicht gestartet). Dazu muß der Schalter am Zielsystem auf<br />

"PC" stehen. Zum Programmstart drücken Sie die RESET-Taste am Zielrechner.<br />

Arbeiten mit der seriellen Schnittstelle<br />

Bei Programmen, die die serielle Schnittstelle verwenden, im mit dem Terminalprogramm auf dem PC<br />

(z.B. Hyperterminal oder PuTTY) zu kommunizieren ist der Schalter am Zielsystem auf "Man."<br />

umzustellen, bevor die RESET-Taste gedrückt wird. Das Terminalprogramm muss online sein<br />

(Telefonhöhrer abgehoben).<br />

Beim Laden des Programms ins Zielsystem muss der Schalter wieder auf "PC" gestellt werden.<br />

Achten Sie auch darauf, das ein gegebenenfalls geöffnetes Terminalprogramm auf "aufgelegt =<br />

offline" geschaltet wird, da sonst ein Konflickt beider Programme um die serielle Schnittstelle<br />

entsteht. Das Terminalprogramm muss jedoch nicht geschlossen werden.<br />

In Kurzform:<br />

RUN: Terminal online, Schalter auf "Man."<br />

LOAD: Terminal offline, Schalter auf "PC<br />

Hinweise zur Programmerstellung<br />

Mikrocomputertechnik<br />

Jedes Programm muß folgende Anweisungen enthalten:<br />

stak equ $7FFF ; Stackbereich ab $7FFF (RAM, abwaerts)<br />

prog equ $8000 ; Programmbereich ab $8000 (EEPROM)<br />

data equ $2000 ; Datenbereich ab $2000 (RAM)<br />

rvec equ $FFFE ; Reset-Vektor<br />

. ; ggf. weitere Vektoren<br />

org data ; Beginn Datenbereich<br />

. ; Variablen-Definitionen<br />

.<br />

org prog ; Beginn Programmbereich<br />

main lds #stak ; Stackpointer setzen<br />

.<br />

. ; alle Initialisierungen<br />

.<br />

loop . ; Befehle des Programms<br />

.<br />

.<br />

jmp loop<br />

. ; ggf. fixe Tabellen dahinter<br />

.<br />

. ; ggf. Setzen der Interrupt-Vektoren<br />

Tools → Load in Target 190


. ; (Reihenfolge der Adressen beachten!)<br />

org rvec ; Setzen des Reset-Vektors<br />

fdb main<br />

end<br />

Der RAM-Speicher ab Adresse 0 bis Adresse 255 kann nicht genutzt werden (Bootloader bzw.<br />

Trace).<br />

Tools → Terminal<br />

Mikrocomputertechnik<br />

Der Datenverkehr zwischen dem PC und dem Zielrechner über die serielle Schnittstelle wird mittels<br />

des Terminalprogramms Hyperterm am PC dargestellt. Damit kann der Datenverkehr über die<br />

SCI-Schnittstelle interaktiv erfolgen.<br />

Hinweise zur Programmerstellung 191


Mikrocomputertechnik<br />

Belegung des Experimentier-Boards<br />

Auf dem Experimentierboard steckt eine Anzeigeplatine (die getrennt vom Board mit Strom versorgt<br />

werden muß). Die Platine enthält vier decodierte und eine undecodierte Siebensegmentanzeigen. Ihre<br />

Belegung zeigt die folgene Abbildung:<br />

Das Anschlußkabel zwischen M68HC11 und Experimentierboard endet auf einem Buchsenfeld, von<br />

dem aus die Verbindungen zur Anzeigeplatine bzw. zu den Schaltern, Tastern und LEDs gesteckt<br />

werden müssen.<br />

Belegung des Experimentier-Boards 192


Mikrocomputertechnik<br />

Beachten Sie, daß die LED-Treiber an der Vorderkante des Boards sowie das Board mit den<br />

Siebensegmentanzeigen gesondert mit Spannung versorgt werden muß. Ihr Betreuer zeigt Ihnen die<br />

entsprechenden Verbindungen am ersten Praktikumstag.<br />

Beschaltung der Eingänge des 68HC11<br />

Die Schalter des Experimentier-Boards haben keine aktive Spannungsversorgung sondern schalten<br />

lediglich das Massepotential wechselweise auf zwei Anschlußbuchsen. Verbindet man einen Schalter<br />

mit dem Eingang eines Ports des 68HC11, dann wird - je nach Schalterstellung - der Port mit Masse<br />

verbunden oder der Porteingang ist offen. Aus diesem Grund muß die Leitung vom Schalter zum<br />

Eingangsport des 68HC11 mittels Pull-Up-Widerstand ein 1-Potential erhalten.<br />

Sie finden auf dem Experimentier-Board auf einer der IC-Buchsen ein Widerstandsarray (WID-SIP)<br />

eingesteckt, das acht Widerstände enthält, die auf einer Seite miteinander verbunden sind. Dieser<br />

gemeinsame Anschluß ist auf dem Gehäuse des WID-SIP durch einen Punkt gekennzeichnet. Er wird<br />

mit +5V verbunden. Die anderen Pins des WID-SIP werden einerseits mit einem Schalter verbunden<br />

und andererseits mit einem Eingansport des 68HC11.<br />

Beschaltung der Eingänge des 68HC11 193


Mikrocomputertechnik<br />

Die beiden Taster sind bereits mit einer Entprell-Logik verbunden und liefern korrekte Digitalsignale<br />

für 0 und 1. Sie können daher direkt mit einem Eingangspin des 68HC11 verbunden werden.<br />

Beschaltung der Eingänge des 68HC11 194


Anhang: Binär zu ASCII-Decodierung (hx4a)<br />

Diese Unterprogramme werden beim vierten Praktikumstermin benötigt. Im Speicher liegen die Werte<br />

bekanntermaßen binär vor. Um einen Speicherinhalt oder ene Adresse auf der seriellen Schnittstelle<br />

(Terminal) oder einem LC-Display ausgeben zu können, müsen die Werte als ASCII-Zeichen<br />

dargestellt werden.<br />

Die folgenden vier miteinander verbundenen Unterprogramme wandeln einen 16-Bit-Wert, einen<br />

8-Bit-Wert oder einen 4-Bit-Wert in eine Hexadezimalzahl in ASCII-Darstellung um (4, 2, oder 1<br />

Stelle):<br />

• hx4a wandelt den Inhalt von Akku D in vier ASCII-Zeichen, die in einem 4 Byte langen<br />

Puffer abgelegt werden. Beim Unterprogrammaufruf muß das Indexregister Y auf die letzte<br />

Stelle des Puffers zeigen.<br />

• hx2a wandelt den Inhalt von Akku B in zwei ASCII-Zeichen, die in einem 2 Byte langen<br />

Puffer abgelegt werden. Beim Unterprogrammaufruf muß das Indexregister Y auf die letzte<br />

Stelle des Puffers zeigen.<br />

• hx1a wandelt den Inhalt von Akku B (Bits 0-3) in ein ASCII-Zeichen, das in einem 1 Byte<br />

langen Puffer abgelegt wird. Beim Unterprogrammaufruf muß das Indexregister Y auf den<br />

Puffers zeigen.<br />

hx4a psha ; Akku A auf dem Stack ablegen<br />

bsr hx2a ; Akku B umwandeln (Stelle 3 und 4)<br />

pulb ; Akku A vom Stack holen, in Akku B ablegen<br />

; Nun einfach in hx2a fallen und Akku B<br />

; umwandeln (Stelle 1 und 2)<br />

hx2a pshb ; Akku B auf dem Stack sichern<br />

bsr hx1a ; Bits 0-3 von Akku B umwandeln<br />

pulb ; Original-Akku B wieder holen<br />

lsrb ; viermal schieben (Bits 4-7 --> 0-3)<br />

lsrb<br />

lsrb ; und nun die obere Haelfte umwandeln<br />

lsrb ; indem einfach in hx1a gefallen wird<br />

; Nun wird die eigentliche Arbeit gemacht:<br />

hx1a andb #$0F ; die oberen 4 Bits ausmaskieren<br />

addb #48 ; ASCII-Wert von "0" addieren<br />

cmpb #57 ; groesser als "9"?<br />

bls hx1b ; nein, dann speichern<br />

addb #7 ; sonst die Distanz zwischen "9" und "a" addieren<br />

hx1b stab 0,y ; im Speicher ablegen, auf den Y zeigt<br />

dey ; Y zeigt jetzt auf die Stelle davor<br />

rts ; und weg<br />

Beispielaufruf:<br />

Versuche<br />

ldd #$AFFE ; Hexzahl in Akku D laden<br />

ldy #PUFFER+3 ; Position auf letzte Stelle im Puffer<br />

; der Puffer muss im Datenbereich reserviert sein<br />

bsr hx4a ; do it!<br />

ldy #PUFFER ; y --> Pufferanfang<br />

bsr STOU ; z.B. seriell ausgeben<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 20. Feb 2011, 16:49:01<br />

Mikrocomputertechnik<br />

Anhang: Binär zu ASCII-Decodierung (hx4a) 195


Mikrocomputertechnik<br />

Mikrocomputertechnik<br />

Prof. Jürgen Plate<br />

Mikrocomputertechnik 196


Praktikum Mikrocomputer<br />

Versuch 1: Parallel-Ports, Unterprogramme,<br />

Zeitverzögerungen<br />

Bei diesem Versuch soll unter Verwendung der Ports B und C des M68HC11 Datenverkehr mit<br />

externen Komponenten durchgeführt werden. Es soll grundsätzlich im polling mode gearbeitet<br />

werden, d.h. ohne Unterbrechungen. Geeignete Programmteile sind als Unterprogramm zu<br />

formulieren. Zeichnen Sie immer zuerst ein Flussdiagramm und programmieren Sie dann danach.<br />

Die Stellung der Schalter S7 - S4 soll andauernd über Port C [3:0] eingelesen und über Port C [7:4]<br />

auf die LEDs L3 - L0 ausgegeben werden. Die Initialisierung des Ports C soll als Unterprogramm<br />

(Name: PINI) formuliert werden.<br />

Zusätzlich soll ein 8-bit-Lauflicht mit einem Takt von 10 Hz programmiert werden. Seine aktuelle<br />

Stellung soll über Port B [7:0] ausgegeben und mittels der LEDs L15 - L8 angezeigt werden. Der<br />

zeitbestimmende Programmteil sowie das Weiterschalten und Anzeigen des Lauflichts sollen als<br />

Unterprogramme (Namen: DELAY und DISPLAY) formuliert werden.<br />

Nun soll sich der Takt verändern lassen. Der über die Schalter S7 - S4 des Experimentier-Boards<br />

eingestellte und über Port C [3:0] eingelesene Wert stellt die Lauflichtfrequenz in Hz dar, wenn er<br />

grösser als 0 ist. Der Wert 0 führt zu einem Anhalten der Anzeige (Lauflicht bleibt stehen und läuft<br />

erst weiter, wenn der Wert grösser als 0 ist). Siehe Anmerkung unten.<br />

Als Letztes soll noch mittels der Taste T0, die am Eingang STRA des M68HC11 anzuschließen ist,<br />

die Laufrichtung von Linkslauf auf Rechtslauf umgeschaltet werden können und umgekehrt (toggle).<br />

Anmerkung: Es gilt bekanntlich, dass die Frequenz ein Kehrwert der Zeit (Periodendauer) ist (f =<br />

1/t). Für eine Warteschleife, wie sie in der Vorlesung behandelt wurde, muss die Frequenz in eine<br />

Periodendauer umgerechnet werden (1 Hz = 1000 ms, 2 Hz = 500 ms, 3 Hz = 333 ms, 4 Hz = 250 ms<br />

usw.). Das Umrechnen der Frequenz in die Wartezeit kann programmtechnisch auf zweierlei Weise<br />

geschehen, durch (Integer-)Division oder durch eine Tabelle. Verwenden Sie in diesem Fall die<br />

Division (IDIV-Befehl). Schematisch stellt sich die Programmierung wie folgt dar:<br />

1. Entwurf einer Warteschleife für 1 Hz = 1000 ms mit einem möglichst großen Startwert I des<br />

Schleifenzählers.<br />

2. Einlesen der Schalterstellung und Expandieren des Wertes auf eine 16-Bit-Variable K.<br />

3. Division von J = I/K. J ist nun der aktuelle Startwert für die Zählschleife.<br />

Praktikum Mikrocomputer 197


Versuch 2: Parallel-Ports, 7-Segmentanzeige,<br />

Tabellenzugriff<br />

Bei diesem Versuch soll unter Verwendung der Ports B und C des M68HC11 Datenverkehr mit<br />

externen Komponenten durchgeführt werden. Es soll grundsätzlich im polling mode gearbeitet<br />

werden, d.h. ohne Unterbrechungen. Geeignete Programmteile sind als Unterprogramm zu<br />

formulieren. Zeichnen Sie immer zuerst ein Flußdiagramm und programmieren Sie dann danach.<br />

Die Stellung der Schalter S7 - S4 soll andauernd über Port C [3:0] eingelesen, über Port C [7:4]<br />

ausgegeben und als einstellige Sedezimalzahl angezeigt werden. Dazu ist die 7-Segment-Anzeige A3<br />

(mit Decoder) zu verwenden. Die Initialisierung des Ports C soll als Unterprogramm (Name: PINI)<br />

formuliert werden.<br />

Nun werden die 7-Segment-Anzeigen A1 und A2 (mit Decoder) an Port B (A1: [7:4], A2: [3:0])<br />

angeschlossen. Es soll eine 'Digitaluhr' programmiert werden, die Sekunden und Zehntelsekunden<br />

anzeigt (Sekunden Zehner auf A1, Sekunden Einer auf A2 und Zehntelsekunden auf A3). Dazu wird,<br />

wie schon im ersten Versuch, einem Warteroutine DELAY benötigt, die hier eine Periodendauer von<br />

100 ms hat.<br />

Die Digitaluhr soll bei einen vorgegebenen Wert (Programmvariable) starten, bis zum Wert 00.0<br />

herunterzählen und dann anhalten. Mittels der Taste T0, die am Eingang STRA des M68HC11<br />

anzuschließen ist, kann der Zähler mit dem voreingestellten Anfangswert gestartet oder gestoppt<br />

werden.<br />

Über die Schalter S7 - S4 an Port C [3:0] soll die Startzeit des Zählers aus einer Tabelle gewählt<br />

werden, wobei in der Tabelle nur die Sekunden gespeichert werden, die Zehntensekunden starten<br />

immer mit 0. Die Tabelle besitzt somit 16 Einträge. Die in der Tabelle einzutragenden Zeiten sind frei<br />

wählbar.<br />

Hinweis:Optional kann anstelle einer Warteschleife mittels X- oder Y-Register auch der frei laufende<br />

Zähler für die Zeitverzögerung verwendet werden (ohne Interrupt). Dazu sind folgende<br />

Vereinbarungen notwendig:<br />

1. Bei den Konstantendefinitionen<br />

Mikrocomputertechnik<br />

tflag equ $1025 ; Timer Flag Register<br />

tmask equ $1024 ; Timer Mask Register<br />

faktor equ 30 ; Multiplikationsfaktor fuer Timer<br />

; 3 ~ 0,1 s:<br />

; 32,77 * 3 = 98,31 (fast 0,1 s)<br />

; 30 ~ 1 s:<br />

; 32,77 * 30 = 983,1 ms (fast 1 s)<br />

2. Bei den Veriablendefinitionen<br />

org data<br />

...<br />

dlycnt ds.b 1<br />

3. Bei den Unterprogrammen (tinit wird beim Programm-Init aufgerufen)<br />

tinit psha ; Timer Init<br />

clr tmask ; Timer-Prescaler / 1 --> 32,77 ms<br />

ldaa #faktor ; Zeit festlegen<br />

staa dlycnt<br />

pula<br />

rts<br />

Versuch 2: Parallel-Ports, 7-Segmentanzeige, Tabellenzugriff 198


Mikrocomputertechnik<br />

delay psha ; Delay-Routine<br />

delay1 ldaa tflag ; warten auf Timer-Ueberlauf<br />

bpl delay1<br />

ldaa #$80 ; TOFL-Flag zuruecksetzen<br />

staa tflag<br />

dec dlycnt ; delay-counter dekrementieren<br />

tst dlycnt<br />

bne delay1 ; warten auf dlycnt == 0<br />

ldaa #faktor ; dann dlycnt neu setzen<br />

staa dlycnt<br />

pula ; und fertig<br />

rts<br />

Versuch 2: Parallel-Ports, 7-Segmentanzeige, Tabellenzugriff 199


Mikrocomputertechnik<br />

Versuch 3: Serielle Schnittstelle, ASCII-Zeichenketten<br />

Bei diesem Versuch soll unter Verwendung des SCI (Asynchronous Serial Communications Interface)<br />

des M68HC11 Datenverkehr zwischen Prozessor M68HC11 und PC als Terminal durchgeführt<br />

werden. Es soll grundsätzlich im polling mode gearbeitet werden, d.h. ohne Unterbrechungen. Als<br />

String-Terminator dient wie bei C das Nullbyte ($00). Geeignete Programmteile sind als<br />

Unterprogramm zu formulieren. Zeichnen Sie immer zuerst ein Flussdiagramm und programmieren<br />

Sie dann danach.<br />

Wichtig: Zum Terminalbetrieb ist nach dem Terminalbetrieb der Schalter "PC-MAN" am<br />

Praktikumsrechner in Stellung MAN zu bringen. Zum Laden des Programms muss er dann wieder auf<br />

PC gestellt werden. Entsprechend muss beim Hyperterminal zum Programm-Download "aufgelegt"<br />

(Telefon-Icon in der oberen Werkzeugleiste) und zum Betrieb wieder "abgehoben" werden.<br />

Zum Einstieg soll das ASCII-Zeichen 'R' mit einer Wiederholfrequenz von etwa 5 Hz andauernd auf<br />

das Terminalfenster des Hyperterminal-Programms ausgegeben werden. Die Initialisierung des SCI ist<br />

als Unterprogramm (Name: SINIT) zu formulieren. Das Senden des Zeiches soll durch ein<br />

Unterprogramm namens CHOU erfolgen, das das im Akku A übergebene Zeichen (bei freier<br />

Schnittstelle) sendet.<br />

Ein vorbereiteter Text (nullterminierter ASCII-String) ist nun mittels des neu zu schreibenden<br />

Unterprogramms STOU dauernd auf das Terminalfenster auszugeben. Register X enthält die Adresse<br />

des ersten Zeichens des Textes. Das Unterprogramm STOU gibt die ab (X) stehenden ASCII-Zeichen<br />

unter Verwendung des Unterprogramms CHOU aus, bis das Textendezeichen (\0) gefunden wird, das<br />

selbst nicht mit ausgegeben wird. Stattdessen werden die Steuerzeichen CR (Carriage Return) und LF<br />

(Line Feed) ausgegeben.<br />

Ein über die Tastatur eingegebenes Zeichen ist mittels des Unterprogramms CHIN einzulesen und<br />

mittels des Unterprogramms CHOU als Echo auszugeben (Endlos-Schleife). Das Unterprogramm<br />

CHIN übergibt das gelesene Zeichen im Akku A.<br />

Nun soll statt eines einzelnen Zeichens ein String über die Tastatur eingegeben, mittels des<br />

Unterprogramms STIN eingelesen und im Speicher abgelegt werden. STIN verwendet seinerseits<br />

CHIN, um ein Zeichen zu lesen. Zur Kontrolle wird der String mithilfe des Unterprogramms STOU<br />

wieder ausgegeben (Endlos-Schleife). Das Unterprogramm STIN soll folgende Eigenschaften<br />

besitzen:<br />

i. STIN echot die mittels CHIN eingelesenen Zeichen und legt sie im Speicher ab. Die Adresse<br />

des Eingabepuffers wird im Indexregister X übergeben.<br />

ii. Nicht darstellbare Zeichen (alle ASCII-Zeichen < " ") werden bei der Eingabe ignoriert.<br />

iii. Das ASCII-Zeichen CR beendet die Eingabe, es wird ohne Echo als Nullbyte abgelegt.<br />

iv. STIN wird durch die Ausgabe von CR und LF abgeschlossen.<br />

Mittels STIN soll schließlich eine Zeichenkette eingelesen und mit einem im Programm abgelegten,<br />

konstanten String zeichenweise verglichen werden (z. B. als Passwortabfrage). Das Ergebnis des<br />

Vergleichs soll über Port B [6:0] ausgegeben und mittels der 7-Segment-Anzeige A5 (ohne Decoder)<br />

dargestellt werden:<br />

i. Sind die Zeichenketten unterschiedlich, wird ein "F" ausgegeben (für "falsch"). Gleichzeitig<br />

wird ein Fehlerzähler inkrementiert.<br />

ii. Stimmen beide Zeichenketten überein, wird eine "1" ausgegeben. Der Fehlerzähler wird in<br />

diesem Fall zurückgesetzt.<br />

iii. Erfolgt dreimal hintereinander eine falsche Eingabe (Fehlerzähler == 3), wird ein "E"<br />

ausgegeben (für "Error"), das im Rhythmus von 2 Hz blinkt, und keine Eingabe mehr<br />

Versuch 3: Serielle Schnittstelle, ASCII-Zeichenketten 200


angenommen.<br />

Mikrocomputertechnik<br />

Versuch 3: Serielle Schnittstelle, ASCII-Zeichenketten 201


Mikrocomputertechnik<br />

Versuch 4: Zähler, bedingte Unterbrechungen<br />

Bei diesem Versuch sollen ein einfacher Zähler betrieben und verschiedene bedingte Unterbrechungen<br />

aktiviert und bearbeitet werden. Geeignete Programmteile sind als Unterprogramm zu formulieren.<br />

Zeichnen Sie immer zuerst ein Flussdiagramm und programmieren Sie dann danach.<br />

Ein 2-stelliger Sedezimalzähler ist mit einer Frequenz von etwa 10 Hz zu betreiben. Seine aktuelle<br />

Stellung soll über Port C [7:0] ausgegeben und mittels der 7-Segment-Anzeigen A1 und A2 (mit<br />

Decoder) dargestellt werden. Der zeitbestimmende Programmteil soll als Unterprogramm (D100)<br />

unter Verwendung des Registers Y formuliert werden. Orientieren Sie sich an den Programmen aus<br />

den Versuchen 1 und 2.<br />

Modifizieren Sie das Programm nun so, dass beim Starten des Programms der Text "M68HC11<br />

gestartet" auf das Terminalfenster ausgegeben wird. Verwenden Sie dazu die beim Versuch 3<br />

entwickelten Unterprogramme zur Initialisierung der SCI, sowie zur Zeichen- und Stringausgabe<br />

(CHOU und STOU).<br />

Zusätzlich sind nun bedingte Unterbrechungen zu bearbeiten. Mittels der Tasten T0 und T1, die an<br />

den Eingängen STRA und PA7 des M68HC11 anzuschließen sind, können bedingte Unterbrechungen<br />

ausgelöst werden. Als Folge darauf sollen vom Hauptprogramm aus die unten beschriebenen<br />

Aktionen erfolgen.<br />

Die Unterprogramme zur Unterbrechungsbearbeitung sind möglichst kurz zu halten. Zur<br />

Signalisierung von der Unterbrechungsbearbeitung zum Hauptprogramm sollen die Bits 0 und 1 einer<br />

Variablen DFLG (display flag) verwendet werden. Die zum Starten der Unterbrechungsbearbeitungen<br />

nötigen Vektoren nicht vergessen:<br />

org $ffda<br />

dc.w pirq ; pulse accu input (PA7)<br />

org $fff2<br />

dc.w sirq ; IRQ/STRA<br />

org $fffe<br />

dc.w main ; reset<br />

• Beim Auftreten einer Unterbrechung durch T1 an PA7 soll der jeweilige Befehlszählerstand<br />

des unterbrochenen Programms als 4-stellige Hexzahl auf das Terminalfenster ausgegeben<br />

werden ("PC=XXXX"). Verwenden Sie dazu unter anderem das Unterprogramm hx4a (siehe<br />

unten).<br />

Von der Interrupt-Serviceroutine wird nur der Wert des Befehlszählers in der<br />

16-Bit-Variablen PCSTAT ans Hauptprogramm übergeben. Die Tatsache, dass ein Interrupt<br />

auftrat, wird in einer Flag-Variablen namens PFLAG signalisiert. Die Umwandlung Binär →<br />

Hex sowie die Ausgabe erfolgen im Haptprogramm, das auch PFLAG wieder zurücksetzt.<br />

• Beim Auftreten einer Unterbrechung durch T0 an STRA soll jeweils nach dem 3. Impuls am<br />

Interrupteingang (also nach dreimaligem Tastendruck) der Zähler gestoppt und erst nach<br />

weiteren 3 Tastenbetätigungen wieder weiterlaufen. Dies soll sich periodisch wiederholen.<br />

Bearbeiten Sie das Zählen der Tastenbetätigungen innerhalb der Interrupt-Serviceroutine und<br />

signalisieren Sie die Start/Stopp-Information über eine Flag-Variable namens SFLAG. Im<br />

Hauptprogramm wird anhand dieser Variablen entschieden, ob der Zähler läuft oder steht.<br />

Die beiden Unterprogramme hx2a und hx4a können Sie von dieser Angabe per Cut-and-Paste<br />

übernehmen. Dabei ist zu beachten, dass hx2a und hx4a den entstehenden String nach fallenden<br />

Adressen hin aufbauen und dass damit die Übergabeparameter entsprechend gewählt werden müssen.<br />

Sehen Sie sich dazu auch den Quelltext zu den Unterprogrammen am Ende dieses Dokuments an.<br />

Versuch 4: Zähler, bedingte Unterbrechungen 202


Anhang: Binär zu ASCII-Decodierung (hx4a)<br />

Diese Unterprogramme werden beim vierten Praktikumstermin benötigt. Im Speicher liegen die Werte<br />

bekanntermaßen binär vor. Um einen Speicherinhalt oder eine Adresse auf der seriellen Schnittstelle<br />

(Terminal) oder einem LC-Display ausgeben zu können, müsen die Werte als ASCII-Zeichen<br />

dargestellt werden.<br />

Die folgenden vier miteinander verbundenen Unterprogramme wandeln einen 16-Bit-Wert, einen<br />

8-Bit-Wert oder einen 4-Bit-Wert in eine Hexadezimalzahl in ASCII-Darstellung um (4, 2, oder 1<br />

Stelle):<br />

• hx4a wandelt den Inhalt von Akku D in vier ASCII-Zeichen, die in einem 4 Byte langen<br />

Puffer abgelegt werden. Beim Unterprogrammaufruf muss das Indexregister Y auf die letzte<br />

Stelle des Puffers zeigen.<br />

• hx2a wandelt den Inhalt von Akku B in zwei ASCII-Zeichen, die in einem 2 Byte langen<br />

Puffer abgelegt werden. Beim Unterprogrammaufruf muss das Indexregister Y auf die letzte<br />

Stelle des Puffers zeigen.<br />

• hx1a wandelt den Inhalt von Akku B (Bits 0-3) in ein ASCII-Zeichen, das in einem 1 Byte<br />

langen Puffer abgelegt wird. Beim Unterprogrammaufruf muss das Indexregister Y auf den<br />

Puffers zeigen.<br />

hx4a psha ; Akku A auf dem Stack ablegen<br />

bsr hx2a ; Akku B umwandeln (Stelle 3 und 4)<br />

pulb ; Akku A vom Stack holen, in Akku B ablegen<br />

; Nun einfach in hx2a fallen und Akku B<br />

; umwandeln (Stelle 1 und 2)<br />

hx2a pshb ; Akku B auf dem Stack sichern<br />

bsr hx1a ; Bits 0-3 von Akku B umwandeln<br />

pulb ; Original-Akku B wieder holen<br />

lsrb ; viermal schieben (Bits 4-7 --> 0-3)<br />

lsrb<br />

lsrb ; und nun die obere Haelfte umwandeln<br />

lsrb ; indem einfach in hx1a gefallen wird<br />

; Nun wird die eigentliche Arbeit gemacht:<br />

hx1a andb #$0F ; die oberen 4 Bits ausmaskieren<br />

addb #48 ; ASCII-Wert von "0" addieren<br />

cmpb #57 ; groesser als "9"?<br />

bls hx1b ; nein, dann speichern<br />

addb #7 ; sonst die Distanz zwischen "9" und "a" addieren<br />

hx1b stab 0,y ; im Speicher ablegen, auf den Y zeigt<br />

dey ; Y zeigt jetzt auf die Stelle davor<br />

rts ; und weg<br />

Beispielaufruf:<br />

ldd #$AFFE ; Hexzahl in Akku D laden<br />

ldy #PUFFER+3 ; Position auf letzte Stelle im Puffer<br />

; der Puffer muss im Datenbereich reserviert sein<br />

bsr hx4a ; do it!<br />

ldy #PUFFER ; y --> Pufferanfang<br />

bsr STOU ; z.B. seriell ausgeben<br />

[ Praktikumsanleitung ] [ Skript ]<br />

Copyright © FH München, FB 04, Prof. Jürgen Plate<br />

Letzte Aktualisierung: 20. Feb 2011, 16:49:01<br />

Mikrocomputertechnik<br />

Anhang: Binär zu ASCII-Decodierung (hx4a) 203

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

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!