Nachdem sich der erste Teil dieser Serie mehr dem Handwerklichen (sprich Hardware) gewidmet hat, geht es nun ans Künstlerische: die Software. Das komplette Entwicklungssystem für die komfortable Programmentwicklung befindet sich auf einer PD-Disk, die Sie im Rahmen der ST-Computer PD, oder zusammen mit dem Komplett-Bausatz (Adresse am Schluß dieses Artikels) bestellen können. Natürlich können Ihnen diese paar Seiten nicht alle Kenntnisse über die Programmierung des Mikro-Controllers vermitteln. Aber in jedem Fall werden sie Ihnen einen guten Überblick bieten, und einige interessante Anregungen sind selbstverständlich auch dabei.
In der Hardware wurde der Mikro-Controller 80C31 verwendet. Er ist, wie schon im ersten Teil angedeutet, vollständig softwarekompatibel mit dem Vater der 80x1x-Familie, dem 8031. Schon zum Zeitpunkt der Entwicklung des 8031 (im Jahre 1980) war klar, daß weitere Familienmitglieder folgen würden. So zum Beispiel der in Europa weit verbreitete Mikro-Controller 80515 von Siemens: gegenüber dem 8031 besitzt er unter anderem 8 schnelle 8-Bit A/D-Wandler, mehr RAM, mehr Ports, mehr Timer etc. Trotzdem können alle diese zusätzlichen Funktionen mit jedem Standard-8031-Assembler genutzt werden (insbesondere auch mit dem MIDI8031 -Entwicklungssystem).
Der 8031 selbst weist die folgenden Leistungsmerkmale auf:
Im Gegensatz zu anderen Prozessoren, sind beim 8031 RAM und ROM/EPROM getrennt. Dadurch vergrößert sich der gesamte Adreßbereich auf 128 KB. Leider kann er aber normalerweise nur Programmbefehle im ROM/EPROM-Bereich ausführen. Um auch Programme in der Entwicklungsphase im RAM der MIDI8031-Hardware ablaufen lassen zu können, enthält MIDI8031 ein extra Gatter. Es sorgt dafür, daß bei bei allen Adressen über $8000 der Zugriff immer im RAM erfolgt! Auf dem Chip selbst befinden sich ebenfalls 256 adressierbare Bytes, wovon die unteren 128 das interne RAM darstellen. Die internen Adressen 128 bis 255 werden als ‘Special-Function-Registers ‘ (SF-Re-gister) bezeichnet. Wie Sie Bild 1 entnehmen können, sind auf dem 8031 nur wenige der SF-Register belegt. Die freien Plätze sind den Verwandten des 8031 Vorbehalten. Wahrscheinlich ahnen Sie es nun schon: Bei verwandten Mikro-Controller-Typen genügt es, die zusätzlichen SF-Register im Programm-Listing zu benennen. Jedes SF-Register hat einen Namen (zum Beispiel ‘PI’)- Um ihre Adressen müssen Sie sich daher beim Programmieren nicht im geringsten kümmern: das macht der Assembler. Auf jedes SF-Register kann also direkt per Namen zugegriffen werden.
Obwohl es in Bild 1 den Anschein hat, als ob alle SF-Register einträchtig nebeneinander lägen, dürfen Sie sich davon nicht täuschen lassen: Manche lassen sich lesen und beschreiben (wie etwa ‘B’), andere lassen sich nur lesen oder beschreiben, bei wieder anderen können Zugriffe darauf zu ‘Nebeneffekten’ führen, einige dürfen überhaupt nicht verwendet werden. Die detaillierte Beschreibung der einzelnen SF-Register würde den Rahmen dieser Serie sprengen. Beachten Sie dazu den Buchverweis am Ende diesen Teils der Serie.
Das interne RAM des 8031 ist mit 128 Bytes so groß, daß bei einfachen Anwendungsfällen sogar auf das externe RAM verzichtet werden kann (sowieso wird das externe RAM im großen und ganzen etwas ‘stiefmütterlich’ behandelt). In Bild 1 fallen im internen RAM die 4 Registerbänke R0-R7 auf: Die Register R0-R7 werden normalerweise zum Zählen, Indizieren, Rechnen verwendet. Mit einem einzigen Befehl kann bei Bedarf schnell zwischen den 4 Bänken hin- und hergeschaltet werden. Ein Anwendungsfall wären zum Beispiel 4 verschiedene, gleichzeitige Interrupts, von denen jeder seine eigene Bank verwendet.
Der zweite Block im internen RAM in Bild 1 ist als ‘Bit-adressierbares RAM’ bezeichnet: Da Mikro-Controller auch speziell für Steuerungszwecke entwickelt worden sind, treten oft binäre Zustände auf (etwa: 1 = Motor an, 0 = Motor aus). Also lassen sich 8 binäre Variablen in ein Byte packen. Insgesamt kann der 8031 256 verschieden Bits adressieren. Davon befinden sich 128 im ‘Bit-adressierbaren RAM’, die restlichen sind auf die SF-Register verteilt. Es kann nur auf einige der SF-Register bitweise zugegriffen werden. Diese sind in Bild 2 mit einem Stern (*) markiert. Bit-Adressen werden im 8031-Sourcecode durch Punkte gekennzeichnet: so bezeichnet etwa ‘ACC.7’ das 7. Bit von ACC, ‘$1F.0’ greift auf die niedrigste mögliche Bit-Adresse im RAM zu.
Das restliche interne RAM hat keine besonderen Eigenschaften. Bleibt nur noch, darauf hinzuweisen, daß sich beim 8031 der Stack ebenfalls im internen RAM befindet. Auf dem Stack werden hauptsächlich Rücksprungadressen von Unterprogrammen und Interrupts gespeichert. Wenn also in einem Programm der Stack verwendet wird, muß für ihn ebenfalls genügend internes RAM reserviert bleiben.
Insgesamt kennen die Mikro-Controller der 80x1x-Familie genau 255 Befehle [einer ($A5) ist nicht definiert]. Die meisten Befehle werden von einem mit 12MHz getaktetem Mikro-Controller in nur 1 Mikrosekunde abgearbeitet, für eine 8*8-Bit-Multiplikation oder eine 16/8-Bit-Divison benötigt er nur 4 Mikrosekunden. Für fast alle arithmetischen Berechnungen wird, wie auf anderen Prozessoren auch, ein Akkumulatorregister (Akku) verwendet (‘CPL A’). Der Akku hat aber auch eine SF-Adresse! Das heißt, auf dieses Register kann auf 2 Arten zugegriffen werden! Ein ähnlicher Fall liegt beim Carry-Bit vor: Das Carry-Bit wird gesetzt, wenn zum Beispiel bei Byte-Additionen ein Übertrag am höchsten Bit entsteht. Auf das Carry-Bit kann als Bit-Adresse PSW.7 (z. Bsp ‘CLR PSW.7’) und über Assembler-Befehle (wie z.B. ‘CLR C’ zugegriffen werden. Der Unterschied besteht lediglich darin, daß die erste Version ein Byte mehr Code benötigt.
Im großen und ganzen kann man die Assembler-Befehle des 8031 in 4 Gruppen einteilen:
Befehle zur Datenübertragung: Etwas gewöhnungsbedürftig ist die Syntax des ‘MOV’-Befehls: MOV [Ziel],[Quelle] (die Schreibweise beim 68000-Assembler ist genau umgekehrt). Also ‘MOV A,#100’ würde den Wert 100 in den Akku laden. Alle ‘MOV’-Befehle beziehen sich auf das interne RAM. Sollen Daten aus dem externen RAM oder vom ROM/EPROM angesprochen werden, gibt es dazu die Befehle ‘MOVX’ (externes RAM) und ‘MOVC’ (ROM/ EPROM). Meistens wird dabei das SF-Register ‘DPTR’ mit benötigt, das dann eine 16-Bit-Basisadresse enthält.
arithmetische Befehle: Addition, Subtraktion etc., wie sie auf jedem Prozessor vorhanden sind. Der 8031 unterstützt zum Beispiel auch BCD-Berechnungen (das sind Berechnungen im Dezimalsystem).
logische und boolsche Befehle: Logische Befehle sind beispielsweise Oder-Verknüpfungen oder Bit-Rotationen. Allerdings gibt es eine ganze Reihe von Befehlen, die nur jeweils 2 Bits miteinander verknüpfen, was für die oben erwähnten Steuerungsaufgäben von großem Vorteil sein kann.
Steuerbefehle: Der 8031 kennt eine Reihe ziemlich effektiver bedingter S prung-befehle. Schleifen lassen sich ähnlich einfach programmieren wie auf dem 68000: Der Schleifenzähler wird vom Sprungbefehl gleich mitverwaltet. Als Besonderheit kann der 8031 auch auf Bit-Bedingungen hin springen, beispielsweise einer gedrückten Taste an einem Portpin.
Die Adressierungsarten im einzelnen (aus Bild 3): ‘ml6’ ist eine Wort-Konstante, ‘m8’ eine Byte-Konstante, ‘d’ eine direkte Byte-Adresse (für interne Adressierung), ‘b’ ist eine der 256 Bit-Adressen, ist das Kennzeichen für indirekte Adessierung. Sprünge können über Byte-Distanz ‘ar’ in einem 2-KB Bereich ‘al 1' oder auf eine Wort-Adresse ‘al6’ erfolgen.
Da die eigentliche Domäne der Mikro-Controller vor allem der Einsatz bei Steuerungsaufgaben ist, soll diese kurze Erläuterung des 8031-Befehlssatzes genügen, da bei solchen Anwendungen andere Punkte mindestens ebenso wichtig sind. Zusammenfassend kann man sagen, daß der 8031 einen ausgewogenen, schnellen und auch sehr leicht erlernbaren Befehlssatz besitzt. Mit Sicherheit werden Sie bei der Programmierung eigener Anwendungen kaum Schwierigkeiten haben.
Eine weitere wichtige Sache bei Mikro-Controllern sind die Ports. Da jedes zusätzliche IC bei Mikro-Controller-Schaltungen die Kosten erhöht, wurden die Ports sehr universell und flexibel gehalten. Die Arbeitsrichtung jedes einzelnen Portpins ist frei wählbar (bidirektional). Einige Portpins besitzen zudem Mehrfachfunktionen, wie Sie auch dem Schaltplan in der vorigen Ausgabe entnehmen können: So kann etwa das Portpin P3.4 auch zum Zählen von Impulsen verwendet werden, indem einige SF-Register mit anderen Werten beschrieben werden. Für den ‘einfachen’ Gebrauch der maximal 14 nutzbaren Portpins von MIDI8031 (Sie können auch alle 16 Portpins nutzen, dann aber können nur Programme im EPROM ablaufen, das RAM muß entfernt werden) gilt das stark vereinfachte Modell der Schaltung eines Portpins nach Bild 4. Einfache Ein- und Ausgabeeinheiten können fast direkt an das jeweilige Pin angeschlossen werden. Nach einem Reset des 80C31 ist der Feldeffekt-Transistor (FET) zwischen Pin und Masse gesperrt, am Portpin wird die Spannung Vcc (+5V) gemessen. Wird der Port mit Null beschrieben, leitet der FET, und das Portpin geht fast auf Massepegel. Das Latch hat die Aufgabe, den Port-Zustand zwischenzuspeichern. Der FET kann einen Strom von einigen Milliampere (kurzzeitig bis zu etwa 20 Milliampere) aufnehmen, was zum Beispiel für eine LED problemlos reicht. Genauso einfach ist der Anschluß eines Schalters oder einer Taste, nur wird diese zwischen Portpin und Masse gelegt. Es ist allerdings wichtig zu wissen, daß bei Abfragen des Ports das Latch vorher mit Eins beschrieben werden muß, damit der FET sperrt. Bei Bild 4 handelt es sich, wie bereits erwähnt, um ein sehr einfaches Modell. In Wirklichkeit sind noch etliche weitere FETs in der Schaltung enthalten, zum Beispiel um bei Schreibzugriffen auf den Port steilflankige Signale zu erhalten. Bei Anschluß des Schalters sollte daher der Schutzwiderstand von 150Ω eingebaut werden. Er kann entfallen, wenn Sie sich sicher sind, daß bei geschlossenem Schalter der Port niemals mit einer Eins beschrieben wird.
In vielen Anwendungsbereichen werden analoge Spannungen benötigt (das könnte zum Beispiel die Fahrspannung Ihrer Modelleisenbahn sein). Zur Erzeugung analoger Spannungen mit einem 80C31 benötigen Sie lediglich ein Portpin. Per Software erzeugt der 80C31 ein sogenanntes pulsweitemoduliertes Signal (PWM). Die Frequenz der Impulse ist dabei konstant, es ändert sich lediglich ihre Breite. Das PWM-Signal wird durch die beiden Widerstände und den Kondensator geglättet. Allerdings ist diese sehr einfache Schaltung nicht besonders linear, was sich aber mit etwas Software korrigieren ließe. Ein einfacher Analog-Digital-Wandler kann nach dem gleichen, aber genau umgekehrten Schema gebaut werden: Mit einem Multivibrator wird ein rechteckförmiges Signal erzeugt und auf das Portpin geschaltet. Die Software kann nun die Breite der Impulse des Signals messen. Es gibt sogar spezielle (preiswerte) ICs, die mit hoher Linearität Spannungen in Frequenzen umsetzen (wie etwa den 74HC4046). Die Genauigkeit der Messung ist verblüffend: bei 200 Messungen pro Sekunde kann der 80C31 das Signal mit bis zu 12 Bits auflösen! In dem am Schluß dieses Artikels genannten Buch finden Sie einige gute Schaltungen rund um den 74HC4046.
Um Ihnen die Programmierung von 80xlx-Mikro-Controllern zu demonstrieren, ist auf dieser Seite ein Listing in 8031 - Assembler abgebildet. Es wurde mit dem Public-Domain- Entwicklungssystem geschrieben. Das Programm gibt im Morsealphabet einen Text aus, der im Listing in den letzten beiden Zeilen steht. Der Text wird optisch über die LED auf der Platine von MIDI8031 und akustisch als Tonsignal über das Portpin P1.0 ausgegeben. Um auch die einfache Verwendung eines Portpins als Eingang zu zeigen, läßt sich mit einer Taste zwischen P3.3 und GND die Tonhöhe des Morsesignals ändern. Natürlich können Sie das Programm erst exakt verstehen, wenn Sie sich etwas in die 8031-Programmierung eingearbeitet haben. Der Sinn des Listings liegt vielmehr darin. Ihnen zu zeigen, daß sich auch Mikro-Controller übersichtlich und effektiv programmieren lassen. Die vielen nützlichen Direktiven des Assemblers erleichtern die Programmentwicklung zusätzlich. Vom Editor des Entwicklungssystem aus läßt sich das Programm mit nur 2 Tastendrücken automatisch assemblieren und wahlweise starten oder debuggen. Es soll noch einmal ausdrücklich darauf hingewiesen werden, daß es sich beim Debugger des Entwicklungssystems um einen echten Source-Level-Debugger handelt! Selbstverständlich liegt dem Entwicklungssystem auch eine ausführliche Anleitung bei, sowie eine benutzerfreundliche Shell, Disassembler, Hardware-Testprogramme, etliche Demos und noch vieles mehr.
Als „Appetithappen" soll eines der Demoprogramme kurz vorgestellt werden: der Sprachsynthesizer ‘PHONEM’. Durch ein kompliziertes mathematisches Verfahren kann man aus digitalisierten Sprachsignalen einfache „Grundbausteine“ menschlicher Sprache isolieren. Diese Grundbausteine lassen sich bei nur geringem Speicherverbrauch in ein EPROM brennen. In einem 32KB-EPROM haben dabei problemlos Sprachdaten für mehrere Minuten Platz. Jeder normale 8031 ist nun schnell genug, das sehr gut verständliche Sprachsignal in Echtzeit wieder zu synthetisieren! Das Sprachsignal kann als PWM-Signal an einem Portpin abgenommen werden (zum Beispiel mit der Schaltung nach Bild 5). Die Anwendungsmöglichkeiten dieser fast reinen Software-Lösung sind enorm: Informationssysteme, Alarmanlagen, sprechende Meßgeräte... Außerdem Sourcecode von ‘PHONEM’ für die MIDI8031-Hardware befinden sich auf der Entwicklungssystem-Disk die umfangreiche Software zur Sprachanalyse mit einer speziellen Ankopplung an MIDI8031 sowie diverse Demodateien zur Sprachsynthese. Durch eine Spezialschaltung, die im Sourcecode von ‘PHONEM’ beschrieben ist, läßt sich ein Lautsprecher direkt in den Digital-Analog-Wandler mit einbauen, so daß nicht einmal mehr ein zusätzlicher Verstärker für das Sprachsignal notwendig wird!
Im nächsten und letzten Teil des MIDI8031-Mikro-Controller-Projekts werden Sie eine Schaltung finden, mit der jedes Portpin bis zu 20 Ampere schalten kann: den MIDI8031-Powerport. Um die Programmierung der 8031-Interrupts zu demonstrieren, wird MIDI8031 über den MIDI8031 -Powerport gleichzeitig zwei voneinander unabhängige Schrittmotoren steuern. MIDI8031 wird dabei die Befehle ausführen, die es von einem GFA-BASIC-Programm erhält.
Wie auch schon im letzten Teil erwähnt: Die MIDI8031-Hardware gibt es als Komplett-Bausatz, inklusive gebranntem EPROM und Entwicklungssystem-Disk. Sie können ihn für DM 85.-(Verrechnungsscheck), oder DM 89,- (Nachnahme) unter der Adresse des Autors bestellen.
Besteller des Bausatzes erwerben gleichzeitig das Recht, für MIDI8031 geeignete EPROMs zum Selbstkostenpreis brennen zu lassen! Wie das geht, steht in der Anleitung zum Entwicklungssystem.
Literaturempfehlung:
; ***********************************************
; * MIDI8051 - Mikrocontroller Entwicklungsboard
; * fuer ATARI ST/STE
; * (c)1992 by MAXON-Computer
; * Autor: Jürgen Piscol
; * MORSE: Diese kleine Demo sendet einen Text im
; * Morsealphabet. Das Signal wird auf der
; * eingebauten LED (optisch) und und am
; * Port P1.0 als Tonsignal ausgegeben.
; * Mit einer Taste zwischen P3.3 und GND
; * laesst sich die Morsetonhoehe aendern.
; *
; ***********************************************
.registers reg51.inc; 8031-Register-Defs.
; * Konstanten: Morsetempo und Tonhoehe:
tonh_o = 200 ; Die orig. Werte
speed_o = 200
; * Variablen (im internen RAM)
.var_org $30
tonh: .ds.b 1 ; 1 Byte fuer tonh
speed: .ds.b 1 ; 1 Byte fuer speed
stack: ; darueber ist Stack
.text_org $8000 ; RAM Entwicklungsboards
; * Hier geht's los:
go_0:
mov SP,#stack ; Stack ueber Vars,
mov tonh,#tonh_o ; Variablen init.
mov speed,#speed_o ; Originalpeed
go:
mov DPTR,#text ; Auf den Text zeigen
again:
movx A,@DPTR ; Zeich. ODPTR im XRAM
inc DPTR ; DPTR auf naechstes Byte
jz go ; '0': Wieder von vorne
jb P3.3,ton_ok ; Schalter am Port gedr.?
inc speed ; Ton hoeher, damit aber
dec tonh ; wg. Tempo konst.: Speed dekr.
mov A,#'e' ; ein 'e' ausgeben (.)
mov DPTR,#text ; und wieder von vorne...
ton_ok:
cjne A,#' ',was
mov R3,#16 ; Space: Laengere Pause
acall pause
sjmp again ; und von vorne
was: ; Es gibt was zu piepsen
acall holen ; Daten zum Buchst. holen
zeich:
setb P3.5 ; LED an
rlc A ; A shift, Bit7 in Carry
jnc kurz
acall on ; Lang: lang piepsen
acall on
kurz:
acall on ; Kurz: kurz piepsen
clr P3.5 ; LED aus
setb P1.0 ; Lautsp. aus (sparen!)
mov R3,#1
acall pause ; kurz warten
djnz R0,zeich ; Zeichen ausgeben
mov R3,#4 ; am Ende:
acall pause ; laengere Pause
sjmp again ; Bis Textende...
; * pause: Wartet in R2 angegebene Pausen
pause:
mov R2,speed
?p1:
mov R1,tonh ; Timing wie 'on:'
djnz R1,1 ; Inner Warteschleife
djnz R2,?p1
djnz R3,pause ; Aeussere Warteschl.
ret
; * on: Sound piepen, kurz warten
on:
mov R2,speed ; 'speed' mal
?o1: ; '?': Verstecktes Label
cpl P1.0 ; Lautsprecher AN/AUS
mov R1,tonh ; tonhoehe
djnz R1,1 ; Inner Warteschleife
djnz R2,?o1 ; Aeussere Warteschl.
ret
; * Holen A: Lang/Kurz's, R0: Anzahl Bits
holen:
add A,#-'a' ; A=A-'a'
rl A ; A=2*A
mov R0,A ; A merken
add A,#alphabet-?hl+1 ; Offs, zur Tab.
move A,@A+PC ; Anz. Bits holen
?h1:
xch A,R0 ; A/R0 vertausch,
add A,#alphabet-?h2 ; R0: Anzahl Bits
move A,@A+PC ; A: Muster
?h2:
ret
alphabet:
; * Aufb.: 1.) 1/0: lang/kurz, 2.) Anz. Bits
.dc.b %01000000,2 ; 'a' .-
.dc.b %10000000,4 ; 'b' -...
.dc.b %10100000,4 ; 'c' -.-.
.dc.b %10000000,3 ; ‘d' -..
.dc.b %00000000,1 ; 'e' .
.dc.b %00100000,4 ; 'f' ..-.
.dc.b %11000000,3 ; 'g' --.
.dc.b %00000000,4 ; 'h' ....
.dc.b %00000000,3 ; 'i ..
.dc.b %01110000,4 ; 'j' .---
.dc.b %10100000,3 ; 'k' -.-
.dc.b %01000000,4 ; 'l' .-..
.dc.b %11000000,2 ; 'm' --
.dc.b %10000000,2 ; 'n' -.
.dc.b %11100000,3 ; ’o' ---
.dc.b %01100000,4 ; 'p' .--.
.dc.b %11010000,4 ; 'q' --.-
.dc.b %10100000,3 ; 'r' -.-
.dc.b %00000000,3 ; 's' ...
.dc.b %10000000,1 ; 't' -
.dc.b %00100000,3 ; 'u' ..-
.dc.b %00100000,4 ; 'v' ...-
.dc.b %01100000,3 ; 'w' .--
.dc.b %10010000,4 ; 'x' -..-
.dc.b %10110000,4 ; ’y' -.--
.dc.b %11000000,4 ; 'z' --..
; * Der Morsetext (nur Kleinbuchstaben und
;* 'Space', keine Zahlen!)
text:
.dc.b "hallo user hier morst dein "
.dc.b "mikrocontroller ",0