Quellen
Allgemeines
Speicherzellen
Flags
Schreibregeln
Assembler-Befehle
weiter
zum
erweiterten Befehlssatz
weiter
zu
'Spezial-Befehlen'
weiter
zu
'Pseudo-Befehlen'
Befehlsübersicht
ADDLW , ADDWF , ANDLW , ANDWF , BCF , BSF , BTFSC , BTFSS , CALL , CLRF , CLRW , CLRWDT , COMF
DECF , DECFSZ , GOTO , INCF , INCFSZ , IORLW , IORWF , MOVF , MOVLW , MOVWF , NOP
RETFIE , RETLW
, RETURN , RLF , RRF
, SLEEP , SUBLW ,
SUBWF
, SWAPF , XORLW ,
XORWF
Befehlsübersicht nach Gruppen
Kopierbefehle
(MOV...)
Löschbefehle
(CLR...)
Setzen und Löschen
einzelner Bits, Bitverschiebungen, Bitvertauschungen
(BSF, BCF,
RLF,
RRF, SWAPF)
Aritmetische
Operationen
(ADD.., SUB.., COM..., AND..., IOR..., XOR... )
Increment und
Decrement
(INC... und DEC...)
Steuerbefehle und
Anderes
(NOP, BTFSC, BTFSS, GOTO, CALL, RETURN, RETLW, RETFIE,
SLEEP,
CLRWDT)
Jede Sekundärliteratur, also jedes Buch jeder Zeitschriftenartikel und z.B. meine Homepage sind naturgemäß fehlerträchtiger als das Orginal.
Trotzdem möchte ich nachfolgend in deutsch die Befehle des PIC erläutern. Wer mir guten Gewissens ein tolles deutsches Buch zu diesem Thema empfehlen kann, soll das gern per eMail tun. Ich bin gern bereit an dieser Stelle gute Sekundärliteratur zu erwähnen.
Es gibt Ein-Adressbefehle und Zwei-Adressbefehle. Ein Ein-Adressbefehl bezieht sich nur auf das Arbeitsregister oder nur auf eine Speicherzelle. Ein Beispiel hierfür ist der Löschbefehl, der eine Speicherzelle oder W auf den Wert 0 setzt. Zwei-Adressbefehle arbeiten immer mit dem Arbeitsregister und einer Speicherzelle. Ein Beispiel ist der MOV-Befehl, der den Wert einer Speicherzelle in das Arbeitsregister kopiert (oder umgekehrt).
Somit ist es nicht möglich, den Wert einer Speicherzelle unter Umgehung von W direkt in eine andere Speicherzelle zu kopieren. Hier muss der Wert zunächst aus der Speicherzelle nach W kopiert werden, um anschließend von W in die andere Speicherzelle kopiert zu werden. Dafür werden also zwei Befehle benötigt.
Zu den Zwei-Adressbefehlen gehören auch die "literal"-Befehle, das sind Befehle mit Zahlen. Hier ersetzt ein fester Zahlenwert die Speicherzelle. So kann man z.B. eine Zahl in das Arbeitsregister laden, oder eine Zahl zum Arbeitsregister dazuaddieren. Der Zahlenwert ist dann Teil des Befehlscodes, und muss nicht vorher in einer Speicherzelle stehen. Literal-Befehle arbeiten immer nur mit dem Arbeitsregister zusammen. Man kann also keine Zahl direkt in eine Speicherzelle laden, sondern nur in das Arbeitsregister, von dem es mit einem weiteren Zwei-Adressbefehl (MOV) in die Speicherzelle kopiert werden muss.
Für eine normale Addition nach dem Muster a+b=c würde man eigentlich drei Adressen benötigen (je eine für a, b und c) solche Befehle gibt es aber nicht. Auch Additionen und Subtraktionen sind Zwei-Adressbefehle. Der Wert aus dem Arbeitsregister W wird zunächst mit dem Wert aus einer Speicherzelle addiert. Die resultierende Summe wird dann (je nach Befehl) ins Arbeitsregister oder in die selbe Speicherzelle geschrieben. Einer der beiden Ausgangswerte wird dabei also vernichtet. ( a := a+b )
Multiplikation, Division oder komplizierteres gibt es als Assemblerbefehl gar nicht. Benötigt man so eine Operation, muss man auf ein Unterprogramm zurückgreifen, das diese Funktionen als Algoritmus realisiert. Solche Algoritmen gibt es aber schon fertig z.B. bei Microchip.
Das kling alles nach
einer
Beschränkung auf ein Minimum, und das war auch die Idee der
Designer.
Der PIC ist ein RISC-Prozessor, der nur über einen minimalen
Befehlsvorrat
verfügt. Das macht den Chip schnell und billig. Gerade einmal
35
unterschiedliche
Befehle muss man als Programmierer kennen, mehr gibt es
nämlich
nicht.
Die Grafik zeigt den
möglichen
Datenfluss im Prozessor bei einem Zweiadressbefehl. Die zwei
Eingänge
der ALU ("Rechenzentrale" des Chip) werden entweder von einer
Zahl (k)
und W oder von W oder einer Speicherzelle gespeist. Das
steuert ein
"input
swich", der bei allen Befehlen der Form "...LW"
(literal-Befehl) in der
linken und bei "...WF"-Befehlen in der rechten Position steht.
Das Resultat der
Operation
geht aus der ALU über den "output switch" in eine
Speicherzelle
oder
zurück in W. Dieser "output switch" wird vom Wert des Bits "d"
gesteuert.
Welche Speicherzelle genau in die Operation einbezogen ist,
steuern der
"f-read" und "f-write switch". Beide stehen in der selben
Position, die
durch den Wert "f" vorgegeben ist.
"k", "d", "f" sowie
"..LW"
und "..WF" stammen aus dem Befehl, den der Prozessor gerade
abarbeitet.
Der Befehl enthält darüberhinaus noch die Art der
mathematischen
Operation (Addition, Subtraktion ...) die die ALU ausführen
soll.
In der momentanen Schalterstellung werden die Werte aus W und der Speicherzelle 01h miteinander verknüpft (z.B. addiert). Das Resultat wird wieder in der Speicherzelle 01h gespeichert.
Viele dieser
Speicherzelle
dienen nur der Speicherung von 1-Byte Daten. Andere werden zur
Steuerung
des Prozessors benutzt. Als reine Speicherzellen werden im
16F84 die
Zellen
mit den Adressen 0Ch bis 4Fh und 8Ch bis CFh verwendet. In
Wirklichkeit
verbergen sich hinter diesen zwei Adressgruppen die selben
Speicherzellen.
Die Zelle mit der Adresse 0Ch hat nämlich auch die Adresse
8Ch,
die
Zelle 0Dh kann auch mit 8Dh addressiert werden u.s.w. Somit
stehen uns
68 freie Speicherzellen zur Verfügung.
In größeren
PICs
hat jede Bank eigene Speicherzellen. Im 16F84 sind nur die zur
Steuerung
des PIC benütigten Speicherzellen 00h-0Bh und 80h bis 8Bh in
den
beiden
Bänken verschieden.
Die 68 Byte nehmen
sich
neben
den mehrere 100MByte großen Hauptspeichern moderner PCs recht
bescheiden
aus, aber für viele Zwecke reicht das aus.
Von 00h bis 0Bh und
80h
bis
8Bh liegen Speicherzellen, die zur Steuerung des Prozessors
verwendet
weren.
Diese Steuerregister werden wie normale Speicherzellen
beschrieben
und gelesen. Ihre Funktionen sind im Datenblatt des PIC
erläutert.
Da ihre Addressierung mit Hilfe der hexadezimalen Adresse
umständlich
ist (wer kann sich schon die ganzen Zahlen merken) sind für
die
Steuerregister
leicht zu merkende Aliasnamen eingeführt worden. Die Zuordnung
der
Aliasnamen zu den physischen Adressen steht im der
*.INC-Datei, die
für
den PIC16F84 z.B. P16f84.INC heißt. Um die Aliasnamen
verwenden
zu
können, muss im Assemblerprogram das INC eingebunden werden.
Das geschieht mit folgender Zeile am Anfang des Programms:
#include
<P16f84.INC>
Auch für die
einfachen
Speicherzellen kann man beliebige Aliasnamen festlegen. Dazu
dient im
Assemblerprogramm
der EQU-Befehl. Das ist eigentlich gar kein richtiger Befehl,
sondern
nur
ein Hinweis für den Assembler, das in Zukunft eine bestimmte
Speicherzelle
mit einem bestimmten Namen addressiert wird:
Temp
Equ
0x10
Diese Zeile legt für
die Speicherzelle mit der Adresse 10h (hier Schreibweise 0x10)
den
neuen
Namen Temp fest. Man muss bei diesen Namen übrigens die
Groß-
und Kleinschreibung beachten!
bit 0 : Das Carry-Bit
Mit seiner 8-Bit
Datenbreite
kann der PIC (ohne spezielle Algoritmen) nur mit Zahlen von 0
bis 255
rechnen.
Wird der Wert 255 überschritten, so fängt der PIC wieder bei
0 an. So ergibt die Berechnung 255+1 das lustige Ergebnis 0
und 250+20
ergibt 14. Allerdings fällt dem PIC dieses Überlaufen auf,
und
er setzt in diesem Fall das Carry-Bit auf 1. Bei einer
Addition ohne
Überlauf
bleibt das Carry-Bit dagegen auf 0.
ACHTUNG: Bei einer
Subtraktion
verhält sich das Carry-Bit genau verkehrt herum. 20-5=15 setzt
Carry
auf 1 aber 20-25=251 löscht das Carry-Flag.
bit 2 : Das Zero-Bit
Ergibt eine Operation
zufällig
genau Null, so wird das Zero-Bit auf 1 gesetzt. Ergibt die
Operation
ein
anderes Ergebnis, so geht das Zero-Bit auf 0.
Nicht alle Operationen, von denen man es erwarten würde, beeinflussen die Flags. So beeinflusst der INCF-Befehl, der den Inhalt einer Speicherzelle um 1 erhöht, zwar das Zero-Bit, aber nicht das Carry-Bit. In der unten folgenden Beschreibung der einzelnen Befehle sind die beeinflussten Flags jeweils aufgelistet.
f | eine Speicherzelle |
d | Ergebins wird
gespeichert
in: d=0: Arbeitsregister W d=1: Speicherzelle |
W | das Arbeitsregister |
k | ein Zahlenwert von 0 ... 255 (bei CALL und GOTO: 0..2047) |
b | ein Zahlenwert von 0 bis 7 |
Mit MOV-Befehlen
werden
Werte
im Prozessor "transportiert" also von einer Speicherzelle oder
dem
Arbeitsregister
in eine andere Speicherzelle kopiert. Der Begriff "kopieren"
ist dabei
genauer als das englische "move" was bewegen bedeuten würde.
Die
Speicherzelle,
aus der der Wert kommt behält diesen Wert nämlich beim
MOV-Befehl
unverändert bei, und eine Kopie ihres Inhalts wird in
der
Ziel-Speicherzelle
angelegt.
Mit dem MOVLW-Befehl
lassen
sich feste Zahlenwerte in die Speicherzellen bringen.
MOVLW | Kopiere einen Zahl (k) nach W |
Syntax: | MOVLW k |
Bedeutung: | Die Zahl k wird in das Arbeitsregisters W geschrieben |
Beispiel: | MOVLW 5 ; Der Wert 5 wird in das Arbeitsregister geschrieben |
Mit Löschbefehlen
lassen
sich Speicherzellen oder das Arbeitsregister auf 0 setzen.
Dabei wird
das
Zero-Flag gesetzt.
CLRF | Lösche die Speicherzelle f |
Syntax: | CLRF f |
Bedeutung: | In die Speicherzelle f wird mit der Wert 0 geschrieben. |
Beispiel: | CLRF PORTA ;In das Register PORTA wird 0 geschrieben |
Flags: | Z=1 |
CLRW | Lösche W |
Syntax: | CLRW |
Bedeutung: | Das Arbeitsregisters W wird mit 0 beschrieben |
Beispiel: | CLRW ;In das Arbeitsregister wird 0 geschrieben |
Flags: | Z=1 |
Setzen und Löschen einzelner Bits, Bitverschiebungen, Bitvertauschungen (BSF, BCF, RLF, RRF, SWAPF)
Mit den BSF und
BCF-Befehlen
lassen sich einzelne Bits in einer beliebigen Speicherzelle
auf 1 oder
0 stellen. Dabei werden Flags nicht beeinflusst.
Die Bits innerhalb
einer
8-Bit-Speicherzelle tragen die Nummern 0 bis 7, wobei Bit Nr.
0 den
kleinsten
Wert hat (LSB = 1) während Bit Nr.7 den höchsten Wert besitzt
(MSB = 128). Einzelne Bits im Arbeitsregister W lassen sich
nicht
direkt
setzen.
Aritmetische Operationen (ADD.., SUB.., COM..., AND..., IOR..., XOR... )
Das sind die Befehle
zur
"Datenverarbeitung". Hier wird also gerechnet.
ADDLW | Das Arbeitsregister mit einer Zahl addieren |
Syntax: | ADDLW k |
Bedeutung: | Der Wert von W wird um k erhöht. |
Beispiel: | ADDLW 5 ; Der Wert von w wird um 5 erhöht. |
Flags: | C, DC, Z |
Increment und Decrement (INC... und DEC...)
Increment-
und
Decrement-Befehle
erhöhen bzw. verringern den Wert einer
Speicherzelle
oder des Arbeitsregisters jeweils um 1. Sie eignen sich damit
zum
Aufbau
von Zählschleifen. Läuft eine Speicherzelle beim
Incrementieren
über (255+1=0) oder beim Decrementieren unter (0-1=255) wird
das
Carry-Flag
nicht gesetzt. Ist das Ergebnis von Increment oder Decrement
aber 0
(255+1=0
oder 1-1=0), so wird das Zero-Flag gesetzt.
Eine Besondere Form
der
DEC...
und INC...-Befehle beinhaltet einen relativen Sprung: Falls
das
Ergebnis
der Incrementierung oder Decrementierung 0 ist, wird der
folgende
Befehl
übersprungen. Damit lassen sich einfach Schleifen aufbauen,
die
eine
bestimmte Anzahl von Zyklen durchlaufen werden müssen. Da die
Auswertung
des Null-Zustandes schon intern erfolgt, wird das eigentliche
Zero-Flag
nicht
beeinflusst.
Beispiel für eine Programmschleife, die 5 Mal durchlaufen wird:
MOVLW
5 ; 5 ins
Arbeitsregister
laden
MOVWF
0x20 ; die 5 wird in die Speicherzelle
0x20
kopiert
LOOP
;
eine
Einsprungmarke
; weitere Befehle in
der
Schleife
; können hier
eingefügt
werden
DECFSZ
0x20,1
; der Wert in der Speicherzelle 20h wird um 1 verringert
GOTO
LOOP ; Sprung zur Marke LOOP
nächster Befehl
Die ersten beiden
Zeilen
sin Vorbereitung. Von "LOOP" bis "GOTO LOOP" reicht die
Schleife.
Der DECFSZ-Befehl
wird
immer
am Schleifenende ausgeführt. Ist das Ergebnis nicht 0 (sondern
4,
3, 2 oder schließlich 1), so wird der darauf folgende "GOTO
LOOP"-Befehl
ausgeführt, und der Prozessor macht ab er oben stehenden
LOOP-Marke
weiter. Beim fünften Mal ist das Ergebnis des DECFSZ-Befehle
Null,
und der folgende Befehl wird ignoriert. Der GOTO-Befehl wird
also nicht
ausgeführt, und das Programm wird mit den Befehlen nach der
GOTO-Zile
fortgesetzt.
Steuerbefehle und Anderes (NOP, BTFSC, BTFSS, GOTO, CALL, RETURN, RETLW, RETFIE, SLEEP, CLRWDT)
Der NOP-Befehl tut
gar
nichts
(no operation)
NOP | Einen Takt lang gar nichts tun |
Syntax: | NOP |
Bedeutung: | Der Prozessor legt für einen Arbeitszyklus eine Pause ein |
Beispiel: | NOP ; nichts ändert sich |
Flags: | keine |
Die Bittestbefehle
(BTF..)
sind bedingte Sprünge. In Abhängigkeit vom Wert eines
beliebigen
Bits einer beliebigen Speicherzelle wird der auf diesen Befehl
folgende
Befehl ausgeführt oder übergangen. Ist dieser (bedingt
ausgeführte)
Befehl ein Sprungbefehl (GOTO), ergeben die beiden Befehle
zusammen
einen
bedingten Sprung..
Mit den
Bittestbefehlen
werden in der Regel Sprünge in Abhängigkeit von den Flags
realisiert.
Die Flags sind einzelne Bits in der Speicherzelle mit dem
Bezeichner
STATUS
(Speicherzelle 0x03 oder 03h). Das Zero-Bit ist dort das Bit
Nr. 2 und
das Carry-Flag ist das Bit Nr. 0 .
Die addressierung des
Zero-Flag
wäre demzufolge "STATUS,2" und des Carry-Flag "STATUS,0". Um
das
zu
vereinfachen, wurden für 0 und 2 die Bezeichner C und Z
eingeführt.
Damit ist das Zero-Flag mit "STATUS,Z" und das
Carry-Flag mit
"STATUS,C"
zu addressieren.
Am Ende eines
Unterprogramms
kehr man mit RETURN und RETLW autiomatisch zu der Stelle im
Hauptprogramm
zurück, von der das Unterprogramm gerufen wurde.
RETLW setzt dabei W
auf
einen bestimmten Wert. Falls ein Unterprogramm mehrere
mögliche
"Enden"
hat, kann man so leicht erkennen, welchen Ausgang das
Unterprogramm
genommen
hat.
RETFIE wird nur
benötigt,
wenn man mit Interrupts arbeitet.
Der Sleep-Befehl
versetzt
den Prozessor in den stromsparenden stand-by-Mode.
Durch die einige
bestimmte
Interrupts
wird der PIC wieder geweckt. Falls das zum Interrupt
zugehörige
Interrupte-Enable-Bit
gesetzt ist, läuft der PIC einfach im Programm weiter. Ist
auch
noch
das GIE-Bit gesetzt, wird zusätzlich noch die
Interruptbehandlungsroutine
aufgerufen.
CLRWDT ist nur
nötig,
wenn man den Watch-Dog-Timer
nutzt.
Autor: sprut
erstellt: 30.11.2001
letzte Änderung: 26.04.2015