Inhaltsverzeichnis
Programmsteuerung
Mnemonic | Code | short description | Beschreibung |
---|---|---|---|
NOP | 00 | No Operation | es wird nichts gemacht, aber die Ausführung kostet trotzdem etwas Zeit und Prozessorzyklen |
WAIT #x | 2x | wait <time> | Verzögerung des Programms, 1⇐ x ⇐ 15, nach der vorher stehenden Tabelle . Wahlweise kann auch ein String verwendet werden. Mögliche Werte dazu: 1ms, 2ms … 60s. |
RJMP #x | 3x | Jump back | Sprung zurück um x Befehle, oder zu :label |
PAGE #x | 8x | page #x | Setzen des Page Registers 0 ⇐ x < 16 |
JMP #x | 9x | jump to #x + 16 * page | Springe nach Adresse #x + (16 * page) 0 ⇐ x < 16 |
LOOPC #x | Ax | loop c | Ist C>0: C=C-1; Springe nach #x + (16*page), sonst gehe zum nächsten Befehl |
LOOPD #x | Bx | loop d | Ist D>0: D=D-1; Springe nach #x + (16*page), sonst gehe zum nächsten Befehl |
SKIP0 | C0 | Skip if A = 0 | Überspringe nächsten Befehl wenn A = 0 |
AGTB | C1 | Skip if A > B | Überspringe nächsten Befehl wenn A > B |
ALTB | C2 | Skip if A < B | Überspringe nächsten Befehl wenn A < B |
AEQB | C3 | Skip if A = B | Überspringe nächsten Befehl wenn A = B |
DEQ#y #x | C4..CB | Skip if Din.X = Y | Überspringe nächsten Befehl wenn der Eingang #y 0 oder 1 ist. x=0,1 |
PRG#x | CC, CE | Skip if PRG = x | Überspringe nächsten Befehl wenn der PRG TAster gedrückt(0) oder nicht gedrückt (1) ist. x=0,1 |
SEL#x | CD, CF | Skip if SEL = x | „ nur für SEL |
CALL #x | Dx | Call #x + (16 * page) | |
RTR | E0 | Return | Zurück springen nach einem Call-Befehl oder am Ende einer Subroutine |
CASB #x | E1..E6 | Call sub #x | Aufruf der Subroutine x, 1 ⇐ x ⇐ 6 |
DFSB #x | E8..ED | Define sub #x | Definierung der Subroutine x, 1 ⇐ x ⇐ 6 |
REST | EF | Restart program | |
PEND | FF | Program end |
Laden und Speichern
Mnemonic | Code | short description | Beschreibung |
---|---|---|---|
LDA ##x | 4x | A = #x | Register A wird mit dem festen Wert #x geladen |
SWAP | 50 | Swap A & B | Tauschen der Register A und B |
MOV X,Y | 51..53, 61..63, 5D, 5E, 6D, 6E | X = Y | kopiert ein Register in ein anderes X und Y dürfen folgende Werte annehmen: A, B, C, D, E, F |
PUSH | 5F | push A on stack | Das A Register wird auf dem Stack gelegt |
POP | 6F | Pop value from stack to A | Wert aus dem Stack in das A Register übertragen |
Mathematik
Mnemonic | Code | short description | Beschreibung |
---|---|---|---|
INC | 71 | A = A + 1 | Increment A |
DEC | 72 | A = A - 1 | Decrement A |
ADD | 73 | A = A + B | |
SUB | 74 | A = A - B | |
MUL | 75 | A = A * B | |
DIV | 76 | A = A / B | |
AND | 77 | A = A and B | |
OR | 78 | A = A or B | |
XOR | 79 | A = A xor B | |
NOT | 7A | A = not A | |
MOD | 7B | A = A % B | |
BYTE | 7C | A = A + 16 * B | |
BSUBA | 7D | A = B - A |
Ein/Ausgabe
Mnemonic | Code | short description | Beschreibung |
---|---|---|---|
LDA DIN | 64 | A = Din | Register A wird mit dem Wert vom digitalen Eingang geladen. Alle 4 Bit. |
LDA DINx | 65..68 | A = Din.x | Register A wird mit dem Wert vom digitalen Eingang #x geladen. x = 1..4 |
LDA ADCx | 69, 6A | A = ADC.x | Register A wird mit dem Wert vom analogen Eingang #x geladen. x = 1..2 |
LDA RCx | 6B, 6C | A = RC.x | Register A wird mit dem Wert vom RC Empfängereingang #x geladen. x = 1..2 |
PORT #x | 1x | Dout = #x | Direkte Ausgabe von Wert #x auf den Ausgängen. 0 ⇐ x ⇐ 15. |
STA DOUT | 54 | Dout = A | Ausgabe von A auf den Ausgängen |
STA DOUTx | 55..58 | Dout.x = A | Ausgabe von A.x auf den Ausgang x = 1..4 |
STA PWMx | 59, 5A | PWM.x = A | Der Wert aus dem A Register wird als PWM.x ausgegeben. x = 1,2 |
STA SRVx | 5B, 5C | Servo.x = A | Der Wert aus dem A Register wird als Servo.x ausgegeben. x = 1,2 |
Byte Befehle
Mnemonic | Code | short description | Beschreibung |
---|---|---|---|
BLDA ADCx | F0, F1 | A = ADC.x | Bytewert auslesen eines Analogeinganges x = 1,2 |
BLDA RCx | F2, F3 | A = RC.x | Bytewert auslesen eines Fernsteuerungskanals x = 1,2 |
BSTA PWMx | F4, F5 | PWM.x = A | Der Byte Wert aus dem A Register wird als PWM.x ausgegeben. x = 1,2 |
BSTA SRVx | F6, F7 | Servo.x = A | Der Byte Wert aus dem A Register wird als Servo.x ausgegeben. x = 1,2 |
TONE | F8 | Tone A | Ausgabe eines Tones nach Midi 32 ⇐ A ⇐ 108 |
Labels
Für die Jump, Loop und Call Befehle kann auch ein Label verwendet werden. Der zugehörige Page Befehl muss aber selber implementiert werden. Die Berechnung der Sprungadresse erfolgt dabei automatisch, wenn das Argument des Page Befehles als :? angegebenen wird. Beispiel:
:Loop PORT #4 WAIT 200ms PORT #0 WAIT 200ms PAGE :? JMP :Loop
Labels sind bei den Mnemonics RJMP, JMP, LOOPC, LOOPD und CALL erlaubt. Auch die beiden erweiterten Befehle DFSB und CASB zur Unterprogrammausführung unterstützen Labels.
Somit funktioniert auch sowas:
CASB :Blink ... DFSB :Blink PORT #4 WAIT 200ms PORT #0 WAIT 200ms RTR
Kommentare
Kommentare sind erlaubt. Es gibt 2 Arten von Kommentaren. Blockkommentare gehen über mehrere Zeilen, Starten mit „\*“ und Enden mit „*/„
Zeilenkommentare werden mit ; gestartet, stehen hinter dem Argument und der Assembler ignoriert den Rest der Zeile.
Beispiel:
/* Kommentar über mehrere Zeilen */ :loop PORT #0x0F ; Zeilenkommentar WAIT 200ms PORT #0x00 WAIT 200ms RJMP :loop
JMP, CALL, LOOPx und PAGE
Für die absoluten Sprünge werden immer das Argument des Mnemonics und zusätzlich der Inhalt des PAGE Registers verwendet. Die Adresse berechnet sich dann aus: adr = #x + (16 * PAGE). Nun muss man sich vorher die PAGE berechnen und den entsprechenden PAGE Befehl vor den Sprung setzten. Hier kann einem der Assembler bei der Berechnung helfen. Steht direkt vor dem Sprung mit Label ein PAGE mit Argument :? berechnet der Assembler selber die PAGE Nummer. Beispiel:
PAGE :? JMP :loop2 :loop PORT #0x0F WAIT 200ms :loop2 PORT #0x00 WAIT 200ms RJMP :loop
Hier wird automatisch die richtige Seite in den ersten PAGE Befehl eingetragen.
Makros
Es können auch zur Vereinfachung von Programmen Makros verwendet werden. Zunächst muss man ein Makro definieren. Beispiel hier mal die Blink Funktion:
PORT #0B1111 WAIT 200ms PORT #0B0000 WAIT 200ms
Um diese als Makro an verschiedenen Stellen einsetzen zu können, muss man zunächst die Stelle als Makro markieren. Das macht man, indem man ein mit .macro und .endmacro Anfang und Ende markiert. Hinter .macro muss man dann den Namen des Makros schreiben, unter dem man das Makro dann verwenden möchte. Ergebnis:
.macro blink PORT #0B1111 WAIT 200ms PORT #0B0000 WAIT 200ms .endmacro
Jetzt kann man bestimmte Werte auch noch variabel gestalten. Also hier z.B. welche LEDs blinken sollen und wie lange die Wartezeit sein soll.
.macro blink output delay PORT output WAIT delay PORT #0B0000 WAIT delay .endmacro
Im eigentlichen Programm kann man das Makro mit z.B.
.blink #0B1010 200ms
aufrufen.
Makros müssen vor dem ersten Aufruf definiert sein. Das gesamte Programm lautet also nun:
.macro blink output delay PORT output WAIT delay PORT #0B0000 WAIT delay .endmacro :loop .blink #0B1111 200ms RJMP :loop
Direktriven
Der Assembler unterstützt verschiedene Direktriven. Einige haben wir schon kennengelernt, die Macros, Loops…
Weitere:
- .arduinosps: damit wird die Hardware auf Arduino_TPS festgelegt. Diese Directrive sollte vor dem eigentlichen Code erscheinen.
- .tinysps: legt die Hardware auf die Tiny_TPS fest.
- .atmega8: legt die Hardware auf die ATMega8 fest.
- .holtek: legt die Hardware auf Holtek fest.
- .include
Mit dieser Direktrive kann man ein Unterprogramm aus einer anderen Datei einbinden. (Dieses Feature wird im Webmodus nicht unterstützt) mit ``.include Blink `` wird eine Datei Blink.asm an dieser Stelle mit ins Programm eingebunden. Damit steht der gesamte Code dieser Datei an dieser Stelle als wäre er dort in der originalen Datei hingeschrieben worden.