Die Subtraktion in Assembler auf PIC-Mikrocontrollern bereitet einiges an Kopfzerbrechen:
SUBWF reg,W
ist die Wirkung W = reg - W
.
Diese wird vor allem bei Vergleichen angewendet, weil nur W verändert wird.
Die Wirkung ist, dass W invertiert wird, also nicht W -= reg
!
SUBWF reg,F
ist die Wirkung reg -= W
.
Man muss dazu im PIC-Assembler-Denkschema bleiben,
wonach generell „Opcode quelle,ziel“ gilt: reg-W => reg
,
also wie beim alten x86-gas und andersherum als bei AVR, Z80, ARM
und höheren Programmiersprachen, bei denen der Zuweisungsoperator
nach links arbeitet.
(Dieses Wirrwarr ist eine Spätfolge der Fehlübersetzung arabischer Mathematik im Mittelalter.)
Um Differenzen zweier Abtastwerte oder Timer-Werte zu bilden, muss man den vorherigen Wert verarbeiten und danach den neuen Wert (nicht die Differenz) speichern.
movfw tic subwf TMR0,w ; w = tic-TMR0 = negative Differenz subwf tic,f ; tic = tic-(tic-TMR0) = TMR0 ;Jetzt in W die negative Differenz und in tic der neue TMR0-Wert
Man benötigt so kein Zwischenregister zum Festhalten des gelesenen TMR0-Wertes.
Wie oben, mit positiver Differenz. Wichtig für PIC12F508, der keinen Timerüberlauf-Interrupt (nicht mal ein Flag) hat.
movfw TMR0 subwf tic,w ; w = TMR0-tic = vergangene Zeit addwf tic,f ; tic = tic+(TMR0-tic) = TMR0 ;Jetzt in W die vergangene Zeit und in tic der neue TMR0-Wert ;Außerdem ist C bei Timerüberlauf gesetzt. Das passt für: skpnc incf t0h,f ;16-Bit-Erweiterung von TMR0 nachführen
In der gleichen Weise funktioniert auch der XOR-Trick zur Abfrage von Tasten und Inkrementalgebern.
Für 16-Bit-Zahlen muss bei Überlauf beim Low-Byte das High-Byte dekrementiert werden. Denn es fehlt ein Subtraktionsbefehl mit Übertrag, etwa subb oder sbc. Den gibt's erst bei größeren PICs.
movfw subtrahend subwf minuend,f skpc ; C=1: kein(!) Überlauf decf minuend+1,f ; Übertrag als zusätzliche Subtraktion von 1 movfw subtrahend+1 subwf minuend+1,f
Wenn kein sublw
-Befehl zur Verfügung steht,
muss der zu prüfende Wert in ein Register (testvar, nicht in W)
und es geht weiter wie folgt:
movlw minimum subwf testvar,w bnc error movlw maximum ; hier: Maximum+1 subwf testvar,w bc error ; auch bei Gleichheit ;hier ist minimum < testvar ≤ maximum (vzl.) error: ;hier: C=0: zu klein, C=1: zu groß