Full Version : Payson's Binary to BCD (PIC ASM)
avr >>PIC 8051 ZILOG ARM TI H8 ETC >>Payson's Binary to BCD (PIC ASM)


Admin3- 04-18-2006
CODE

;-------------------------------------------------------------------

;
; Binary-to-BCD.  Written by John Payson.
;
; Enter with 16-bit binary number in NumH:NumL.
; Exits with BCD equivalent in TenK:Thou:Hund:Tens:Ones.
;

       org     $0010  ;Start of user files for 16c84

NumH:   ds      1
NumL:   ds      1
TenK:   ds      1
Thou:   ds      1
Hund:   ds      1
Tens:   ds      1
Ones:   ds      1

Convert:                       ; Takes number in NumH:NumL
                              ; Returns decimal in
                              ; TenK:Thou:Hund:Tens:Ones
       swapf   NumH,w
       andlw   $0F            ;*** PERSONALLY, I'D REPLACE THESE 2
       addlw   $F0            ;*** LINES WITH "IORLW 11110000B" -AW
       movwf   Thou
       addwf   Thou,f
       addlw   $E2
       movwf   Hund
       addlw   $32
       movwf   Ones

       movf    NumH,w
       andlw   $0F
       addwf   Hund,f
       addwf   Hund,f
       addwf   Ones,f
       addlw   $E9
       movwf   Tens
       addwf   Tens,f
       addwf   Tens,f

       swapf   NumL,w
       andlw   $0F
       addwf   Tens,f
       addwf   Ones,f

       rlf     Tens,f
       rlf     Ones,f
       comf    Ones,f
       rlf     Ones,f

       movf    NumL,w
       andlw   $0F
       addwf   Ones,f
       rlf     Thou,f

       movlw   $07
       movwf   TenK

                      ; At this point, the original number is
                      ; equal to
                       TenK*10000+Thou*1000+Hund*100+Tens*10+Ones;
                       if those entities are regarded as two's
                       compliment; binary.  To be precise, all of
                       them are negative; except TenK.  Now the
                       number needs to be normal-; ized, but this
                       can all be done with simple byte; arithmetic.

       movlw   $0A                            ; Ten
Lb1:
       addwf   Ones,f
       decf    Tens,f
       btfss   3,0
        goto   Lb1
Lb2:
       addwf   Tens,f
       decf    Hund,f
       btfss   3,0
        goto   Lb2
Lb3:
       addwf   Hund,f
       decf    Thou,f
       btfss   3,0
        goto   Lb3
Lb4:
       addwf   Thou,f
       decf    TenK,f
       btfss   3,0
        goto   Lb4

       retlw   0


And according to my analysis:

If you have a 4 digit hexadecimal number, it may be written as

N = a_3*16^3 + a_2*16^2 + a_1*16 + a_0

where a_i, i=0,1,2,3 are the four hexadecimal digits. If you
wish to convert this to decimal, then you need to express N as

N = b_4*10^4 + b_3*10^3 + b_2*10^2 + b_1*10 + b_0

Where b_j, j=0,1,2,3,4 are the five decimal digits.
The reason there are 5 digits in the decimal representation
is because the maximum four digit hexadecimal number (0xffff)
requires 5 decimal digits (65535). Now the goal is to find
a set of equations that allow the b_j's to be expressed in
terms of the a_i's. There are infinitely many ways to do this.
Here are two of probably the simplest expressions.
First, expand the 16^i's and then collect all coefficients
of the 10^j's:

N = a_3*4096 + a_2*256 + a_1*16 + a_0
= a_3*4*10^3 + a_2*2*10^2 + (a_3*9 + a_2*5 + a_1)*10 +
6*(a_3 + a_2 + a_1) + a_0


This gives us five equations:

b_0 = 6*(a_3 + a_2 + a_1) + a_0
b_1 = a_3*9 + a_2*5 + a_1
b_2 = 2*a_2
b_3 = 4*a_3
b_4 = 0

Which as John says, must be "normalized". Normalization in
this context means we need to reduce the b_j's such that
0 <= b_j <= 9

In other words we need to find:

c_0 = b_0 mod 10

b_1 = (b_1 + (b_0 - c_0)/10)
c_1 = b_1 mod 10

b_2 = (b_2 + (b_1 - c_1)/10)
c_2 = b_2 mod 10

b_3 = (b_3 + (b_2 - c_2)/10)
c_3 = b_3 mod 10

c_4 = (b_4 + (b_3 - c_3)/10) mod 10
= (b_2 - c_2)/10

Division by 10 can be done quite efficiently (as was shown
in another thread several months ago). However, it does require
a significant amount of code space compared to say repeated
subtractions. Unfortunately, there can be very many subtractions
that are required. For example, b_1 could be as large as 15*16,
or 240. 10 would have to be subtracted 24 times if you wish to
compute 240 mod 10. I presume John realized this inefficiency
and thus sought to express N so that repeated subtractions
could be used and that the total number of subtractions are
minimized. This leads to the next way that N can be expressed:

N = a_3*(4100 - 4) + a_2*(260 - 4) + a_1*(20-4) + a_0
= 4*a_3*10^3 + (a_3 + 2*a_2)*10^2 + (6*a_2 + 2*a_1)*10 +
a_0 - 4*(a_3 + a_2 + a_1)

This gives five new equations for the b_j's.

b_0 = a_0 - 4*(a_3 + a_2 + a_1)
b_1 = 6*a_2 + 2*a_1
b_2 = a_3 + 2*a_2
b_3 = 4*a_3
b_4 = 0

However, these equations are still not conducive to the
repeated subtraction algorithm, at least the way John has
done it. In other words, it is possible to pre-condition
each of the b_j's so that they are less than zero. Then
the repeated subtractions can simultaneously perform the
"mod 10" and "/10" operations shown above. Consider the
equation b_0 for example,

b_0 = a_0 - 4*(a_3 + a_2 + a_1)

Since each a_i must satisfy: 0 <= a_i <= 15, then b_0
ranges:

-60 <= b_0 <= 15

We can make b_0 negative by subtracting any number greater than
15. A logical choice is 20. This is because if we subtract 20
from b_0, we can add 2 to b_1 to keep the net result the same.
The reason we add "2" can be seen:

b_1*10 + b_0 = b_1*10 + b_0 + 20 - 20
= (b_1 + 2)*10 + b_0 - 20

Carrying this concept out for the rest of the b_i's we have.

b_0 = a_0 - 4*(a_3 + a_2 + a_1) - 20
b_1 = 6*a_2 + 2*a_1 + 2 - 140
= 6*a_2 + 2*a_1 - 138
b_2 = a_3 + 2*a_2 + 14 - 60
= a_3 + 2*a_2 - 46
b_3 = 4*a_3 + 6 - 70
= 4*a_3 - 64
b_4 = 0 + 7
= 7

And if you look at John's code closely, you will see this is
how he has expressed the b_j's.



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.