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 doneat this point we end up with
value = 59 count = 3It'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 donenow we end up with
value = 9 count = 5Now 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 0010When 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 = 3so 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 = 5so 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 donewe 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 doneAnother 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 doneIf 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 doneWhich 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:
GETONES movlw .10 addwf t1,w returnThis works because when the code reaches "GETONES" section, all the "tens" have been subtracted from t1 and then one more ten has been subtracted, causing t1 to rollover. Therefore by adding ten back to t1, you get back to the number of ones.