please dont rip this site

PIC Microcontoller Program Flow Method: Conditionally replace one value with another

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 ]

Single Value Replacement

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'


Conditional Swap

From http://www.myke.com/basic.htm

Here's a compare and swap
   movf    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

Min and Max

code to find the minimum or maximum value of 2 or values.

limit

Code to force a variable to the maximum value if it exceeds that value.

Also known as ``saturating arithmetic''. Very important in audio filters.

8 bit saturating arithmetic

"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

16-bit saturating arithmetic

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




Absolute Value

; 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. 

16 bit signed integer min and 16 bit signed integer max

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:


file: /Techref/microchip/condrepl.htm, 12KB, , updated: 2013/7/7 08:57, local time: 2024/11/5 07:33, owner: DAV-MP-E62a,
TOP NEW HELP FIND: 
18.118.27.119:LOG IN
©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!

 ©2024 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?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://linistepper.com/techref/microchip/condrepl.htm"> PIC Microcontoller Program Flow Method: Conditionally replace one value with another </A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?