[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'
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
; 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 ]
|file: /Techref/microchip/condrepl.htm, 12KB, , updated: 2013/7/7 08:57, local time: 2017/2/22 14:14,
|©2017 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?|
<A HREF="http://www.piclist.com/techref/microchip/condrepl.htm"> PIC Microcontoller Program Flow Method: Conditionally replace one value with another </A>
|Did you find what you needed?|
PICList 2017 contributors:
o List host: MIT, Site host massmind.org, Top posters @20170222 IVP, RussellMc, Van Horn, David, Neil, James Cameron, Sean Breheny, alan.b.pearce, Denny Esterline, David Duffy (AVD), Bob Blick,
* Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.
Welcome to www.piclist.com!