Lange Zeit wurde aus den vorhandenen Bauteilen, erst Relais, dann Röhren, später Transistoren und schließlich standard-IC's für jedes Schaltungsproblem eine logische Schaltung entwickelt ohne daß jedoch ein Bauteil zur Verfügung stand, das viele Standardfunktionen ausführen konnte. Als dann universell programmierbare Mikroprozessoren verfügbar wurden, setzte man diese auch in Steuerungen ein. Der wachsende Bedarf nach Steuerungen führte schließlich zur Entwicklung von einfach anwendbaren Prozessoren, die die wesentlichen Mikrokomputerkomponenten wie CPU mit deren Takterzeugung, Timer, Speicher (RAM/ROM/EPROM/EEPROM/FLASH), serielle Schnittstelle und - für Steuerungen besonders wichtig - Interrupts und digitale I/O Ports schon enthalten. Man nennt diese ''Computer auf einem Chip'' Mikrocontroller. Da sie nur Komponenten besitzen, die für Steuerungsaufgaben interessant sind und da durch die Integration auf einem Chip das Gehäuse klein gehalten werden kann, sind die Bauteile relativ billig. Durch ihren Einsatz läßt sich häufig diskrete Hardware durch Software ersetzen , was Schaltungen vereinfacht und so Designkosten und Kosten für Änderungen teilweise erheblich reduziert. Mikrocontroller werden beispielsweise eingesetzt in HiFi- und Haushaltsgeräten (Mikrowelle, Waschmaschine, Fernseher, Videorecorder), Computerzubehör (Drucker, Modem), Meßgeräten, in der Meß- Steuer- Regelungstechnik zur Erfassung von Meßdaten und zur Steuerung, in Klimaanlagen und in zunehmendem Maße auch im Automobil (Motorregelung, ABS, Armaturenbrett mit digitalen Displays). Der Einsatz von Kleincomputern im Automobil ist heute teilweise soweit fortgeschritten, daß die Recheneinheiten schon durch ein kleines Netzwerk (meist CAN-Standard) untereinander verbunden werden. Je nach Anforderungen gibt es 4, 8, 16 und 32 Bit Mikrocontroller mit unterschiedlichen Taktraten und Zusatzkomponenten, wie PWM, Schnittstellen (CAN, I2C), A/D Wandler, Watchdog, DSP u.a. Den größten Anteil am Markt haben jedoch die 8-Bit Mikrocontroller und sie werden von ihren Herstellern weiter gefördert. Die wichtigsten Mikrocontrollerfamilien sind Motorola 68hc11, Intel 8051 (MCS-51) und Microchip PIC mit ihrem bekannten low-cost Abkömmling, der BASIC-Briefmarke. Der Motorola 68hc11 ist ein 8-Bit Mikrocontroller, der jedoch 16Bit Arithmetik kennt. Er hat sich aus den Motorola Prozessoren 6502, 6805, 6809 entwickelt, ist aber zu diesen nicht kompatibel. Bei ihm sind PWM Ausgänge Standard. Auch Microcontroller mit 68000 Kern sind erhältlich (683xx). Intels MCS-51 Architektur ist eine Weiterentwicklung der MCS-48 Reihe (eingeführt 1976), dem ersten Mikrocontroller überhaupt, der lange in Tastaturen für Computer eingesetzt wurde. Auch Intel bietet 16-Bit (MCS-96) und 32-Bit (80386EX) Mikrocontroller an. Es gibt viele andere Prozessor Hersteller, darunter National Semiconductor, Zilog, Atmel, Dallas, Siemens, Mitsubishi und NEC, die entweder eigene Architekturen entworfen haben, oder aber zu den vorher genannten kompatible Prozessoren anbieten.
Der original 8051 als Basis des MCS-51 Standards wurde von Intel 1980 entwickelt und hat sich zur erfolgreichsten und größten Mikrocontrollerfamilie entwickelt. Seine Fähigkeiten zur Bit-Manipulation und die große Menge an freier Software und Beispielprogrammen, die es für diese Architektur gibt, sowie die jüngsten Weiterentwicklungen anderer Hersteller (Atmel: FLASH, Dallas: High-speed, Philips, Siemens ...) machen diese Familie besonders interessant. Sie deckt den weitesten Bereich von Mikrocontrollerapplikationen bei Binärkompatibilität untereinander ab, d.h. bei unvorhergesehenen Problemen oder Weiterentwicklungen findet man wahrscheinlich einen Mikrocontroller von irgendeinem anderen Hersteller, der genau dieses Problem löst, ohne daß man neue Schaltungen entwickeln, neue Software kaufen und sich neu einarbeiten muß.
Die Familie MCS-51 ist sehr groß. Verschiedene Hersteller bieten Typen an, die sich in der Art und Anzahl von on-chip Zusatzkomponenten unterscheiden. Der Grundtyp ist der 8051, ein 8-Bit Rechner mit vier 8-Bit Ports, 128 Bytes internem RAM für Daten, 4k maskenprogrammierbarem ROM für Programmcode, internem Oszillator, zwei Timern/Countern, serieller bidirektionaler Schnittstelle und Harvard-Architektur, die getrennt je 64 kBytes externen Daten- und Programmspeicher ansprechen kann. Die traditionelle von Neumann Architektur mit gemeinsamem Programm- und Datenbereich ist bei Mikrocontrollern problematisch, da die Programme anders als bei Heimcomputern oft nicht aus dem RAM, sondern aus dem ROM ausgeführt werden. Daten können dort aber nicht verändert werden, so daß dafür ein separater Datenbereich zur Verfügung steht.
Aufgrund des maskenprogrammierbaren ROM's wird der original 8051 natürlich nur von größeren Firmen eingesetzt. Die ROM-lose Version heißt 8031 und es gibt auch Mikrocontroller mit EPROM mit Quarzglasfenster zum Löschen des Programmes oder als billigere OTP (one time programmable) Version für Kleinserien in denen der Code nur einmal geschrieben wird, ein maskenprogrammierbarer Speicher sich aber nicht lohnt. Die EPROM und OTP Versionen heißen 87Cxxx und elektrisch löschbare EEPROM Varianten in der Regel 89Cxxx. Der 8052 besitzt doppelt soviel RAM und ROM wie der 8051 und einen zusätzlichen Timer, der 8032 ist wiederum dessen ROM-lose Version, womit die Beschreibung der Grundtypen auch schon abgeschlossen ist.
Alle anderen haben mindestens die Eigenschaften des 8031, wenn man von den neuesten Chips Atmel 89C2051 und 89C1051 absieht, die ein nur 20 poliges Gehäuse, keine Möglichkeit zum Anschluß externen Speichers und daher nur 2 Ports haben. Versionen mit stark erweiterten Funktionen haben mehr Pins und dann auch andere Gehäuse. Der am einfachsten anzuwendende Typ ist sicher der 8052 AH-BASIC mit internem BASIC-Interpreter, der bei entsprechender Platine auch gleich die Programmiermöglichkeit für EPROMS bietet. Beim Aufbau eines Systems fällt also der externe Speicher für den Startup-Code weg und die Programmierung vereinfacht sich auch, setzt aber zeitunkritische Anwendungen voraus. Der Quellcode zum Basic-51 1.1 ist von intel als Public Domain freigegeben und kann daher selbst in ein EPROM gebrannt werden. Die derzeit schnellsten MCS-51 Mikrocontroller werden von Dallas angeboten (DS80C320, DS80C520), sie besitzen Taktraten bis 33MHz, bei optimiertem Prozessorkern. Die wohl komfortabelsten werden von Siemens hergestellt (SAB 80C517, SAB 80C537), die auch 16 Bit Arithmetik kennen, 6 Ports besitzen und standardmäßig über 4 PWM Ausgänge verfügen, dem 68HC11 also überlegen sind.
Im weiteren bezieht sich der Ausdruck 8051 auf alle Mitglieder der MCS-51 Familie, soweit nicht näher bezeichnet.
Der 8051 besitzt einen umfangreichen Befehlssatz mit logischen Befehlen, den üblichen Datentransport- und Sprungbefehlen, und auch arithmetischen Befehlen SUB, ADD, MUL, DIV. Die Stärke des Prozessors liegt jedoch in der direkten Bit Manipulation. Es müssen also nicht Bits mit z.B. OR 00001000B maskiert werden, sondern sie können direkt adressiert werden (nicht bei allen Adressen). Im Unterschied zu anderen Prozessoren, beispielsweise dem Vorgänger 8048, werden zur Steuerung von Timer und serieller Schnittstelle keine speziellen Befehle verwendet. Vielmehr gibt es spezielle Register, die im Datenbereich des 8051 angeordnet sind, die special function register (SFR). So sind Erweiterungen der Architektur leicht möglich, denn Compiler oder Assembler ändern sich nicht, der Programmierer kann aber die erweiterten Funktionen seines Prozessors über SFR Adressen ansprechen [15], [9], [13], [12], [2].
Das minimale MCS-51 System besteht aus einem 8751 mit eingebranntem Programmcode, einem Schwingquarz, zwei Keramik- und einem Elektrolytkondensator, und einem Widerstand. Programmänderungen sind dann aber nur durch Bestrahlung des Quarzfensters mit UV-Licht und anschließendem Beschreiben des Mikrocontrollers in einem speziellen EPROM-Brenner möglich, das Rücksetzen nur indem man die Versorgungsspannung abschaltet. Als Steuerplatine eines Mikrowellenofens wäre das völlig ausreichen, als Experimentalsystem zur Programmentwicklung jedoch völlig ungeeignet.
Besser ist eine Schaltung, bei der man eine externe EPROM Emulation hat, in die man Programme laden und austesten kann und bei der Resetschalter und RS232 Pegelwandlung zum Anschluß an einen Computer vorhanden sind. Im Gegensatz zu TTL-Pegeln, bei denen eine logische null 0 bis 0.8V eine eins 2.4-5V entspricht, arbeitet die RS-232C Schnittstelle mit -3 bis -15 V als logischer eins und +3 bis +15V als logischer null, was sie unempfindlich gegenüber elektromagnetischer Einstreuung macht. Um den 8051 nicht zu zerstören braucht man jedoch eine Pegelwandlung. Diese, wie auch die Erzeugung einer symmetrischen Spannung +/- 10V übernimmt ein MAX232, der mit vier Kondensatoren 1 uF, 16V beschaltet werden muß, oder ein MAX233, der die Kondensatoren nicht benötigt.
Legt man den EA pin des Mikrocontrollers auf null, so spricht der 8051 externen Speicher über seine Ports P0 und P2 an, diese sind dann nicht mehr als I/O Ports nutzbar. P0 enthält dabei zuerst die unteren 8 Adreßbits und dann die Daten. Man nennt dieses Verfahren multiplexen. Es wird angewendet um Anschlüsse zu sparen. Port P2 enthält die oberen 8 Adreßbits. Um die Adresse vollständig zuückzugewinnen benutzt man ein Latch, einen Zwischenspeicher, der mit dem ALE-pin des Prozessors angesteuert wird. Das ist in der Regel ein 74373 oder 74573, wegen der hohen Geschwindigkeit im Mikrocontrollersystem am Besten als HCT Version. Nun läßt sich externer Speicher über 16 Bit Adress- und 8 Bit Datenbus ansprechen. Um in einem Experimentalsystem Programme im RAM zu speichern und dort abarbeiten zu lassen, macht man die Trennung des Speichers in Daten- und Programmteil durch den Prozessor wieder rückgängig. Das geschieht durch logische OR Verknüpfung des PSEN und RD Signales. Da diese Pins aktiv eine Null führen wird dazu ein AND Gatter verwendet. Dieses Signal steuert dann das RAM. Der Adressdecodierung dient üblicherweise ein 74138. Die an den Adress-/Datenbus verlorenen Ports gewinnt man durch Einsatz eines I/O Bausteines 8255 zurück, hat dann sogar einen Port mehr als vorher, d.h. 40 I/O Leitungen von denen normalerweise zwei für die serielle Schnittstelle verwendet werden, also netto 38 Pins. Ein Resetschalter ermöglicht den Neustart des Rechners, dabei bleibt der RAM Inhalt übrigens erhalten.
Das hier benutzte Schaltungslayout und die Platine stammt von einem Lichtorgelprojekt aus [4]. Es handelt sich um einen Einplatinencomputer (EPC). Die Platine ist einseitig und die Schaltung entspricht dem eben beschriebenen experimentellen Minimalsystem mit EPROM Emulation zum schnellen Austesten von Programmen. Es besitzt keine serielle Pegelwandlung, da vom Entwickler die Ansteuerung über ein 11 poliges paralleles Kabel vorgesehen war, und kann mit einem beliebigen 40poligen 8051 Derivat mit passendem Quarz, einem EPROM 2764 oder 27128, einem 32K RAM 62256 und dem I/O Baustein 8255 bestückt werden. Es wurde der Dallas Prozessor 80C320 mit 24MHz Quarz und das 16K EPROM 27C128 gewählt. Bei den Speichern muß auf kurze Zugriffszeiten geachtet werden, da der Prozessor recht schnell ist. Das EPROM besitzt 150ns Zugriffszeit, das statische RAM üblicherweise 70ns, 166ns sind Maximum beim 80C320 mit 24MHz.
Der 80C320 von Dallas besitzt zusätzlich zu den Austattungsmerkmalen des 8032 einen Power-fail Reset und Frühwarninterrupt, sieben zusätzliche Interrupts, einen zweiten Datenzeiger (DPTR1), der Blockverschiebungen beschleunigt, Verbesserungen bei den Stromsparmodi, sowie einen programmierbaren Watchdog und ist in Versionen erhältlich, die bis 25 oder 33MHz betrieben werden können. Da die Architektur des CPU Kerns verbessert wurde, führt er einen Maschinenzyklus in nur 4 Taktzyklen aus. Ein Standard 80C32 braucht 12 Taktzyklen für einen Maschinenzyklus und wird üblicherweise mit 12MHz getaktet. Der eingesetzte Prozessor ist bei 24 MHz bis zu 6 mal schneller als ein Standardcontroller und erreicht eine theoretische peak performance von 6 Mips. Ein 8032 müßte mit 60MHz laufen um dieselbe Leistung zu erreichen. Um trotz der hohen Leistung langsame Peripherie ansprechen zu können, ist die Speicherzugriffsgeschwindigkeit bei externen Datenspeicherzugriffen wählbar von 2-9 Maschinenzyklen (80-1120 ns bei 25Mhz).
Die Speicheraufteilung des EPC ist bewußt einfach gehalten:
Der Multiplexer unterteilt den Speicherbereich in 16k Blöcke. Über die beiden Dioden, die ein OR Gatter darstellen werden aus 2x16k zusammenhängende 32k für das RAM[4].
Dabei ein Paar grundlegende Worte zu Speichern: Die Speicher teilen sich grob in ROM, read ony memory - Nur Lesespeicher, und RAM , random access memory - Speicher mit wahlfreiem Zugriff auf. Für die beschreibbaren Speicher werden kleine Kondensatoren verwendet, deren Ladung schnell verlorengeht und die daher immer neu aufgefrischt werden müssen. Man nennt diese dynamische RAM's. Solche, die den Schaltzustand mit Flip-Flop's halten und nicht aufgefrischt werden müssen heißen statische RAM's. Sie besitzen typischerweise kleinere Zugriffszeiten, eine geringere Speicherdichte und sie sind teuerer als die dynamischen [3].
Einmal programmierbare PROMS besitzen durchschmelzende Sicherungen, maskenprogrammierbare ROM's werden ab Fabrik bei der Herstellung durch Einätzen des Bitmusters programmiert. Die Herstellung der Masken lohnt sich nur bei großen Stückzahlen. Der in Kleinserien, im Labor- und Hobbybereich beliebteste Festspeicher ist das EPROM, erasable programmable read only memory. Er kann in einem speziellen Gerät beschrieben und mit UV Licht wieder gelöscht werden. Er ist folgendermaßen aufgebaut: jedes Bit besitzt zwei Transistoren, einen für die Adreßdecodierung und einen FAMOS-Transistor, der die Information speichert. FAMOS bedeutet ''Floating Avalanche injection Metal Oxide Semiconductor''. Das Gate dieses Transistors ist rundum in Siliziumoxyd eingebettet und somit vollständig isoliert. Bei der Programmierung wird zwischen Gate und Substrat eine im Verhältnis zur Betriebsspannung relativ hohe Programmierspannung von 12 bis 21V angelegt, wodurch es zum Avalanche- oder Lawinendurchbruch durch die Isolierschicht kommt. Die so auf das Gate aufgebrachten Ladungsträger bleiben einige Jahre erhalten.
Auskunft über Hersteller und Programmierspannung gibt die silicon signature, die aus vielen EPROM's ausgelesen werden kann. Zur Löschung besitzen EPROM's UV-Licht durchlässige Quarzglasfenster. Bei Bestrahlung mit energiereichem UV-Licht entsteht nämlich ein fotoelektrischer Strom über den die Gate-Ladung abfließen kann. Im Freien bei Sonnenlicht kann ein EPROM bereits in einer Woche einzelne Bits verlieren. Man deckt daher das Fenster mit einem Selbstklebeetikett ab, das idealerweise metallisiert ist, ein Papieraufkleber schützt aber auch schon. Das Löschen im Löschgerät dauert etwa 15 bis 45 Minuten und man sollte eher großzügig sein, da ein unzureichend gelöschtes EPROM kurz nach dem Löschen leer erscheint, nach einiger Zeit aber das ursprüngliche Bitmuster wieder auftaucht! Nach korrektem Löschen ist das EPROM mit Einsen gefüllt, d.h. mit 0xFF in allen Zellen. Der Programmiervorgang besteht also darin, Bits zu löschen. Mit einem Programmiergerät ist es nicht möglich, Bits zu setzen, ein Speicherbereich der mit 0xFF gefüllt ist, läßt sich allerdings auch später programmieren ohne das EPROM erneut löschen zu müssen. Dadurch kann man ein kleines Monitorprogramm in ein großes EPROM brennen, wobei ein großer Teil des Speichers frei bleibt, den man später mit anderen Daten oder Programmen füllt.
Der Standardprogrammieralgorithmus sieht Programmierimpulse von 50 ms vor, d.h. an Vpp liegt die Programmierspannung an und Adreß- und Datenleitungen ändern sich während dieser Zeit nicht. Bei einem 27128, einem 16 kByte EPROM beträgt die Programmierzeit dann 13 Minuten und 40 Sekunden. Um das Verfahren zu beschleunigen wurden modifizierte Programmieralgorithmen entwickelt. Viele Speicherzellen sollen mit dem Wert 0xFF programmiert werden, den sie aber schon besitzen. Durch Auslassung dieser Speicherzellen läßt sich das Verfahren etwas verkürzen. Der intelligente Algorithmus geht jedoch weiter. Er benutzt Impulse vom 1ms, prüft danach, ob das Byte fehlerfrei zurückgelesen werden kann und wenn dies der Fall ist, maximal jedoch nach 15ms, wird mit der drei- bis vierfachen verstrichenen Zeit nachprogrammiert, um den Datenerhalt über längere Zeit sicherzustellen. Noch schneller ist eine Programmierung mit 0.5ms Impulsen und Nachprogrammierung mit nur der doppelten Dauer. Dieses Verfahren entspricht jedoch nicht mehr der Herstellerspezifikation und die Daten sind eventuell nicht ganz so lange haltbar [6], [7].
In [2] ist eine RAM Backup Schaltung beschrieben: eine 3,6V Lithium Zelle liefert über eine Diode und einen 1k Widerstand Strom an den 62256. Pin 28 aber auch Pin 20 (CE) werden über einen weiteren 1k Widerstand versorgt. Im Normalbetrieb liegt dieser Pin über einen selbstsperrenden MOSFET BS170 auf Masse, so daß der Baustein selektiert ist. Fällt die Betriebsspannung aus, so sperrt der FET und CE liegt auf Betriebsspannung, was dem Stand by modus des Chips entspricht.
Doch zurück zum benutzten Einplatinencomputer.
Die 8 LEDs des Ports B müssen nicht bestückt werden, erweisen sich jedoch als hilfreich, da sie Programmzustände anzeigen können, ähnlich dem Einfügen von printf() statements in C Quellcode beim Debuggen. Sie sind außer der seriellen Schnittstelle die einzige Möglichkeit, dem Benutzer etwas mitzuteilen. Abweichend von der Baubeschreibung sollte man jedoch Low current LEDs mit entsprechenden Vorwiderständen benutzen, da der 8255 normale LEDs gar nicht treiben darf (offenbar schafft er das doch).
Die voreingestellten Adressen für den PAULMON Start und den Anfang des RAM's
sind 0x0000 und 0x2000, können jedoch leicht geändert werden. Für den
EPC wird der
RAM Bereich auf 0x8000 gelegt. Die Einschaltmeldung und der Prompt wurden
gekürzt, die Benutzerführung ins Deutsche übersetzt, mehrere Bugs entfernt und
einige Routinen ergänzt. Darunter die INI8032 Routine, welche Timer 2 für die
Baudratenerzeugung benutzt und einige andere hardwarespezifische
Verbesserungen enthält, darunter das Wechselblinken der Einschalt LED und die
Erweiterung der Interruptvektoren am Anfang des Speicherbereichs auf alle dem
80C320 bekannten Interrupts. Die Zieladressen der Interruptvektoren wurden an
das Ende des Speichers gelegt, wobei für jede Routine 256 Byte zur Verfügung
stehen. Im Gegensatz zur Original INIT Routine darf sie mit einem
Standardprozessor, einem anderen Quarz oder mit einem anderen Platinenlayout
nicht verwendet werden. Es wird nämlich eine starre Baudratenerzeugung
verwendet, wodurch mit einem 24MHz Quarz Baudraten von 19200 möglich
sind, was die INIT Routine nicht mehr leistet. Damit der Monitor wieder mit
allen Prozessoren, Quarzen und Bordlayouts zusammenarbeitet, muß in der
Routine poweron
der Aufruf ACALL INI8032
ersetzt werden durch
LCALL INIT. Um Platz zu sparen kann dann die INI8032 Routine, die
Rauschroutine und die Routinen zur LED Ansteuerung entfernt werden. Die
Routinen STIME und MSTIME, die Zeitverzögerungsschleifen sind, sind Prozessor-
und quarzspezifisch, können also angepaßt werden und einige Interruptvektoren
am Anfang des Programms sind nur benutzbar mit dem 80C320, können also auch
entfernt werden.
Variable EQU WertAS31 verlangt hingegen
.EQU Variable, Wert
Das kann man als Verbesserung des Sprachstandards ansehen, da Opcodes von Pseudo Opcodes durch den Punkt klar unterschieden sind. Von anderen Programmen übernommene Teile muß man jedoch meist leicht modifizieren. Die Kompatibilität der anderen getesteten Assembler ist jedoch ähnlich begrenzt. Mit einigen Änderungen des Quelltextes kann natürlich jeder andere 8051 Assembler verwendet werden. Es gibt außerdem auch FORTH51 Systeme im Internet oder aber kommerzielle C Compiler und Assembler.
Nun wird das serielle Interface mit dem MAX232 getestet, das auf der separaten Steuerplatine aufgebaut ist. Pin 16 führt die 5V Versorgungsspannung, pin 15 Ground. An Pin 2 müssen 8 bis 10V liegen, an Pin 6 -8 bis -10V. Der RS232 TxD Ausgang Pin 14 (Pin 7) hat normalerweise -9V und sollte auf +9V springen, wenn man den TTL Eingang Pin 11 (Pin 10) auf Ground legt. Analog liegt der TTL Ausgang Pin 12 (Pin 9) auf Eins und geht beim Anlegen einer positiven Spannung an RxD Pin 13 (Pin 8) auf Null. Pin 12 (Pin 9) des MAX232 geht an Pin 10 des 8051 und Pin 11 des MAX 232 wie des 8051 sind verbunden. Ohne Spannung werden jetzt der Prozessor, das EPROM mit eingebranntem Monitorprogramm, der 74373/573, 74138 und 7408 eingesetzt.
Die Kommunikation mit dem EPC geschieht über jedes Terminal oder Terminalprogramm, wie Kermit, ProComm, Windows oder OS/2 Terminal, mit dem auch die Uploads von Testprogrammen möglich sind. Die Verbindung erfolgt über ein normales dreiadriges Nullmodemkabel mit Kreuzung von RxD und TxD, der dritte Anschluß ist GND.
Die Datenübertragung bei RS232 erfolgt seriell, d.h. die einzelnen Bits werden nacheinander über eine Leitung übertragen. Da die Schnittstelle bidirektional ist, benötigt man eine Hin-, eine Rückleitung und die Masseleitung. Die vollständige RS232 Schnittstelle hat allerdings andere Leitungen, die Steuerungs- und Kontrollfunktion besitzen. Die Übertragung beginnt laut Norm mit einem logischen MARK (logisch 1) Zustand der Sender Ausgangsleitung. Diese Zustand liegt nach dem Einschalten vor und wird auch nach jeder Übertragung wieder eingenommen. Zur Benachrichtigung des Empfängers dient das Startbit: Für die Dauer eines Bits gibt der Sender SPACE (logisch 0) aus, wodurch der Empfänger seine Abfragelogik vorbereitet. Die Datenbits folgen dann von LSB bis MSB. Die elektrische Spezifikation sieht vor, Leitungen bis 30m anzuschließen, dies bei eingeschaltetem Rechner zu tun und erlaubt es, die Ausgänge kurzzuschließen. Der RS232 Standard ist auch als V.24 bekannt, mit der elektrischen Spezifikation in der V.28 und ist ebenfalls in der DIN66020 definiert. Eine solche Schnittstelle ist meist in irgendeiner Form an einem Computer, Drucker oder Terminal vorhanden. Dabei unterscheidet man zwischen DTE, data terminal equipment, oder Datenendeinrichtung und DCE, data communication equipment, also Datenübertragungseinrichtung. Bei DCE und DTE sind RxD und TxD gleich bezeichnet, bedeuten aber beim sendenden DCE, daß der Pin als solcher fungiert, beim DTE, daß hier der entsprechende Pin des DCE angeschlossen werden soll. DTE besitzt dabei einen männlichen Steckanschluß und die Pins sind von vornherein vertauscht, so daß man nur ein 1:1 Kabel mit einem männlichen und einem weiblichen Stecker benötigt um die Beiden zu verbinden. Zwei solcher Kabel lassen sich einfach zu einem längeren verbinden. Bei EPC Projekten ist es gängige Praxis eine weibliche Buchse benutzen, den EPC also als DCE zu sehen, die Pins aber trotzdem zu vertauschen. Das entspricht nun gar keiner Norm mehr und es ist schwierig, festzulegen ob denn nun der EPC oder der PC mehr sendet, also eher als DCE bezeichnet werden soll. Daher und da man ein ''richtiges'' Nullmodemkabel z.B. auch zur Kommunikation mit anderen Rechnern einsetzen kann, wird in den EPC eine RS232 Schnittstelle mit der Belegung des IBM PC eingebaut. Die RS232 arbeitet mit +/-3 bis 15V, die gegen Masse gemessen wird, und inverser Logik, d.h. dem hohen Spannungspegel für eine logische Null. Die Normen RS422 und RS485 hingegen benutzen zwei Leitungen auf denen +/- 2V anliegen, die differentiell gemessen werden, was eine höhere Übertragungssicherheit schafft. Während die RS232 nur zwei Geräte miteinander verbindet, können bei der RS422 mehrere Empfänger angeschlossen werden, bei der RS485 auch mehrere Sender, daher wird die elektrische Spezifikation RS485 gerne bei Netzwerken eingesetzt. Da bei einem Bussystem die Steckverbinder die größte Fehlerquelle darstellen sind übrigens serielle Busse und Netzwerke weniger fehleranfällig als parallele, da sie einfach weniger Kontakte besitzen. Selbst bei Kopplung mehrerer CPU's in einem Mehrprozessorsystem geht man teilweise ab von der parallelen Verbindung und benutzt statt dessen serielle Hochgeschwindigkeitslinks, einfach weil die heutigen CPU's ohnehin weit über hundert Pins besitzen. Gegen elektromagnetische Einstreuung schützt Abschirmung oder die Übertragung per Lichtleiter, der systembedingt dagegen resistent ist.
25 pol. | 9 pol. | Ein-/ Ausgang | Bezeichnung | Funktion |
---|---|---|---|---|
2 | 3 | Aus | TxD (Transmit Data) | Sendedaten |
3 | 2 | Ein | RxD (Receive Data) | Empfangsdaten |
4 | 7 | Aus | RTS (Request to send) | Sendeteil einschalten |
5 | 8 | Ein | CTS (Clear to send) | Sendebereitschaft |
6 | 6 | Ein | DSR (Data set ready) | Betriebsbereitschaft |
7 | 5 | GND | GND (Ground) | Erde |
8 | 1 | Ein | DCD (Data carrier detect) | Empfangssignalpegel |
20 | 4 | Aus | DTR (Data Terminal Ready) | Endgerät bereit |
22 | 9 | Ein | RI (Ring Indicator) | Ankommender Ruf |
So angeschlossen muß man bei PAULMON nur ein Carriage Return an den EPC senden und er müßte sich melden, dabei sollte man den EPC nicht überfordern, sondern erst eine geringere Baudrate, wie 1200 Baud einstellen. Die Schnittstelle wird dabei mit 8 Datenbits ohne Parität mit einem Start- und einem Stopbit betrieben, es werden also immer 10 Bit als Datenpaket übertragen. Dabei soll nicht unerwähnt bleiben, daß die automatische Baudratenerkennung nur bis etwa 4800 Baud funktioniert wenn nicht ein spezieller Quarz eingesetzt wird. Diese erkennt man am ''krummen'' Wert, oft wird beispielsweise ein solcher mit 11.05920 MHz eingesetzt. Damit sind auch Datenraten von 9600 und 19200 Baud erreichbar, da der Baudratentakt dann exakt berechnet werden kann. Das ist besonders bei PAULMON von Vorteil, da er im Vergleich zu anderen Monitoren viel Text über die Schnittstelle sendet, aber auch beim Intel-Hex download von Programmen ist eine hohe Baudrate vorteilhaft. Timer 2, der nur bei 8032 und besser vorhanden ist, kann Baudraten mit feinerer Stufung generieren. Die bei der 80C320 Version von Paulmon eingesetzte Routine INI8032 generiert mit 24MHz Takt eine Baudrate von 19230.769 Baud. Die korrekte Bitbreite von 52.1ms wird dabei nur um 0,1ms oder 1.9% verfehlt. Da aber nach 10 übertragenen Bit ohnehin wieder auf das nächste Stopbit gewartet wird ist das belanglos. Damit ein Fehler aufritt müßten 521 Bit ohne Stobit übertragen werden. Sogar eine Baudrate von 20270.27, also eine Abweichung von 5.6% auf dem EPC bringt einwandfreie Übertragung bei 19200 Baud.
Meldet sich der EPC, so setzt man das RAM und den 8255 ein, lädt ein Testprogramm welches prüft ob RAM und externe Ports funktionieren. Wenn das nicht der Fall ist, muß man sich noch einmal die Hardware genauer anschauen.
Nun prüft man die angeschlossene Schaltung, bei einem High-speed Prozessor wie dem Dallas chip zweckmäßigerweise mit einem langsameren Quarz. So kommt man mit einem billigeren Oszilloskop aus und die Schaltung funktioniert auch, wenn man unglücklicherweise zu langsame Speicher eingesetzt hat. Mit einem Oszilloskop prüft man, ob der Oszillator schwingt. Das kann man mit einem 1/10 Tastkopf direkt an den Pins 18/19 tun, wobei man aber eventuell die Schwingung zum Erliegen bringt, oder man testet die Pins ALE und PSEN, die ständig arbeiten sollten. Die Pins haben eine Frequenz von 1/6 des Oszillators (beim Standard 8051!) und ALE hat ein Tastverhältnis von 1:3 und PSEN eines von 1:1. Auch ein Frequenzzähler hilft also weiter, wenn man kein Oszilloskop zur Verfügung hat. ALE ist der address latch enable Pin, taktet also das Latch 74373, PSEN bedeutet program store enable, ist also der Lesetakt für den externen Propgrammspeicher.
Zu diesen Messungen ist anzumerken, daß der Oszillator nicht selbst starten kann, wenn er nicht gut abgestimmt ist, sondern dazu muß ein Reset Impuls ausgelöst werden. Man sollte also von Zeit zu Zeit die Reset Taste drücken. Auch wird der Oszillator nicht bei andauerndem Reset schwingen, d.h. hat man beim Resetschalter den Öffner statt des Schließers angeschlossen passiert gar nichts. Beim Reset, wie beim Anlegen der Versorgungsspannung geht der Reset Eingang RST auf Eins um dann sofort wieder auf Null zu fallen. Wegen des internen pull-down Widerstandes am RST Pin genügt ein Kondensator an seinem Eingang für den power on reset. Wenn ein externes EPROM eingesetzt wird, muß der EA Pin des 8051 auf Null gelegt werden. Dann sollte der Prozessor das EPROM ansprechen, indem er den CS Pin des EPROM's auf Null legt. Das kann schon mit einem einfachen Voltmeter überprüft werden, da der Prozessor alle Instruktionen vom EPROM holen sollte und der Pin daher fast immer auf Null liegen sollte. Bei allen Tests prüft man die Schaltung von oben und setzt die Tastköpfe direkt auf die Beinchen der Chips. Erstens ist auch der Schaltplan und die Pinbelegung von oben gezeichnet und außerdem werden so die Verbindungen der Sockel gleich mitgetestet und verbogene Pins erkannt. Bei einem eingesetzten EPROM mit Monitorprogramm sollten die höheren Adressleitungen inaktiv bleiben, da der Prozessor eine kleine Schleife in einem eng umgrenzten Speicherbereich abarbeitet.
Ersetzt man das Programm EPROM durch ein NOP EPROM, also eines, das mit lauter Nullen gefüllt ist, so sollte der Prozessor durch seinen kompletten Adreßraum laufen und die Adressleitungen ein Muster aufweisen, bei dem jede Leitung die halbe Frequenz der vorherigen führt. Das gilt meist auch bei völlig fehlendem Speicher. Die niederwertigen Bits der Adresse mißt man natürlich nach dem Latch. Als nächsten Test setzt man ein EPROM mit einer Endlosschleife ein.
; Test fuer 8051 0000: .org 0x0000 0000: 04 start: inc A 0001: F5 90 mov P1, A 0003: 80 FB sjmp start
Das Programm gibt ansteigend die Werte 0x00 bis 0xFF ab Port P1 des Prozessors aus. Tut sich immer noch nichts, kann man jetzt daran denken, die Bausteine nacheinander auszuwechseln, oder bei selbst entwickelten Schaltungen sollte man sich noch einmal prinzipielle Gedanken über die Schaltung machen [14], [5], [6].
In Maschinensprache zu programmieren ist praktisch unzumutbar. Das bedeutet nämlich, daß der Programmierer für jeden Befehl in einer Tabelle einen Zahlenwert, den operation code, kurz Opcode nachschlägt und eingibt. Schon bei der Fehlersuche jedoch muß der Programmierer alle Opcodes auswendig wissen um das Programm verfolgen zu können. Faßt man aber Opcodes die ähnliche Funktion haben mit einem Merkkürzel, einem Mnemonic zusammen, und überläßt das Nachschauen des Opcodes einem einfachen Programm, so kann der Programmierer alle Maschinenbefehle gezielt einsetzen, muß sie aber nicht als Zahl auswendig lernen. Sowohl die entstandene Sprache als auch das Übersetzungsprogramm heißen Assembler. Übersetzt der Assembler in die Maschinensprache einer anderen Systemarchitektur, beispielsweise Übersetzung eines MCS-51 Assemblerprogramms auf einem IBM kompatiblen PC, so heißt der Assembler Crossassembler. Da heute niemand mehr in Maschinensprache programmiert, wird leider gelegentlich der Begriff Maschinensprache für die Assemblerprogrammierung benutzt.
Auch in Assembler kann man stukturiert programmieren. Aussagekräftige Label für Sprungmarken und Variablen und das Anlegen von wiederverwendbaren Unterroutinen, die natürlich entsprechend kommentiert sind, sind dafür unabdingbar, genau wie in jeder anderen Sprache. Strukturiert heißt in jedem Fall, daß ein möglichst kurzes, leicht durchschaubares Hauptprogramm existiert, das die Funktionen des Programms als Unterroutinen aufruft. Man kann also schon daran erkennen, wie das Programm arbeitet, wenn man auch noch nicht die einzelnen Lösungen versteht. Dafür muß man sich dann die Unterroutinen anschauen. Früher galt ein Assemblerprogrammierer als gut, wenn er die komliziertesten Algorithmen in ein paar Byte packen konnte. Verstehen oder ändern konnte solch eine Routine oft nur der Programmierer selbst. Heute hat man schon auf einem kleinen EPC meist genügend Speicherplatz und Rechengeschwindigkeit, so daß ein paar Befehle mehr uns nicht vor Speicherplatzprobleme stellen. Programmiertricks sollte man daher nur in Ausnahmefällen anwenden. Dort muß dann besonderer Wert auf Dokumentation gelegt werden.
Nun zum Befehlssatz des 8051: Die 44 Mnemonics eines MCS-51 Assemblers ermöglichen bei einigen Befehlen sowohl Bit- als auch Bytemanipulationen (ANL, ORL, CLR, CPL) oder Operationen auf den Datenzeiger DPTR, das einzige 16Bit Register (MOV byte/bit/DPTR, INC), so daß diese als zwei oder drei unterschiedliche Befehle gerechnet werden müssen. Es ergeben sich 51 Grundbefehle (Daher MCS-51). Dafür gibt es wiederum bei Speicherzugriffen unterschiedliche Adressierungsarten, also muß der Programmierer 111 Befehle unterscheiden. 49 davon bestehen aus nur einem Byte, 45 aus zwei und 17 aus dreien. Wie in Assembler üblich folgt dem Mnemonic erst der Ziel- dann der Quelloperand. Für schnellen Zugriff stehen vier Bänke zu acht Registern R0 bis R7 zur Vefügung, die vom Prozessorkern unterschiedlich angesprochen werden. Dadurch spalten sich Befehle die darauf zugreifen noch einmal in je acht Opcodes auf. Insgesamt besteht die MCS-51 Maschinensprache aus 255 Opcodes, also ist nur einer der 256 möglichen 8Bit Opcodes nicht genutzt. Es ist der Opcode 0xA5. Die vier arithmetischen Operationen erlauben nur 8 Bit Arithmetik, höhere Mathematikfunktionen werden nicht direkt unterstützt. Genauere oder Fließkommaarithmetik, sowie Trigonometrische Funktionen u.s.w. lassen sich nur durch entsprechende Routinen auf Kosten der Laufzeit erreichen. Der Prozessor unterstützt jedoch BCD Berechnungen. Bei BCD (binary coded digit) Zahlen, auch gepackte Dezimalzahlen genannt, enthält ein Nybble (Nybble=4 Bit) jeweils eine Dezimalziffer, man benutzt also die Codes 0xA bis 0xF nicht. Das ist vorteilhaft bei Ansteuerung von Anzeigen, da die dezimale Struktur der Zahl nicht vollständig verlorengeht. Bei arithmetischen Operationen treten jedoch Fehler auf, die mit dem speziellen Maschinenbefehl DA korrigiert werden können. Der Status der Berechnung läßt sich im Prozessorstatuswort (PSW) abfragen, das folgende Flags enthält:
Das Carry CY, PSW.7 oder C wird gesetzt, wenn ein Übertrag in Bitposition 7 entsteht, andernfalls wird es gelöscht. Es wird benutzt bei Addition von vorzeichenlosen Zahlen.
Zur BCD Addition gibt es das Auxiliary Carry AC, PSW.6, das gesetzt wird, wenn ein Übertrag in Bitposition 3 entsteht, d.h. von der ersten Stelle zur zweiten.
Das Überlauf Flag OV, PSW.2 wird gesetzt wenn ein Übertrag an Bitposition 6 entsteht aber keiner an Position 7 oder aber an Position 7 und keiner an Position 6. Es ist zur Addition vorzeichenbehafteter Zahlen gedacht.
Prüfsummenberechnungen führt der Mikrocontroller im Akkumulator selbständig durch. Das Parity Flag P, PSW.0 wird automatisch entsprechend gerader Parität gesetzt.
Das Flag F0, PSW.5 kann vom Benutzer frei genutzt werden.
Die Flags PSW.4, RS1 und PSW.3, RS0 selektieren die Registerbank, wie im Anhang beschrieben.
Obwohl der Mikrocontroller 8051 eine CISC CPU enthält und daher Stack- und Akkumulatororientiert arbeitet, d.h. bei arithmetischen Operationen enthält der Akkumulator ACC oder A den Quelloperand und auch nach Ausführung des Befehls das Ergebnis, ist es möglich viele Operationen am Akkumulator vorbei direkt an Registern auszuführen. Die jeweils aktive Registerbank R0-R7 wird durch PSW.4 (RS1) und PSW.3 (RS0) selektiert (siehe Anhang). Die Bänke belegen die ersten 32 Byte 0x00 bis 0x1F des internen Speichers. Man könnte bei der Programmierung auch diese Adressen angeben, der Befehl belegt dann aber mehr Speicher und wird langsamer ausgeführt. Gleiches gilt für den Akkumulator: ACC ist die Speicheradresse des Akkumulator, die Angabe von A generiert einen speziellen, auf den Akkumulator ausgerichteten Befehl wenn das möglich ist. Einen speziellen Opcode für PUSH A gibt es beispielsweise nicht, dort muß man die Adresse des Akkumulators angeben: PUSH ACC. Der Unterschied in der Opcodegenerierung ist im Motorola Assembler deutlicher: dort gibt es einen eigenen Befehl um den Akkumulator zu laden - LDA XXX. Bei intel heißt dieser Befehl MOV A, XXX.
Das B Register dient bei MUL und DIV als zweites Arbeitsregister, kann aber sonst einfach als neuntes Register genutzt werden. Im Gegensatz zu diesen ist B Bit adressierbar, d.h. es gibt die Bit Adresse B.3 (Bit drei des Bytes B), aber nicht die Adresse R0.3.
Der Stackpointer SP zeigt nach einem Reset auf die Adresse 0x07, wodurch der Stack bei 0x08 beginnt, also bei Registerbank 1. Im Speicher folgen die Registerbank 2 und 3 und dann der Bit adressierbare Speicherbereich. Die Registerbänke und der Bit adressierbare Bereich würden daher bei höherer Stapeltiefe vom Stack überschrieben, können so also nicht benutzt werden. Es ist daher sinnvoll den Stackpointer bei der Initialisierung darüber zu legen, d.h. ab 0x30 oder höher. Bei den Mikrocontrollern mit 256 Byte internem RAM bietet sich der Bereich ab Adresse 0x80 an. Dieser Bereich ist zweigeteilt. Bei direkter Adressierung erfolgt der Zugriff auf SFR, bei indirekter Adressierung auf die zweite Hälfte des internen RAM, der Stack benutzt natürlich das RAM.
Der Datenzeiger DPTR besteht aus den Bytes DPH (data pointer high) und DPL (data pointer low) und ermöglicht Zugriff auf den gesamten 64kByte Speicher. Er wird wie ein 16 Bit Register verwaltet, es gibt also Befehle mit denen direkt ein Wort in den DPTR geschrieben werden kann.
Diese Zusammenhänge werden klarer, wenn man die Adressierungsarten des 8051 versteht.
MOV A, R0
in nur ein Byte Maschinensprache 0xE8 übersetzt. Register Adressierung wird im MCS-51 Assembler mit Rn bezeichnet.
.EQU Variable, 0x21 MOV A, Variable ; Adresse 0x21 direkt adressiert
Beim 8032 können die oberen 128 Bytes internes RAM nur über den Stackpointer SP und die Register indirekte Adressierung angesprochen werden. Direkte Adressierung wiederum ist der einzige Weg Hardwareadressen (SFR) anzusprechen.
MOV R0, 0x21 . . . INC R0 MOV A, @R0 ; Hole Wert der an Speicherstelle ; 0x22 steht in den ACC
MOV A, #0xFF
MOV DPTR, #0x4001 ; 16 Bit Adresse laden MOVX @DPTR, A ; Akkumulator ins externe RAM ; (oder Peripherie), ; Adresse M0x4001schreiben. . . CLR Acc MOV DPTR, 0x1000 MOVC A, @A+DPTR ; z.B. um aus einer Tabelle im ; ROM sequentiell zu lesen.
MOVC ist nicht nur relativ zu A, sondern auch relativ zum PC möglich, mit MOVC kann man selbstverständlich nur lesen (ROM!).
B | F7 | F6 | F5 | F4 | F3 | F2 | F1 | F0 | 0xF0 |
ACC | E7 | E6 | E5 | E4 | E3 | E2 | E1 | E0 | 0xE0 |
PSW | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 0xD0 |
IP | BF | BE | BD | BC | BB | BA | B9 | B8 | 0xB8 |
P3 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | 0xB0 |
IE | AF | AE | AD | AC | AB | AA | A9 | A8 | 0xA8 |
P2 | A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 | 0xA0 |
SCON | 9F | 9E | 9D | 9C | 9B | 9A | 99 | 98 | 0x98 |
P1 | 97 | 96 | 95 | 94 | 93 | 92 | 91 | 90 | 0x90 |
TCON | 8F | 8E | 8D | 8C | 8B | 8A | 89 | 88 | 0x88 |
P0 | 87 | 86 | 85 | 84 | 83 | 82 | 81 | 80 | 0x80 |
Dabei ist jedoch die Notation Adresse.Bit einzuhalten, da die Angabe einer Adresse vom Assembler als absolute Adresse verstanden würde und nicht als Bit Adresse. Bei der Angabe MOV C, Adresse.Bit codiert der Assembler den Opcode für bitweises MOV 0xA2 und dann die Bit-Adresse.
Das Carry kann als Akkumulator bei Bit Operationen angesehen werden.
MOV C, P1.3 ; Wert des Bit 3 von Port 1 ins Carry
LJMP addr16
läßt sich also jede beliebige Adresse im Programmspeicher des 8051 erreichen.
AJMP addr11
SJMP rel
Die Sprungmarken werden dabei als Bezeichner mit nachgestelltem Doppelpunkt definiert und ohne Doppelpunkt referenziert.
label: . . SJMP label
Der intel Assembler asm51 erlaubt im Gegensatz zum as31 die Verwendung des Pseudo Mnemonics JMP. Der Assembler entscheidet dann selbst, welcher der drei Sprünge ausgeführt wird.
Bei Unterprogrammaufrufen ist es nicht sinnvoll einen eigenen Opcode für kurze Sprünge zu reservieren, es gibt daher nur ACALL und LCALL, keinen SCALL [15], [9], [2].
Auch die Ports können bitweise adressiert werden. Sie sind bidirektional, können also sowohl als Eingang, als auch als Ausgang dienen. Wenn ein Pin als Eingang benutzt werden soll, so muß eine Eins in das Bit des betreffenden Ports geschrieben werden. Dabei ist zu beachten, daß Port 0 im Gegensatz zu den anderen drei Ports Open drain Ausgänge hat, also bei Ausgabe einer Eins stromlos ist. Die anderen Ports besitzen interne Pullups, bei Port 0 muß man diese selbst ergänzen. Bei Benutzung von externem EPROM und/oder RAM werden jedoch ohnehin die Ports 0 und 2 als Adress-/Datenbus benutzt, stehen also zur Ausgabe nicht zur Verfügung. Einige Operationen lesen den Status des Latches am Port, andere geben den Pegel der Pins zurück. Die Operationen, die Werte vom Port lesen, verändern und zurückschreiben sind solche, die das Latch lesen. Dazu zählen die logischen Operationen ANL, ORL, XRL, CPL, sowie INC, DEC, DJNZ und die Bit-Operationen "MOV PX.Y, C", "CLR PX.Y", und "SETB PX.Y". Man nennt das read-modify-write feature. Ein einfaches "MOV var, PX" liest nur das Level der Portpins.
Welche Ereignisse aber können Interruptauslöser sein? Das legt die Hardware des Prozessors fest. Beim 8051 gibt es fünf Interruptquellen, beim 8052 sechs. Dazu gehören die externen Interrupts, also Pins des Prozessorchips, die Timer und der serielle Port. Werden die Pins P3.2 und P3.3, auch INT0 und INT1 genannt, auf low gelegt, so verzweigt der Prozessor an die Adressen 0x0003 bzw. 0x0013. Diese Adressen werden auch Interruptvektoren genannt. Auch die Timer lösen bei einem Zählerüberlauf einen Interrupt aus und bei Empfang eines Zeichens über die serielle Schnittstelle oder nach erfolgtem Senden eines Zeichens wird zum seriellen Interrupt verzweigt. Beim seriellen Interrupt muß in der service Routine anhand der Bits RI und TI entschieden werden, ob empfangen, oder erfolgreich gesendet wurde. Je nach Ausstattungsmerkmalen besitzt der Prozessor eine unterschiedliche Anzahl an Interrupts, so erklärt sich schnell das der 8051 nur fünf Interruptquellen, nämlich zwei externe, die Timer 0 und 1 und den seriellen Interrupt besitzt, beim 8052 aber auch der Timer2 Interrupts auslösen kann. Der Dallas 80C320 besitzt statt sechs Interrupts dreizehn. Die zusätzlichen Interrupts sind vier externe Interrupts und weitere von der zweiten seriellen Schnittstelle, vom Watchdog und Power fail. Eine Tabelle der Interruptvektoren findet sich im Anhang. Damit wirklich zur Interruptroutine gesprungen wird, muß nicht nur die Interruptbedingung eintreten, sondern auch der Interrupt eingeschaltet (enabled) sein. Das geschieht einerseits durch Setzen des globalen Interrupt enable Bits EA (enable all) im Register IE (interrupt enable) und dann durch Setzen des individuellen enable Bits, beim Timer0 interrupt beispielsweise das Bit ET0 (IE.1).
Beim Einschalten des Rechners beginnt der Prozessor mit der Programmabarbeitung an der Stelle 0x0000, d.h. an dieser Stelle muß sich bereits ein Programm befinden (Monitorprogramm). Das kann nur ein ROM oder EPROM sein. Kurz darüber liegen aber die Interruptvektoren, so daß auch diese im ROM liegen. Benutzerprogramme könnten also nie Interrupts benutzen. Hinzu kommt, daß zwischen den Vektoren nur wenige Bytes frei sind. Man schreibt daher üblicherweise ins ROM an diese Adressen LJMP's, die in die EPROM Emulation springen. Ein Ausschnitt aus PAULMON sieht folgendermaßen aus:
.EQU start,0x0000 ; EPROM start .EQU interrupt, 0xF300 ; interrupt mapping .ORG start+0x0B ; Timer 0 interrupt LJMP interrupt+0x0200 ; Jump to service Routine
Wenn also der Timer0 überläuft, so verzweigt der Prozessor ins EPROM an die Adresse 0x000B, an der der Befehl LJMP 0xF500 steht. Verwendet man die deutsche PAULMON Version für den 80C320 Prozessor, so steht diese Sequenz bereits im Speicher. Das folgende Programm INTRDEMO.A51, startet den Timer 0, ermöglicht den Interrupt und plaziert eine Interrupt service Routine an der Stelle interrupt+0x0200, die in diesem Fall beispielsweise die LED's blinken läßt. Das Programm zeigt in Kürze die Programmierung des 8255, eines Timers und eines Interrupts und einiges mehr, es lohnt sich also, ein wenig Zeit aufzuwenden um es zu verstehen.
; Ein paar Definitionen .EQU FlagReg, 0x7E .FLAG Linksflag, B.0 .EQU Muster, 0x7F .EQU Mod8255, 0x4003 ; 8255 Steuerregister .EQU PortA, 0x4000 ; Port A des 8255 .EQU PortB, 0x4001 ; ... .EQU PortC, 0x4002 .ORG 0x8000 ; Programmstart MOV dptr, #Mod8255 ; Adresse laden MOV A, #10001001b ; Ports A und B als Ausgang MOVX @dptr, A ; Steuerregister schreiben MOV Muster, #00000001b ; Start-LED Muster MOV TH0, #0x00 ; 65536*12=786432 Taktzyklen MOV TL0, #0x00 ; => Frequenz 30.5Hz MOV TMOD, #00000001b ; Timer0 16 Bit mode MOV TCON, #00010000b ; Timer0 starten MOV IE, #10000010b ; Bits EA und ET0 gesetzt RET ; Das war's schon ; ****************************************************************** ; Jetzt die Interrupt service Routine. .ORG 0xF500 ; Timer 0 Interrupt ; Da ein Interrupt immer auftreten kann, muessen alle benutzten ; Register durch PUSH gesichert werden PUSH PSW PUSH Acc PUSH B PUSH DPL PUSH DPH ; ============================ cut here ============================ ; Jetzt die eigentliche Routine. Sie laesst die 8 LED's der ; Prozessorplatine nach Art des Knight Rider blinken, d.h. eine ; LED laeuft wie ein Ping Pong Ball von links nach rechts und ; wieder zurueck. Fuer das Verstaendnis der Interruptprogrammierung ; ist die eigentliche Routine aber nicht wichtig. MOV B, FlagReg MOV A, Muster ; LED-Muster laden MOV C, Acc.7 ; erstes und ORL C, Acc.0 ; letztes Bit verodern JNC weiter JB Acc.7, clrl ; Linkes Ende => rechts SETB Linksflag ; andernfalls links rollen SJMP weiter clrl: CLR Linksflag weiter: JB Linksflag, links rechts: RR A ; Nach rechts schieben SJMP Ausgab links: RL A ; Nach links schieben Ausgab: MOV Muster, A ; Muster wieder speichern MOV dptr, #PortB ; Adresse Port B laden MOVX @dptr, A ; Port B schreiben MOV FlagReg, B ; ============================ cut here ============================ ; Die gesicherten Register wiederherstellen POP DPH POP DPL POP B POP Acc POP PSW RETI ; und zurueckspringen ; ******************************************************************
Nach Programmstart kann mit PAULMON ganz normal weitergearbeitet werden, die LED's blinken interruptgesteuert weiter. Zum Verständnis kann man einmal das RETI ändern in ein normales RET. Das Programm funktioniert dann nicht mehr. Zwischen den beiden Zeilen ''cut here'' kann eigentlich jede beliebige Routine stehen, die nur die Register A, B und DPTR benutzt. sonst müssen zusätzliche PUSH und POP eingefügt werden. Das PSW sollte immer gerettet werden, da man oft Befehle einfügt, die das Carry Flag C benutzen, das im PSW liegt, was leicht vergessen wird.
Zur Programmierung der seriellen Schnittstelle und Arithmetik sei hier auf Paulmon verwiesen.
comp.sys.intel comp.arch.embedded comp.robotics sci.electronics alt.comp.hardware.homebuiltAnd various FTP sites ..., 1995
Stück | Best. Nr. | Bezeichnung | Einzelp. | Preis |
---|---|---|---|---|
1 | - | DS80C320 DIL40 | 18.80 | 18.80 |
1 | - | 62256 CMOS SRAM | 8.91 | 8.91 |
1 | - | 74HCT573 | 1.15 | 1.15 |
1 | 150150 | 74HCT08 | -.95 | -.95 |
1 | 150398 | 74CHT138 | 1.25 | 1.25 |
2 | - | Dioden 1N4148 o.ä. | -.20 | -.20 |
1 | - | Taster für Reset | 2.50 | 2.50 |
1 | - | Quarz 24 MHz | 1.77 | 1.77 |
1 | 179345 | 2A 5V Spannungsregler | 1.95 | 1.95 |
1 | 528560 | Euro beschichtet Epoxy | 3.60 | 3.60 |
1 | 162051 | 27C128 EPROM | 7.95 | 7.95 |
1 | 181587 | 8255AP PIO | 6.30 | 6.30 |
8 | 146005 | LED, low current, rot | -.35 | 2.80 |
8 | 400289 | 1.8 k | -.15 | 1.20 |
1 | 403377 | 10k | -.15 | -.15 |
2 | 451673 | 22pF | -.30 | -.60 |
1 | - | Elko 10uF 16V | -.50 | -.50 |
1 | - | Elko 100uF 16V | -.50 | -.50 |
2 | 189588 | Sockel 40pol | -.90 | 1.80 |
2 | 189570 | Sockel 28pol | -.70 | 1.40 |
1 | - | Sockel 20pol | -.35 | -.35 |
1 | - | Sockel 16pol | -.35 | -.35 |
1 | 189510 | Sockel 14pol | -.30 | -.30 |
1 | - | Buchse 13 pol | 3.60 | 3.60 |
1 | - | Stecker 25 pol | 4.- | 4.- |
Code | Bytes | Zyklus | Mnemonic | Code | Bytes | Zyklus | Mnemonic |
---|---|---|---|---|---|---|---|
00 | 1 | 1 | NOP | 30 | 3 | 2 | JNB bitAdr, cAdr |
01 | 2 | 2 | AJMP cAdr | 31 | 2 | 2 | ACALL cAdr |
02 | 3 | 2 | LJMP cAdr | 32 | 1 | 2 | RETI |
03 | 1 | 1 | RR A | 33 | 1 | 1 | RLC A |
04 | 1 | 1 | INC A | 34 | 2 | 1 | ADDC A, #data |
05 | 2 | 1 | INC dAdr | 35 | 2 | 1 | ADDC A, dAdr |
06 | 1 | 1 | INC @R0 | 36 | 1 | 1 | ADDC A, @R0 |
07 | 1 | 1 | INC @R1 | 37 | 1 | 1 | ADDC A, @R1 |
08 | 1 | 1 | INC R0 | 38 | 1 | 1 | ADDC A, R0 |
09 | 1 | 1 | INC R1 | 39 | 1 | 1 | ADDC A, R1 |
0A | 1 | 1 | INC R2 | 3A | 1 | 1 | ADDC A, R2 |
0B | 1 | 1 | INC R3 | 3B | 1 | 1 | ADDC A, R3 |
0C | 1 | 1 | INC R4 | 3C | 1 | 1 | ADDC A, R4 |
0D | 1 | 1 | INC R5 | 3D | 1 | 1 | ADDC A, R5 |
0E | 1 | 1 | INC R6 | 3E | 1 | 1 | ADDC A, R6 |
0F | 1 | 1 | INC R7 | 3F | 1 | 1 | ADDC A, R7 |
10 | 3 | 2 | JBC bitAdr, cAdr | 40 | 2 | 2 | JC cAdr |
11 | 2 | 2 | ACALL cAdr | 41 | 2 | 2 | AJMP cAdr |
12 | 3 | 2 | LCALL cAdr | 42 | 2 | 1 | ORL dAdr, A |
13 | 1 | 1 | RRC A | 43 | 3 | 2 | ORL dAdr, #data |
14 | 1 | 1 | DEC A | 44 | 2 | 1 | ORL A, #data |
15 | 2 | 1 | DEC dAdr | 45 | 2 | 1 | ORL A, dAdr |
16 | 1 | 1 | DEC @R0 | 46 | 1 | 1 | ORL A, @R0 |
17 | 1 | 1 | DEC @R1 | 47 | 1 | 1 | ORL A, @R1 |
18 | 1 | 1 | DEC R0 | 48 | 1 | 1 | ORL A, R0 |
19 | 1 | 1 | DEC R1 | 49 | 1 | 1 | ORL A, R1 |
1A | 1 | 1 | DEC R2 | 4A | 1 | 1 | ORL A, R2 |
1B | 1 | 1 | DEC R3 | 4B | 1 | 1 | ORL A, R3 |
1C | 1 | 1 | DEC R4 | 4C | 1 | 1 | ORL A, R4 |
1D | 1 | 1 | DEC R5 | 4D | 1 | 1 | ORL A, R5 |
1E | 1 | 1 | DEC R6 | 4E | 1 | 1 | ORL A, R6 |
1F | 1 | 1 | DEC R7 | 4F | 1 | 1 | ORL A, R7 |
20 | 3 | 2 | JB bitAdr, cAdr | 50 | 2 | 2 | JNC cAdr |
21 | 2 | 2 | AJMP cAdr | 51 | 2 | 2 | ACALL cAdr |
22 | 1 | 2 | RET | 52 | 2 | 1 | ANL dAdr, A |
23 | 1 | 1 | RL A | 53 | 3 | 2 | ANL dAdr, #data |
24 | 2 | 1 | ADD A, #data | 54 | 2 | 1 | ANL A, #data |
25 | 2 | 1 | ADD A, dAdr | 55 | 2 | 1 | ANL A, dAdr |
26 | 1 | 1 | ADD A, @R0 | 56 | 1 | 1 | ANL A, @R0 |
27 | 1 | 1 | ADD A, @R1 | 57 | 1 | 1 | ANL A, @R1 |
28 | 1 | 1 | ADD A, R0 | 58 | 1 | 1 | ANL A, R0 |
29 | 1 | 1 | ADD A, R1 | 59 | 1 | 1 | ANL A, R1 |
2A | 1 | 1 | ADD A, R2 | 5A | 1 | 1 | ANL A, R2 |
2B | 1 | 1 | ADD A, R3 | 5B | 1 | 1 | ANL A, R3 |
2C | 1 | 1 | ADD A, R4 | 5C | 1 | 1 | ANL A, R4 |
2D | 1 | 1 | ADD A, R5 | 5D | 1 | 1 | ANL A, R5 |
2E | 1 | 1 | ADD A, R6 | 5E | 1 | 1 | ANL A, R6 |
2F | 1 | 1 | ADD A, R7 | 5F | 1 | 1 | ANL A, R7 |
Code | Bytes | Zyklus | Mnemonic | Code | Bytes | Zyklus | Mnemonic |
---|---|---|---|---|---|---|---|
60 | 2 | 2 | JZ cAdr | 90 | 3 | 2 | MOV DPTR, #data16 |
61 | 2 | 2 | AJMP cAdr | 91 | 2 | 2 | ACALL cAdr |
62 | 2 | 1 | XRL dAdr, A | 92 | 2 | 2 | MOV bitAdr, C |
63 | 3 | 2 | XRL dAdr, #data | 93 | 1 | 2 | MOVC A, @A+DPTR |
64 | 2 | 1 | XRL A, #data | 94 | 2 | 1 | SUBB A, #data |
65 | 2 | 1 | XRL A, dAdr | 95 | 2 | 1 | SUBB A, dAdr |
66 | 1 | 1 | XRL A, @R0 | 96 | 1 | 1 | SUBB A, @R0 |
67 | 1 | 1 | XRL A, @R1 | 97 | 1 | 1 | SUBB A, @R1 |
68 | 1 | 1 | XRL A, R0 | 98 | 1 | 1 | SUBB A, R0 |
69 | 1 | 1 | XRL A, R1 | 99 | 1 | 1 | SUBB A, R1 |
6A | 1 | 1 | XRL A, R2 | 9A | 1 | 1 | SUBB A, R2 |
6B | 1 | 1 | XRL A, R3 | 9B | 1 | 1 | SUBB A, R3 |
6C | 1 | 1 | XRL A, R4 | 9C | 1 | 1 | SUBB A, R4 |
6D | 1 | 1 | XRL A, R5 | 9D | 1 | 1 | SUBB A, R5 |
6E | 1 | 1 | XRL A, R6 | 9E | 1 | 1 | SUBB A, R6 |
6F | 1 | 1 | XRL A, R7 | 9F | 1 | 1 | SUBB A, R7 |
70 | 2 | 2 | JNZ cAdr | A0 | 2 | 2 | ORL C, /bitAdr |
71 | 2 | 2 | ACALL cAdr | A1 | 2 | 2 | AJMP cAdr |
72 | 2 | 2 | ORL C, bitAdr | A2 | 2 | 1 | MOV C, bitAdr |
73 | 1 | 2 | JMP @A+DPTR | A3 | 1 | 2 | INC DPTR |
74 | 2 | 1 | MOV A, #data | A4 | 1 | 4 | MUL AB |
75 | 3 | 2 | MOV dAdr, #data | A5 | - | - | reserved |
76 | 2 | 1 | MOV @R0, #data | A6 | 2 | 2 | MOV @R0, dAdr |
77 | 2 | 1 | MOV @R1, #data | A7 | 2 | 2 | MOV @R1, dAdr |
78 | 2 | 1 | MOV R0, #data | A8 | 2 | 2 | MOV R0, dAdr |
79 | 2 | 1 | MOV R1, #data | A9 | 2 | 2 | MOV R1, dAdr |
7A | 2 | 1 | MOV R2, #data | AA | 2 | 2 | MOV R2, dAdr |
7B | 2 | 1 | MOV R3, #data | AB | 2 | 2 | MOV R3, dAdr |
7C | 2 | 1 | MOV R4, #data | AC | 2 | 2 | MOV R4, dAdr |
7D | 2 | 1 | MOV R5, #data | AD | 2 | 2 | MOV R5, dAdr |
7E | 2 | 1 | MOV R6, #data | AE | 2 | 2 | MOV R6, dAdr |
7F | 2 | 1 | MOV R7, #data | AF | 2 | 2 | MOV R7, dAdr |
80 | 2 | 2 | SJMP cAdr | B0 | 2 | 2 | ANL C, /bitAdr |
81 | 2 | 2 | AJMP cAdr | B1 | 2 | 2 | ACALL cAdr |
82 | 2 | 2 | ANL C, bitAdr | B2 | 2 | 1 | CPL bitAdr |
83 | 1 | 2 | MOVC A, @A+PC | B3 | 1 | 1 | CPL C |
84 | 1 | 4 | DIV AB | B4 | 3 | 2 | CJNE A, #data, cAdr |
85 | 3 | 2 | MOV dAdr, dAdr | B5 | 3 | 2 | CJNE A, dAdr, cAdr |
86 | 2 | 2 | MOV dAdr, @R0 | B6 | 3 | 2 | CJNE @R0, #dat, cAdr |
87 | 2 | 2 | MOV dAdr, @R1 | B7 | 3 | 2 | CJNE @R1, #dat, cAdr |
88 | 2 | 2 | MOV dAdr, R0 | B8 | 3 | 2 | CJNE R0, #data, cAdr |
89 | 2 | 2 | MOV dAdr, R1 | B9 | 3 | 2 | CJNE R1, #data, cAdr |
8A | 2 | 2 | MOV dAdr, R2 | BA | 3 | 2 | CJNE R2, #data, cAdr |
8B | 2 | 2 | MOV dAdr, R3 | BB | 3 | 2 | CJNE R3, #data, cAdr |
8C | 2 | 2 | MOV dAdr, R4 | BC | 3 | 2 | CJNE R4, #data, cAdr |
8D | 2 | 2 | MOV dAdr, R5 | BD | 3 | 2 | CJNE R5, #data, cAdr |
8E | 2 | 2 | MOV dAdr, R6 | BE | 3 | 2 | CJNE R6, #data, cAdr |
8F | 2 | 2 | MOV dAdr, R7 | BF | 3 | 2 | CJNE R7, #data, cAdr |
Code | Bytes | Zyklus | Mnemonic | Code | Bytes | Zyklus | Mnemonic |
---|---|---|---|---|---|---|---|
C0 | 2 | 2 | PUSH dAdr | E0 | 1 | 2 | MOVX A, @DPTR |
C1 | 2 | 2 | AJMP cAdr | E1 | 2 | 2 | AJMP cAdr |
C2 | 2 | 1 | CLR bitAdr | E2 | 1 | 2 | MOVX A, @R0 |
C3 | 1 | 1 | CLR C | E3 | 1 | 2 | MOVX A, @R1 |
C4 | 1 | 1 | SWAP A | E4 | 1 | 1 | CLR A |
C5 | 2 | 1 | XCH A, dAdr | E5 | 2 | 1 | MOV A, dAdr |
C6 | 1 | 1 | XCH A, @R0 | E6 | 1 | 1 | MOV A, @R0 |
C7 | 1 | 1 | XCH A, @R1 | E7 | 1 | 1 | MOV A, @R1 |
C8 | 1 | 1 | XCH A, R0 | E8 | 1 | 1 | MOV A, R0 |
C9 | 1 | 1 | XCH A, R1 | E9 | 1 | 1 | MOV A, R1 |
CA | 1 | 1 | XCH A, R2 | EA | 1 | 1 | MOV A, R2 |
CB | 1 | 1 | XCH A, R3 | EB | 1 | 1 | MOV A, R3 |
CC | 1 | 1 | XCH A, R4 | EC | 1 | 1 | MOV A, R4 |
CD | 1 | 1 | XCH A, R5 | ED | 1 | 1 | MOV A, R5 |
CE | 1 | 1 | XCH A, R6 | EE | 1 | 1 | MOV A, R6 |
CF | 1 | 1 | XCH A, R7 | EF | 1 | 1 | MOV A, R7 |
D0 | 2 | 2 | POP dAdr | F0 | 1 | 2 | MOVX @DPTR, A |
D1 | 2 | 2 | ACALL cAdr | F1 | 2 | 2 | ACALL cAdr |
D2 | 2 | 1 | SETB bitAdr | F2 | 1 | 2 | MOVX @R0, A |
D3 | 1 | 1 | SETB C | F3 | 1 | 2 | MOVX @R1, A |
D4 | 1 | 1 | DA A | F4 | 1 | 1 | CPL A |
D5 | 2 | 2 | DJNZ dAdr, cAdr | F5 | 2 | 1 | MOV dAdr, A |
D6 | 1 | 1 | XCHD A, @R0 | F6 | 1 | 1 | MOV @R0, A |
D7 | 1 | 1 | XCHD A, @R1 | F7 | 1 | 1 | MOV @R1, A |
D8 | 2 | 2 | DJNZ R0, cAdr | F8 | 1 | 1 | MOV R0, A |
D9 | 2 | 2 | DJNZ R1, cAdr | F9 | 1 | 1 | MOV R1, A |
DA | 2 | 2 | DJNZ R2, cAdr | FA | 1 | 1 | MOV R2, A |
DB | 2 | 2 | DJNZ R3, cAdr | FB | 1 | 1 | MOV R3, A |
DC | 2 | 2 | DJNZ R4, cAdr | FC | 1 | 1 | MOV R4, A |
DD | 2 | 2 | DJNZ R5, cAdr | FD | 1 | 1 | MOV R5, A |
DE | 2 | 2 | DJNZ R6, cAdr | FE | 1 | 1 | MOV R6, A |
DF | 2 | 2 | DJNZ R7, cAdr | FF | 1 | 1 | MOV R7, A |
Mnemonic | Description | Byte | Osc. Period |
---|---|---|---|
ADD A,Rn | Add register to Accumulator | 1 | 4 |
ADD A,direct | Add direct byte to Accumulator | 2 | 8 |
ADD A,@Ri | Add indirect RAM to Accumulator | 1 | 4 |
ADD A,#data | Add immediate data to Accumulator | 2 | 8 |
ADDC A,Rn | Add register to Acc. with Carry | 1 | 4 |
ADDC A,direct | Add direct byte to Acc. with Carry | 2 | 8 |
ADDC A,@Ri | Add indirect RAM to Acc. with Carry | 1 | 4 |
ADDC A,#data | Add immediate data to Acc. / Carry | 2 | 8 |
SUBB A,Rn | Subtract reg. from Acc. with borrow | 1 | 4 |
SUBB A,direct | Sub. direct byte from Acc. / borrow | 2 | 8 |
SUBB A,@Ri | Sub. indirect RAM from Acc./ borrow | 1 | 4 |
SUBB A,#data | Sub. imm. data from Acc. / borrow | 2 | 8 |
INC A | Increment Accumulator | 1 | 4 |
INC Rn | Increment register | 1 | 4 |
INC direct | Increment direct byte | 2 | 8 |
INC @Ri | Increment indirect RAM | 1 | 4 |
INC DPTR | Increment Data Pointer | 1 | 12 |
DEC A | Decrement Accumulator | 1 | 4 |
DEC Rn | Decrement register | 1 | 4 |
DEC direct | Decrement direct byte | 2 | 8 |
DEC @Ri | Decrement indirect RAM | 1 | 4 |
MUL AB | Multiply A and B | 1 | 20 |
DIV AB | Divide A by B | 1 | 20 |
DA A | Decimal adjust Accumulator | 1 | 4 |
Mnemonic | Description | Byte | Osc. Period |
---|---|---|---|
ANL A,Rn | AND register to Accumulator | 1 | 4 |
ANL A,direct | AND direct byte to Accumulator | 2 | 8 |
ANL A,@Ri | AND indirect RAM to Accumulator | 1 | 4 |
ANL A,#data | AND immediate data to Accumulator | 2 | 8 |
ANL direct,A | AND Accumulator to direct byte | 2 | 8 |
ANL direct,#data | AND immediate data to direct byte | 3 | 12 |
ORL A,Rn | OR register to Accumulator | 1 | 4 |
ORL A,direct | OR direct byte to Accumulator | 2 | 8 |
ORL A,@Ri | OR indirect RAM to Accumulator | 1 | 4 |
ORL A,#data | OR immediate data to Accumulator | 2 | 8 |
ORL direct,A | OR Accumulator to direct byte | 2 | 8 |
ORL direct,#data | OR immediate data to direct byte | 3 | 12 |
XRL A,Rn | Exc-OR register to Accumulator | 1 | 4 |
XRL A,direct | Exc-OR direct byte to Accumulator | 2 | 8 |
XRL A,@Ri | Exc-OR indirect RAM to Accumulator | 1 | 4 |
XRL A,#data | Exc-OR immediate data to Acc. | 2 | 8 |
XRL direct,A | Exc-OR Accumulator to direct byte | 2 | 8 |
XRL direct,#data | Exc-OR imm. data to direct byte | 3 | 12 |
CLR A | Clear Accumulator | 1 | 4 |
CPL A | Complement Accumulator | 1 | 4 |
RL A | Rotate Accumulator left | 1 | 4 |
RLC A | Rotate Acc. left through Carry | 1 | 4 |
RR A | Rotate Accumulator right | 1 | 4 |
RRC A | Rotate A right through Carry flag | 1 | 4 |
SWAP A | Swap nibbles within the Accumulator | 1 | 4 |
Mnemonic | Description | Byte | Osc. Period |
---|---|---|---|
MOV A,Rn | Move register to Accumulator | 1 | 4 |
MOV A,direct | Move direct byte to Accumulator | 2 | 8 |
MOV A,@Ri | Move indirect RAM to Accumulator | 1 | 4 |
MOV A,#data | Move immediate data to Accumulator | 2 | 8 |
MOV Rn,A | Move Accumulator to register | 1 | 4 |
MOV Rn,direct | Move direct byte to register | 2 | 8 |
MOV Rn,#data | Move immediate data to register | 2 | 8 |
MOV direct,A | Move Accumulator to direct byte | 2 | 8 |
MOV direct,Rn | Move register to direct byte | 2 | 8 |
MOV direct,direct | Move direct byte to direct byte | 3 | 12 |
MOV direct,@Ri | Move indirect RAM to direct byte | 2 | 8 |
MOV direct,#data | Move immediate data to direct byte | 3 | 12 |
MOV @Ri,A | Move Accumulator to indirect RAM | 1 | 4 |
MOV @Ri,direct | Move direct byte to indirect RAM | 2 | 8 |
MOV @Ri,#data | Move immediate data to indirect RAM | 2 | 8 |
MOV DPTR,#data16 | Load Data Pointer with 16-bit const | 3 | 12 |
MOVC A,@A+DPTR | Move Code byte rel. to DPTR to Acc. | 1 | 12 |
MOVC A,@A+PC | Move Code byte rel. to PC to Acc. | 1 | 12 |
MOVX A,@Ri | Move Ext. RAM (8-bit addr.) to Acc. | 1 | 8-36 |
MOVX A,@DPTR | Move Ext. RAM (16-bit addr) to Acc. | 1 | 8-36 |
MOVX @Ri,A | Move Acc. to Ext. RAM (8-bit addr.) | 1 | 8-36 |
MOVX @DPTR,A | Move Acc. to Ext. RAM (16-bit addr) | 1 | 8-36 |
PUSH direct | Push direct byte onto stack | 2 | 8 |
POP direct | Pop direct byte from stack | 2 | 8 |
XCH A,Rn | Exchange register with Accumulator | 1 | 4 |
XCH A,direct | Exchange direct byte with Acc. | 2 | 8 |
XCH A,@Ri | Exchange indirect RAM with Acc. | 1 | 4 |
XCHD A,@Ri | Exchange low order digit indirect RAM with Accumulator | 1 | 4 |
Mnemonic | Description | Byte | Osc. Period |
---|---|---|---|
CLR C | Clear Carry | 1 | 4 |
CLR bit | Clear direct bit | 2 | 8 |
SETB C | Set Carry | 1 | 4 |
SETB bit | Set direct bit | 2 | 8 |
CPL C | Complement Carry | 1 | 4 |
CPL bit | Complement direct bit | 2 | 8 |
ANL C,bit | AND direct bit to Carry | 2 | 8 |
ANL C,/bit | AND complement of dir. bit to Carry | 2 | 8 |
ORL C,bit | OR direct bit to Carry | 2 | 8 |
ORL C,/bit | OR complement of dir. bit to Carry | 2 | 8 |
MOV C,bit | Move direct bit to Carry | 2 | 8 |
MOV bit,C | Move Carry to direct bit | 2 | 8 |
Mnemonic | Description | Byte | Osc. Period |
---|---|---|---|
ACALL addr11 | Absolute subroutine call | 2 | 12 |
LCALL addr16 | Long subroutine call | 3 | 16 |
RET | Return from subroutine | 1 | 16 |
RETI | Return from interrupt | 1 | 16 |
AJMP addr11 | Absolute jump | 2 | 12 |
LJMP addr16 | Long jump | 3 | 16 |
SJMP rel | Short jump (relative address) | 2 | 12 |
JMP @A+DPTR | Jump indirect relative to the DPTR | 1 | 12 |
JZ rel | Jump if Accumulator is zero | 2 | 12 |
JNZ rel | Jump if Accumulator is not zero | 2 | 12 |
DJNZ Rn,rel | Decr. register and jump if not zero | 2 | 12 |
DJNZ direct,rel | Decrement direct byte and jump if not zero | 3 | 16 |
CJNE A,direct,rel | Compare direct byte to Accumulator and jump if not equal | 3 | 16 |
CJNE A,#data,rel | Compare immediate data to Accumulator and jump if not equal | 3 | 16 |
CJNE Rn,#data,rel | Compare immediate data to register and jump if not equal | 3 | 16 |
CJNE @Ri,#data,rel | Compare immediate data to indirect RAM and jump if not equal | 3 | 16 |
JC rel | Jump if Carry is set | 2 | 12 |
JNC rel | Jump if Carry not set | 2 | 12 |
JB bit,rel | Jump if direct bit is set | 3 | 16 |
JNB bit,rel | Jump if direct bit is not set | 3 | 16 |
JBC bit,rel | Jump if dir. bit is set & clear bit | 3 | 16 |
NOP | No operation | 1 | 4 |
Symbol | Name | Address |
---|---|---|
* ACC | Accumulator | 0xE0 |
* B | B Register | 0xF0 |
* PSW | Program Status Word | 0xD0 |
SP | Stack Pointer | 0x81 |
DPTR | Data Pointer | (2 bytes) |
DPH | Data Pointer High Byte | 0x83 |
DPL | Data Pointer Low Byte | 0x82 |
! DPTR1 | Data Pointer 1 | (2 bytes) |
! DPH1 | Data Pointer 1 High Byte | 0x85 |
! DPL1 | Data Pointer 1 Low Byte | 0x84 |
! DPS | Data Pointer select | 0x86 |
* P0 | Port 0 | 0x80 |
* P1 | Port 1 | 0x90 |
* P2 | Port 2 | 0xA0 |
* P3 | Port 3 | 0xB0 |
* IP | Interrupt Priority Control | 0xB8 |
* IE | Interrupt Enable Control | 0xA8 |
* TCON | Timer/Counter Control | 0x88 |
TMOD | Timer/Counter Mode Control | 0x89 |
+* T2CON | Timer/Counter 2 Control | 0xC8 |
TH0 | Timer/Counter 0 High Byte | 0x8C |
TL0 | Timer/Counter 0 Low Byte | 0x8A |
TH1 | Timer/Counter 1 High Byte | 0x8D |
TL1 | Timer/Counter 1 Low Byte | 0x8B |
! CKCON | Clock control | 0x8E |
+ TH2 | Timer/Counter 2 High Byte | 0xCD |
+ TL2 | Timer/Counter 2 Low Byte | 0xCC |
+ RCAP2H | Timer/Counter 2 Capture Register High Byte | 0xCB |
+ RCAP2L | Timer/Counter 2 Capture Register Low Byte | 0xCA |
! EXIF | Extended interrupt flag Register | 0x91 |
* SCON | Serial Control | 0x98 |
SBUF | Serial Data Buffer | 0x99 |
! SCON1 | Serial Control 1 | 0xC0 |
! SBUF1 | Serial Data Buffer 1 | 0xC1 |
! TA | Timed access register | 0xC7 |
! WDCON | Watch Dog Control | 0xD8 |
! EIE | Extended Interrupt Enable | 0xE8 |
! EIP | Extended Interrupt Priority | 0xF8 |
PCON | Power Control | 0x87 |
bit | description | symbol |
---|---|---|
B7 | carry flag | CY |
B6 | auxiliary carry flag | AC |
B5 | general purpose status flag | F0 |
B4 | register bank select bit 1 | RS1 |
B3 | register bank select bit 0 | RS0 |
B2 | overflow flag | OV |
B1 | user definable | FL |
B0 | parity of accumulator | P |
RS1 | RS0 | Register Bank | Address |
---|---|---|---|
0 | 0 | 0 | 0x00..0x07 |
0 | 1 | 1 | 0x08..0x0F |
1 | 0 | 2 | 0x10..0x17 |
1 | 1 | 3 | 0x18..0x1F |
bit | description | symbol |
---|---|---|
B7-B1 | reserved | none |
B0 | Select DPRT0 or DPTR1 | SEL |
This register controls whether each Interrupt will jump to a corresponding Interrupt Service Routine. If an Interrupt is not enabled, software can still test for it's Interrupt Flag to validate whether or not an Interrupt would have happened. However, if the Interrupt is enabled the Interrupt flag will automatically provoke the corresponding Interrupt Service Routine.
bit | description | symbol |
---|---|---|
B7 | EA=0: disable all interrupts | EA |
B6 | enable serial port 1 interrupt | ES1 * |
B5 | enable timer 2 interrupt | ET2 * |
B4 | enable serial port interrupt | ES0 (ES) |
B3 | enable timer 1 overflow interrupt | ET1 |
B2 | enable external interrupt 1 | EX1 |
B1 | enable timer 0 overflow interrupt | ET0 |
B0 | enable external interrupt 0 | EX0 |
The 8051 works with two interrupt priority levels. The register IP defines the priority levels for each interrupt. A logical one selects the higher priority level. Interrupts cannot be interrupted by another interrupt of the same or lower priority. Yet it can be interrupted by an interrupt with higher priority.
bit | description | symbol |
---|---|---|
B7 | reserved | none |
B6 | priority of serial port1 interrupt | PS1 * |
B5 | priority of timer 2 interrupt | PT2 |
B4 | priority of serial port interrupt | PS0 (PS) |
B3 | priority of timer 1 interrupt | PT1 |
B2 | priority of external interrupt 1 | PX1 |
B1 | priority of timer 0 interrupt | PT0 |
B0 | priority of external interrupt 0 | PX0 |
The flags are set by hardware if overflow occurs. They are cleared by hardware when Processor vectors to interrupt routine. TR1 is used by software to turn on the timer. The trigger control bits select if interrupt occurs on falling edge or on low level (counter mode).
bit | description | symbol |
---|---|---|
B7 | timer 1 overflow flag | TF1 |
B6 | timer 1 run (on/off) control | TR1 |
B5 | timer 0 overflow flag | TF0 |
B4 | timer 0 run (on/off) control | TR0 |
B3 | interrupt 1 edge flag | IE1 |
B2 | interrupt 1 trigger control bit | IT1 |
B1 | interrupt 0 edge flag | IE0 |
B0 | interrupt 0 trigger control bit | IT0 |
bit | description | symbol |
---|---|---|
B7 | Timer 2 overflow flag | TF2 |
B6 | Timer 2 external flag set when either a capture or reload is caused by a negative transition on T2EX end EXEN=1. CPU vectors to Timer2 interrupt routine. Flag must be cleared by software | EXF2 |
B5 | Receive clock flag | RCLK |
B4 | Transmit clock flag | TCLK |
B3 | Timer 2 external enable flag | EXEN2 |
B2 | start/stop Timer2. 1 -> start | TR2 |
B1 | timer or counter select | C/T2 |
B0 | capture reload flag | CP/RL2 |
RCLK+ TCLK | CP/ RL2 | TR2 | Mode descr. |
---|---|---|---|
0 | 0 | 1 | 16 Bit auto reload |
0 | 1 | 1 | 16 Bit capture |
1 | X | 1 | baud rate generator |
X | X | 0 | (off) |
bit | description | symbol |
---|---|---|
B7 | 0 = t/c 1 enabled via TR1 1 = t/c enabled via INT1 + TR1 | GATE |
B6 | Type: timer = 0, counter = 1 | T/C |
B5 | operating modes t/c 1 | M1 |
B4 | operating modes t/c 1 | M0 |
B3 | 0 = t/c 0 enabled via TR0 1 = t/c enabled via INT0 + TR0 | GATE |
B2 | Type: timer = 0, counter = 1 | T/C |
B1 | operating modes t/c 0 | M1 |
B0 | operating modes t/c 0 | M0 |
Code | Mode descr. |
---|---|
00 | TLx serves as 5-bit prescaler |
01 | 16-bit t/c THx & TLx are cascaded |
10 | 8-bit auto reload, valTHx is loaded in TLx when TLx overflows |
11 | TL0 is an 8-bit t/c controlled by Timer 0 controlbits. TH0 is an 8-bit t/c controlled by Timer 1 controlbits. (two independent 8 Bit counters). t/c 1 stopped |
bit | description | symbol |
---|---|---|
B7 | Watchdog timing Bit 1 | WD1 |
B6 | Watchdog timing Bit 0 | WD0 |
B5 | Timer 2 mode. The original 8051 uses 12 clock per cycle scheme for timers. The 80C320 timers can be set to run at 4 clocks. | T2M |
B4 | Timer 1 mode | T1M |
B3 | Timer 0 mode | T0M |
B2 | Mode flag for RAM access | MD2 |
B1 | Mode flag for RAM access | MD1 |
B0 | Mode flag for RAM access | MD0 |
MD2 | MD1 | MD0 | Memory cycles | RD/WR strobe width in clocks | Strobe width @ 25 MHz |
---|---|---|---|---|---|
0 | 0 | 0 | 2 | 2 | 80ns |
0 | 0 | 1 | 3 (default) | 4 | 160ns |
0 | 1 | 0 | 4 | 8 | 320ns |
0 | 1 | 1 | 5 | 12 | 480ns |
1 | 0 | 0 | 6 | 16 | 640ns |
1 | 0 | 1 | 7 | 20 | 800ns |
1 | 1 | 0 | 8 | 24 | 960ns |
1 | 1 | 1 | 9 | 28 | 1120ns |
WD1 | WD0 | Interrupt time out | Time (@ 25 MHz) |
---|---|---|---|
0 | 0 | 2^17 clocks | 5.243ms |
0 | 1 | 2^20 clocks | 41.94ms |
1 | 0 | 2^23 clocks | 335.54ms |
1 | 1 | 2^26 clocks | 2684.35ms |
bit | description | symbol |
---|---|---|
B7 | Double baud rate bit | SMOD1 |
B6 | ? | POR |
B5 | Power fail interrupt enable | EPFI |
B4 | Power fail interrupt | PFI |
B3 | interrupt flag set when there are 512 clocks left until reset | WDIF |
B2 | flag is set when reset has occured | WTRF |
B1 | enable watchdog timer | EWT |
B0 | restart (clear) Watchdog | RWT |
MOV 0xC7, #0xAA MOV 0xC7, #0x55The hardware opens a two cycle window that allows software to modify one of the protected bits. If the instruction that seeks to modify the protected bit is not immediately proceeded by these instructions, the write will not take effect.
bit | description | symbol |
---|---|---|
B7 | reserved | none |
B6 | reserved | none |
B5 | reserved | none |
B4 | Enable Watch dog interrupt | EWDI |
B3 | enable external interrupt 5 | EX5 |
B2 | enable external interrupt 4 | EX4 |
B1 | enable external interrupt 3 | EX3 |
B0 | enable external interrupt 2 | EX2 |
bit | description | symbol |
---|---|---|
B7 | reserved | none |
B6 | reserved | none |
B5 | reserved | none |
B4 | priority of Watch dog interrupt | PWDI |
B3 | priority of external interrupt 5 | PX5 |
B2 | priority of external interrupt 4 | PX4 |
B1 | priority of external interrupt 3 | PX3 |
B0 | priority of external interrupt 2 | PX2 |
bit | description | symbol |
---|---|---|
B7 | interrupt 5 edge flag | IE5 |
B6 | interrupt 4 edge flag | IE4 |
B5 | interrupt 3 edge flag | IE3 |
B4 | interrupt 2 edge flag | IE2 |
B3 | reserved | none |
B2 | Ring mode flag set by hardware | RGMD |
B1 | Ring select. Come out of stop mode with ring osc. | RGSL |
B0 | Band gap reference enable during stop mode | BGS |
bit | description | symbol |
---|---|---|
B7 | serial port mode bit 0 | SM0 |
B6 | serial port mode bit 1 | SM1 |
B5 | enable multiprocessorfeature in modes 2 & 3, RI will not be activated if RB8=0 & SM2=1. In mode 1 RI will not be activated if stop bit was invalid & SM2=1. SM2 should be 0 in mode 0 | SM2 |
B4 | enable reception | REN |
B3 | in modes 2 & 3 9-th bit tx | TB8 |
B2 | in modes 2 & 3 9-th bit rx mode1 ; if SM2=0 RB8=stop bit value mode0 ; not used | RB8 |
B1 | Tx interrupt flag mode0 : set by 8-th bit time other modes : set by beginning of stop bit | TI |
B0 | Rx interrupt flag | RI |
SM0 | SM1 | Mode descr. | Baudrate |
---|---|---|---|
0 | 0 | 1: shift register | f_osc/12 |
0 | 1 | 2: 8-bit UART | variable |
1 | 0 | 3: 9-bit UART | f_osc/64 or f_osc/32 |
1 | 1 | 4: 9-bit UART | variable |
The 8051 follows the standard convention for numbering pins: Pin #1 is
indicated by "the dot," and numbering continues sequentially counter-clockwise
around the chip.
Der vom Crossassembler erzeugte Objektcode muß ins Zielsystem geladen werden.
Als Zielsystem dient entweder ein EPROM oder die EPROM Emulation eines
Einplatinencomputers oder aber ein Emulator oder Simulator. Üblich ist die
Übertragung des Objektfiles in hexadezimalem Format, eher selten als
binärfile. Es gibt verschiedene Standards, ein hex File abzulegen, die
wichtigsten sind das intel und das Motorola hex File Format, die von jedem
guten EPROM Brenner verstanden werden. Elektor und Tektronix haben ihre
eigenen Formate entwickelt.
Beim intel hex Format ist das erste Zeichen einer Zeile ein Doppelpunkt. Es
signalisiert den Start der Datenübertragung. Das folgende Byte gibt die Anzahl
der in dieser Zeile enthaltenen Code Bytes an. Danach folgt ein Wort (4
Ascii-Ziffern) mit der Adresse des ersten in dieser Zeile enthaltenen
Code-Bytes.
Das nachfolgende Byte gibt Über den Typ dieses Records Aufschluß:
Danach folgen soviele Code Bytes wie im 1. Byte angegeben. Das letzte Byte ist
eine PrÜfsumme, gebildet aus dem Zweierkomplement der Quersumme Über alle
Bytes dieser Zeile (ohne high Byte).
Beispiele:
Diese mcs-51 Dokumentation ist geschrieben und Copyright ©1996 Arnd Kobus.
Hiermit erlaube ich die Nutzung, Vervielfältigung und Veränderung
ohne Gebühr für private, nichtkommerzielle Nutzung, solange
die Copyrightnotiz, mein Name und diese Kopiererlaubnis und die Haftungsbestimmungen
in allen Kopien unverändert erscheint und die Veränderungen am Werk
namentlich gekennzeichnet werden.
Der Autor Arnd Kobus ist unter keinen Umständen verantwortlich für
Schäden, gleich welcher Art, ob finanziell oder persönlich, die durch die Benutzung
der präsentierten Information und Software ergeben und macht keine Aussage über
die Nützlichkeit und Richtigkeit der Information oder Brauchbarkeit zu irgendeinem Zweck.
Die Information wird in vorliegender Form zur Verfügung gestellt, jedoch tragen SIE,
der Benutzer allein die Risiken bei deren Benutzung.
Fragen, Kommentare, Kritik und Fehlermeldungen betreffend der vorgestellten
Information bitte an Arnd Kobus/
kobus@student.uni-kl.de.
Diese Seite ist
http://www.student.uni-kl.de/~kobus/8051doc.html
PCON - Power Control
The power control register is only available in CMOS versions. The highest bit
SMOD selects if the baud rate is divided by two (SMOD = 0) or not.
bit description symbol
B7 Double baud rate bit SMOD
B6 reserved none
B5 reserved none
B4 reserved none
B3 General purpose flag GF1
B2 General purpose flag GF0
B1 Power down bit PD (STOP)
B0 Idle mode bir IDL
Interrupts
Address description minimum
0x33 Power Fail interrupt 80C320
0x03 External interrupt 0 all
0x0B Timer 0 all
0x13 External interrupt 1 all
0x1B Timer 1 all
0x23 TI0 or RI0 from serial port 0 all
0x2B Timer 2 8052
0x3B TI1 or RI1 from serial port 1 80C320
0x43 External interrupt 2 80C320
0x4B External interrupt 3 80C320
0x53 External interrupt 4 80C320
0x5B External interrupt 5 80C320
0x63 Watchdog Time-out interrupt 80C320
8051 Pinout
Pin Name Description Type
1 P1.0 or T2 Port 1 Bit 0 or Timer 2 External Input Input/Output
2 P1.1 or T2CAP Port 1 Bit 1 or Timer 2 External Reload/Capture Input/Output
3 P1.2 Port 1 Bit 2 Input/Output
4 P1.3 Port 1 Bit 3 Input/Output
5 P1.4 Port 1 Bit 4 Input/Output
6 P1.5 Port 1 Bit 5 Input/Output
7 P1.6 Port 1 Bit 6 Input/Output
8 P1.7 Port 1 Bit 7 Input/Output
9 Reset System Reset Input
10 P3.0 or RXD Port 3 Bit 0 or Serial Receive Input/Output
11 P3.1 or TXD Port 3 Bit 1 or Serial Transmit Input/Output
12 P3.2 or INT0 Port 3 Bit 2 or External Interrupt 0 Input/Output
13 P3.3 or INT1 Port 3 Bit 3 or External Interrupt 1 Input/Output
14 P3.4 or T0 Port 3 Bit 4 or Timer 0 External Input Input/Output
15 P3.5 or T1 Port 3 Bit 5 or Timer 1 External Input Input/Output
16 P3.6 or WR Port 3 Bit 6 or Write Strobe for External Memory Input/Output
17 P3.7 or RD Port 3 Bit 7 or Read Strobe for External Memory Input/Output
18 XTAL1 Crystal Input Input
19 XTAL2 Crystal Output Output
20 VSS Circuit Ground Input
21 P2.0 or Addr8 Port 2 Bit 0 or Address bit 8 Input/Output
22 P2.1 or Addr9 Port 2 Bit 1 or Address bit 9 Input/Output
23 P2.2 or Addr10 Port 2 Bit 2 or Address bit 10 Input/Output
24 P2.3 or Addr11 Port 2 Bit 3 or Address bit 11 Input/Output
25 P2.4 or Addr12 Port 2 Bit 4 or Address bit 12 Input/Output
26 P2.5 or Addr13 Port 2 Bit 5 or Address bit 13 Input/Output
27 P2.6 or Addr14 Port 2 Bit 6 or Address bit 14 Input/Output
28 P2.7 or Addr15 Port 2 Bit 7 or Address bit 15 Input/Output
29 PSEN Program Store Enable (Read Strobe for External Code Memory) Output
30 ALE Address Latch Enable Output
31 EA External Access for Program Memory Input
32 P0.7 or Addr7/Data7 Port 0 Bit 7 or Address bit 7/Data bit 7 Input/Output
33 P0.6 or Addr6/Data6 Port 0 Bit 6 or Address bit 6/Data bit 6 Input/Output
34 P0.5 or Addr5/Data5 Port 0 Bit 5 or Address bit 5/Data bit 5 Input/Output
35 P0.4 or Addr4/Data4 Port 0 Bit 4 or Address bit 4/Data bit 4 Input/Output
36 P0.3 or Addr3/Data3 Port 0 Bit 3 or Address bit 3/Data bit 3 Input/Output
37 P0.2 or Addr2/Data2 Port 0 Bit 2 or Address bit 2/Data bit 2 Input/Output
38 P0.1 or Addr1/Data1 Port 0 Bit 1 or Address bit 1/Data bit 1 Input/Output
39 P0.0 or Addr0/Data0 Port 0 Bit 0 or Address bit 0/Data bit 0 Input/Output
40 VCC Supply Voltage Input
System Reset: Pin 9 is the System Reset trigger. A logical high on this
pin causes the chip to reset.
Write Strobe for External Memory: Whenever an instruction is executed
by the 8051 which requires that external data memory (RAM) be written to,
pin 16 is strobed to execute the write operation.
Read Strobe for External Memory: Whenever an instruction is executed
by the 8051 which requires that external data memory (RAM) be read from,
pin 17 is strobed to execute the write operation.
Program Store Enable: Whenever the 8051 needs to access External
Code Memory (to get an instruction, etc.), pin 29 is strobed to execute
the read operation.
Address Latch Enable: As one of the steps of accessing external
memory (both code and data memory), the 8051 stores the low-byte of the
address on pins 32 through 39. Whenever the low-byte of an address is
being stored on pins 32 through 39 the ALE pin will be strobed. Whenever
the ALE pin is strobed, the contents of pins 32 through 39 should be
"latched" with an Octal Latch.
External Access: Pin 31 is used to tell the 8051 whether to run code
from within the 8051 chip or to use External Code Memory (such as an
EPROM or whatever storage device is connected to External Code Memory).
If +5 Volts is applied to this pin, the 8051 will run the program stored
within the chip. Otherwise, External Code Memory will be used.
Note: It only makes sense to apply +5 Volts (i.e. run the program
stored within the 8051) if you are using some version of the 8051 that
actually allows you to store a program within the chip, like the 8051AH-BASIC.
A true 8051 has no on-chip code memory and it is undefined what happens if you tell
it to run the on-chip code if there isn't any.
Intel-HEX-Format
:03FF0A000204D21C = Zeile mit 03 Codebytes ab Adresse 0xFF0Ah: 02 04 D2
:00000001FF = Ende-Flag mit 0 Code-Bytes, Kennung 01
Copyright und Haftung