 # PICMicrocontoller Program FlowMethod: Conditionally replace one value with another

contents:

• compcon.htm for information about comparisons and conditionals in theory.
• math/radix/ for replacing a nybble in W (or in some register) with its ASCII value, or vice versa.

[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

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
return

; R0new = min(R0initial, w);
; w is unchanged
unsigned_min8:
subwf R0,f
btfss R0,7
clrf 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.

...

total_L res 1
temp res 1
total_H res 1

...

clrf temp
decf temp,f
; now "temp" holds 0xFF if reading was negative, 0 if reading was positive

; semi-normal 16 bit sum
skpnc
incf temp,f
; now temp = 0 for no change, +1 to increment, or 0xFF to decrement.
movf temp,w

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

Questions:

• Merci!
Looked exactly for this code, building my Min/Max thermometer with DS18B20.+

 file: /Techref/microchip/condrepl.htm, 12KB, , updated: 2013/7/7 08:57, local time: 2019/11/19 19:06, owner: DAV-MP-E62a, TOP NEW HELP FIND:  18.204.56.104:LOG IN

 ©2019 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! /  PIC Microcontoller Program Flow Method: Conditionally replace one value with another

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

Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
 Did you find what you needed? "No. I'm looking for: " "No. Take me to the search page." "No. Take me to the top so I can drill down by catagory" "No. I'm willing to pay for help, please refer me to a qualified consultant" "No. But I'm interested. me at when this page is expanded."

.