PIC Microcontoller Radix Math Method

8bit to extract decimal 1's, 10's, 100's by jsvetlin

jsvetlin-email- shares this code:

;for alternative version you might also want to check http://www.piclist.com/techref/microchip/math/32bmath-ph.htm
;This routine will return the number of decimal 
;hundreds from an 8-bit binary
;Input: w
;Output: w
;RAM:2
;Cycles: 12-24

GETHNDS		movwf	t1
                clrf    w2
gethnds_loop	movlw	.100
		incf	w2,f
		subwf	t1,f
		btfsc	STATUS,C
		goto 	gethnds_loop
		decf	w2,w
		return		
;---
;This routine will return the number of decimal 
;tens from an 8-bit binary
;Loop based, so it might take some time...
;It needs getones too
GETTENS		movwf	t1
                clrf    w2
gettens_loop	movlw	.10
		incf	w2,f
		subwf	t1,f
		btfsc	STATUS,C
		goto 	gettens_loop
		decf	w2,w
		goto	getones

;---
;This routine will return the number of decimal 
;ones from an 8-bit binary	
GETONES		movwf	w2
		movlw	.10
deltens_loop	subwf	w2,f
		btfsc	STATUS,C
		goto 	deltens_loop
		addwf	w2,w	
		return
 

  

Sergio Masci says:

lets say you want to convery the binary number 359 to ascii digits. Dont worry that it's shown as decimal or greater than 255 for now.

So what you would normally do is look at the 100s column and take the 3 then the 10s column and take the 5 then the 1s column and take the 9. Ok so how do we take a digit from a column on a computer. Well what we actually do is take '1' away from that column until we get to '0' and we count how many times we are able to do this. If we write this in pseudo code we get:

For the 100s column

       value = 359
       count = 0

       while value >= 100 do
               value = value - 100
               count = count + 1
       done

at this point we end up with

       value = 59
       count = 3

It's important that we start with the highest column first.

For the 10s column

       count = 0

       while value >= 10 do
               value = value - 10
               count = count + 1
       done

now we end up with

       value = 9
       count = 5

Now at this point you can easily see that the '1' column is whats left in 'value' Now to clear up the confusing bits.

decimal 359 is binary 01 0110 0111
decimal 100 is binary 00 0110 0100
decimal  10 is binary 00 0000 1010
decimal   1 is binary 00 0000 0001

decimal 300 is binary 01 0010 1100
decimal  50 is binary 00 0011 0010

When we take the 3 from the 100s (hundreds) column we are trying to convert

binary 0100101100 to binary 0000000011.

When we take the 5 from the 10s (tens) column we are trying to convert

binary 0000110010 to binary 0000000101.

so the easiest way to do this is to repeatedly take binary 0100101100 from binary 0101100111 (359) and count in units (binary 0000000001).

0101100111 (359) - 0001100100 (100) = 0100000011 (259) ; count = 1
0100000011 (259) - 0001100100 (100) = 0010011111 (159) ; count = 2
0010011111 (159) - 0001100100 (100) = 0000111011  (59) ; count = 3

so at this point we have converted 'value' from 0101100111 (359) to 0000111011 (59) and 'count' to 0000000011 (3)

doing the same for the 10s (tens) we get:

0000111011 (59) - 0000001010 (10) = 0000110001 (49) ; count = 1
0000110001 (49) - 0000001010 (10) = 0000100111 (39) ; count = 2
0000100111 (39) - 0000001010 (10) = 0000011101 (29) ; count = 3
0000011101 (29) - 0000001010 (10) = 0000010011 (19) ; count = 4
0000010011 (19) - 0000001010 (10) = 0000001001  (9) ; count = 5

so at this point we have converted 'value' from 0000111011 (59) to 0000001001 (9) and 'count' to 0000000101 (5) now if we look at the pseudo code again - just the 100s (hundreds) for now:

       value = 359
       count = 0

       while value >= 100 do
               value = value - 100
               count = count + 1
       done

we see a horrible '>=' which kind of complicates things if we are trying to convert this pseudo code into assembly language. We can rearrange things to make them easier like this:

       value = 359
       count = 0

       while (value - 100) > 0 do
               value = value - 100
               count = count + 1
       done

Another way to think about "X > 0" is "is X not negative". If you have enough bits in your variables and you are using 2's complement arithmetic (which tends to be available on most processors these days) then this is a very easy test to make.

e.g.

0000111011 (59) - 0001100100 (100) = 1111010111 (-41)

simply by looking at the most significant bit (the left most bit) and testing if it is a '0' or a '1' we can see if the result is positive or zero (for bit = 0) or negative (for bit = 1).

So we can actually convert the pseudo code to

       value = 359
       count = 0

       while ((value - 100) & 512) == 0 do
               value = value - 100
               count = count + 1
       done

If we tried to do this on a variable that had only 8 bits we would be restricting ourselves to numbers on the range -128 to +127 (because we want to use the most significant bit for the sign. If we use 16 bits then we increase our range to -32768 to +32767.

The above pseudo code would then become

       value = 359
       count = 0

       while ((value - 100) & 32768) == 0 do
               value = value - 100
               count = count + 1
       done

Which is really really easy to convert to PIC assembly code!

It is well worth using multiprecision arithmetic on a PIC (going from 8 bit variables to 16 bit variable) to simplify maths.

Also a very important aspect of multiprecision arithmetic on an 8 bit CPU like the PIC is the ability to calculate addresses greater than 255!!!

I hope this helps.

Josh Koffman says:

In the 16F processors it appears that the decf command doesn't effect the carry bit, but in the 18F chips it does. That's screwing up the logic as the routine is assuming C is unchanged and was last effected by an addwf. Here's a snippet: The commented lines are the ones I substituted with the bnc.
mod0
       addwf   _D0,f
       decf    _D1,f
;        skpc
;        goto    mod0
       bnc                mod0

Archive:

Comments: