# Scaling from power of 2 to multiple of 10 in ASM

#### BobW

##### Active Member
Frequently it's necessary to take a value that has a range from zero to some power of two, and then scale it into a range of zero to some multiple of ten for display. For example, I have a 10 bit analog input 0..1023 that I'd like to display on a 3 1/2 digit display (0..1999). The following simple PIC assembly code does this, and can be easily adapted for inputs that have a different power of two range, and outputs that are different multiples of ten. This routine multiplies the input value by 1.953125 (2000/1024)

Code:
;Registers used
;X_H, X_L, X_F - high byte, low byte and fraction byte of input value
;Y_H, Y_L, Y_F - high byte, low byte and fraction byte of output result
;count - temporary counter register
;
Scale
;Scale 0..1024 input to 0..2000 display count 2000/1024=1.953125
;X_H, X_L, X_F should be set to input value before calling this routine
clrf Y_F
clrf Y_L
clrf Y_H
movlw 5
movwf count
sLoop
call ShiftX
decfsz count,f
goto sLoop
call ShiftX
;Result is in Y_H,Y_L with fractional part in Y_F
return
;
;The following subroutines use midrange instructions
ShiftX
bcf status,c
rrf X_H,f
rrf X_L,f
rrf X_F,f
return
;Add x reg to y reg - 3 bytes
incf Y_H,f
movf X_F,w
btfsc status,c
incfsz Y_L,f
decf Y_H,f
movf X_L,w
btfsc status,c
incf Y_H,f
movf X_H,w
return
;
;The following subroutines use enhanced midrange instructions
ShiftX
lsrf X_H,f
rrf X_L,f
rrf X_F,f
return
;Add x reg to y reg - 3 bytes
movf X_F,w
movf X_L,w
movf X_H,w
return
Note that the main routine Scale calls two subroutines ShiftX and AddXY. I've included two versions of the subroutines, one for the regular midline PICs and one for the Enhanced Midline PICs.

For anyone wondering why I'm scaling by 2000/1024 rather than 1999/1023, please refer to this discussion:

For other input ranges, simply left or right shift the input value the appropriate number of positions. For example if the input range is 0..4096 call ShiftX twice at the very beginning of the Scale routine.

For other output ranges: 0..1000, 0..500, 0..250 etc., can be had by right shifting the result.

Edit:
I should also mention that the calculation algorithm is an exact multiplication by 1.953125. If more precision is needed for wider ranges, more bytes can be used with no other changes. As presented, the calculation uses three bytes: two for the integer part and one for the fractional part which may occur during intermediate calculations. So, there's little to no loss of accuracy due to truncation of calculation results.

Last edited: