contents:
See also:
[FIXME: rather than having many copies of each routine, one for each register that you need to adjust, point FSR at the register and use a single routine that uses FSR fsr.htm ]
If w='a' then replace it with 'x', if it is something else, leave it alone.
Nikolai Golovchenko says It can be done like this:
xorlw 'a' ;compare to 'a', w' = w ^ 'a' btfss STATUS, Z movlw 'x'^'a' ;if not equal, w = 'x' ^ 'a' xorlw 'a' ;if w was equal to 'a', restore it ;if w was unequal to 'a', ; w = 'x' ^ 'a' ^ 'a'= 'x'
From http://www.myke.com/basic.htm
Here's a compare and swapmovf X, w subwf Y, w ; Is Y >= X? btfsc STATUS, C ; If Carry Set, Yes goto $ + 2 ; Don't Swap addwf X, f ; Else, X = X + (Y - X) subwf Y, f ; Y = Y - (Y - X)This can be used to, for example, Convert ASCII to Upper Case
code to find the minimum or maximum value of 2 or values.
Code to force a variable to the maximum value if it exceeds that value.
Also known as ``saturating arithmetic''. Very important in audio filters.
"clipping" or "limiting": If the value _x is "too big", clip it to the maximum value. If the value _x is "too small", clip it to the minimum value. Otherwise leave _x alone.
min_limit equ 5 max_limit equ H'F1' _limit_x: ; clip _x to make sure it doesn't exceed the limits. ; unsigned_max8: ; _x_new := max( _x_initial, min_limit ) ; from Anders Jansson movlw min_limit subwf _x, W skpc ; btfss STATUS, C subwf _x, F ; unsigned_min8: ; _x_new := min( _x_initial, max_limit ) ; from Anders Jansson movlw max_limit subwf _x, W skpnc ; btfsc STATUS, C subwf _x, F ; now we can be sure that (min_limit <= x) and (x <= max_limit). return
More routines:
; WARNING: untested code. Does this really work ? ; Change register R0 to maximum of (R0, limit), where limit is passed in w. ; Works when both registers are 8 bit unsigned. ; (What about when both are signed ?) ; results: R0new = max(R0initial, w); ; w is unchanged. ; by David Cary unsigned_max8: subwf R0,f btfsc R0,7 clrf R0 addwf R0 return ; R0new = min(R0initial, w); ; w is unchanged unsigned_min8: subwf R0,f btfss R0,7 clrf R0 addwf R0 return
; Example: Force R0 to stay in the range 8..0x19 saturate8: movlw 8 call unsigned_max8 movlw 0x19 call unsigned_min8 ; Change signed 8 bit register R0 to maximum of (R0, 0). signed_max8: btfsc R0,7 ; skip if positive clrf R0 return
This code adds a signed 8 bit value "reading" to a signed 16 bit running sum "total". (useful for the "I" part of PID control). If the result overflows 16 bits, it properly saturates to max_int or min_int.
; code by jspaarg 2005-05-25 ; as posted to http://forum.microchip.com/tm.asp?m=108810&mpage=2 ; minor changes by David Cary ; warning: untested code. ... reading res 1 total_L res 1 temp res 1 total_H res 1 ... accumulate_reading: ; sign-extend reading into temp clrf temp btfss reading, 7 decf temp,f ; now "temp" holds 0xFF if reading was negative, 0 if reading was positive ; semi-normal 16 bit sum ; http://techref.massmind.org/techref/microchip/math/add/index.htm movf reading,w addwf total_L skpnc incf temp,f ; now temp = 0 for no change, +1 to increment, or 0xFF to decrement. movf temp,w addwf total_H ; if you are sure that total_H can never overflow, ; then we are already done here. ; Check for overflow ; If you sure that you can never exceed limits, then you don't need to check. ; (special shortcut that only works because we are adding 8 bits to 16 bits -- ; -- won't work for adding 16 bits to 16 bits) ; only 2 ways to overflow: ; (a) total_H was already the positive number 0x7F, and we incremented it ; with a positive number (temp = +1), resulting in 0x80 and C=0. --> need to saturate to total = 0x7FFF. ; However, if total_H was already the negative number 0x80, and we "added" reading=0, ; we get the same result: 0x80 and C=0; we *don't* want to saturate. ; (b) total_H was already the negative number 0x80, and we "decremented" it ; with a negative number (temp = 0xFF), resulting in 0x7F and C=1. --> need to saturate to total = 0x8000 (or total = 0x8001 would probably be OK). ; However, if total_H was already the positive number 0x7F (total = 0x7F01), and we "added" reading = -1, ; we get the same result: 0x7F and C=1; we *don't* want to saturate. ; Check for overflow. ; If you have an overflow, ; force the total to the appropriate value ; (0x7FFF for max pos, 0x8000 for max neg). ; An overflow happened if ; (a) temp now equals +1, and the result total_H = 0x80, or ; (b) temp now equals -1 (0xFF), and the result total_H = 0x7F. ; check_for_underflow: ; if ( (total_H == 0x7F) and (temp == -1) ) then ForceNeg; movlw 0x7F xorwf total_H,W skpz goto check_for_overflow movlw H'FF' xorwf temp,W skpz return ; ForceNeg: movlw 0x80 movwf total_H movlw 0x01 movwf total_L return check_for_overflow: ; if ( (total_H == 0x80) and (temp == +1) ) then ForcePos; movlw 0x80 xorwf total_H,W skpz return movlw 1 xorwf temp,W skpz return ; ForcePos: movlw 0x7f movwf total_H movlw 0xff movwf total_L return
; WARNING: untested code. Does this really work ? ; Take absolute value of signed 8 bit register R0: ; R0 = abs(R0); abs_8: btfsc R0,7 decf R0 btfsc R0,7 comf R0 return ; Bug: when R0 is the "wierd" value, 0x80, -128, ; this function returns +127, (the most positive ; value that can be represented as a signed ; 8 bit value) not +128 (since that cannot ; be represented as a signed 8 bit value).
; warning: untested ; Obsolete ? ; from Peter Peres 2001-04-14 ; Fmax = max(Fmax, INDF); // update running maximum so far movf INDF,w subwf Fmax,w ;; Fmax - INDF < 0 ? C = 0 movf INDF,w btfss STATUS,C movwf Fmax ; warning: untested ; Obsolete ? ; from Peter Peres 2001-04-14 ; Fmin = min(Fmin, INDF) ; // update running maximum so far movf Fmin,w subwf INDF,w ; ; INDF - Fmin < 0 ? C = 0 movf INDF,w btfss STATUS,C movwf Fmin ; warning: untested ; from Andy Warren 2001-04-14 ; Fmax = max(Fmax, INDF) ; // update running maximum so far MOVF Fmax ; W = INDF - Fmax. SUBWF INDF,W ; C = ( Fmax <= INDF ). SKPNC ;IF Fmax <= INDF, ADDWF Fmax,f ; then Fmax := (Fmax + INDF - Fmax) = INDF. ; warning: untested ; from Andy Warren 2001-04-14 ; Fmin = min(Fmin, INDF) ; // update running maximum so far MOVF Fmin,W ; W = INDF - Fmin. SUBWF INDF,W ; C = ( Fmax <= INDF ). SKPC ;IF INDF < Fmin, ADDWF Fmin,f ; then Fmin := (Fmin + INDF - Fmin) = INDF.
Keywords: (if anyone looks for this code using a search engine) compare comparing 16-bit signed integer integers DS1820 DS18B20 DALLAS thermometer
I wrote this code after spending several hours on the net looking for a readymade example. I wanted to build a thermometer based on the Dallas DS1820, and have a minimum-maximum reading. This requires a signed-16-bit (2's complement) subtraction. Finally I got this (not so optimized):
;Compare 16-bit signed integer (2's complement) to minimum & maximum. ;First byte is LSB (as in the DS1820 thermometer), second byte is MSB ;compare to MINIMUM: btfsc zeroMinMaxFlag goto setMin movf temperature,w subwf min,w ;subtract LSB (low byte) movf temperature+1,w btfss STATUS,C addlw 1 subwf min+1,w ;subtract MSB (hi byte) andlw b'10000000' ;test result's sign bit btfss STATUS,Z goto skipSetMin setMin movf temperature,w movwf min movf temperature+1,w movwf min+1 skipSetMin ;-- ;compare to MAXIMUM: btfsc zeroMinMaxFlag goto setMax movf temperature,w subwf max,w ;subtract LSB (low byte) movf temperature+1,w btfss STATUS,C addlw 1 subwf max+1,w ;subtract MSB (hi byte) andlw b'10000000' ;test result's sign bit btfsc STATUS,Z goto skipSetMax setMax movf temperature,w movwf max movf temperature+1,w movwf max+1 skipSetMax
James Newton replies: Thank you!
Thank you, whoever you are, this looks useful. (Did you mean to post this anonymously, or do you want us to name you in the credits?) -- DavidCary
See also: PIC Microcontroller Comparison Math Methods
[syntax check this page: http://validator.w3.org/check?uri=http://massmind.org/techref/microchip/condrepl.htm ]
Questions:
Comments: