## Binary to ASCII, 16 bit to 3digits (0..999) FAST

```;-------------------------------------------
;Fast binary to decimal conversion (0..999)
;
;Input: NumH:NumL
;Output Hund:Tens_Ones (packed BCD)
;
;
;
;Size: 56 instructions
;Execution time (with return): 57
;
;8-July-2000 by Nikolai Golovchenko
;23-Aug-2001
;Based on 8bit BIN2BCD of Scott Dattalo
;-------------------------------------------
bin2dec999fast
swapf NumL, w   ;Add the upper and lower nibbles
addwf NumL, w   ;to get the one's digit
andlw 0x0F
skpndc          ;Go through a binary to bcd
addlw 0x16     ;conversion for just the one's
skpndc          ;digit
skpdc

btfsc NumL, 4   ;bit 4 is a special case
addlw 0x16 - 1 + 0x6
skpdc

btfsc NumL, 5   ;2^5 = 32, so add 3 to the ten's
addlw 0x30     ;digit if bit 5 is set

btfsc NumL, 6   ;2^6 = 64, so add 6
addlw 0x60     ;if bit 6 is set

btfsc NumL, 7   ;2^7 = 128, so add 2 (the ten's
addlw 0x20     ;digit) if bit 7 is set

addlw 0x60      ;convert the ten's digit to bcd
clrf Hund
rlf Hund, f     ;if there's a carry, then the input
btfss Hund, 0   ;was greater than 99.
movwf Tens_Ones

movlw 0x66      ;2^8 = 256, so add 0x56 to Tens_Ones
btfsc NumH, 0
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f

movlw 0x66      ;2^9 = 512, so add 0x12 to Tens_Ones
btfsc NumH, 1
movlw 0x12 + 0x66
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f

;        btfsc NumL, 7   ;finish with hundreds
;         incf Hund, f
;        movlw 2
;        btfsc NumH, 0
;        movlw 5
;        btfsc NumH, 1
```
```; Aug 23, 2001 optimization:
```
```        rlf NumL, w             ; copy bit 7 to carry        rlf NumH, w             ; load w with bits 9 to 7        btfsc NumH, 1           ; add b[9]         addlw 1                ;        addwf Hund, f           ; add it to hundreds

return

```

The algorithm is based on the idea of adding up decimal weights of each
bit. Each bit has a weight (equal to 2^b, b - bit number, 0 to 15), which can
be represented and added in decimal:

bit     weight          hundreds tens  ones
------- -------         ------- ------ -------
0       1               0       0       1
1       2               0       0       2
2       4               0       0       4
3       8               0       0       8
4       16              0       1       6
5       32              0       3       2
6       64              0       6       4
7       128             1       2       8
8       256             2       5       6
9       512             5       1       2

So, if a bit is set, we add the appropriate decimal digits to our
result. But testing each bit would be very inefficient. There are
however ways to optimize this. You can notice a regularity, for
example, in the ones column. Values almost repeat the binary weights
(1,2,4,8,6,2,4,8,6,2). That means that we can separate the binary word
in repeatable strings and add these strings together, which would be
the same if we tested each bit.

First, we need to modify the table to see how to separate the bits in
strings:

bit     weight          hundreds tens  ones
------- -------         ------- ------ -------
0       1               0       0       1
1       2               0       0       2
2       4               0       0       4
3       8               0       0       8
4       16              0       1       1+5
5       32              0       2+1     2
6       64              0       4+2     4
7       128             1       2       8
8       256             2       5       1+5
9       512             4+1     1       2

So, the calculations would be:

ones = b[3:0] + b[7:4] + b[9:8] + 5*(b[4] + b[8])
tens = b[6:4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
hund = b[9:7] + b[9]

However, first two sums may exceed the 0 to 9 range, so we would have
to check for that and propagate the overflow to tens and hundreds.

Let's see what the code does...

; add b[3:0] + b[7:4] for ones
swapf NumL, w   ;Add the upper and lower nibbles
addwf NumL, w   ;to get the one's digit
andlw 0x0F
; if sum is bigger than 15 (DC is set), add 16 to BCD result
skpndc          ;Go through a binary to bcd
addlw 0x16     ;conversion for just the one's
; if lower digit overflowed again, add 16 again
skpndc          ;digit
; make sure the lower digit is in 0..9 range. If not, do BCD
skpdc

; add now 5*b[4] to ones accumulator and b[4] to tens, doing the
; BCD correction at the same time
btfsc NumL, 4   ;bit 4 is a special case
addlw 0x16 - 1 + 0x6
skpdc

; here we have converted already bits 0 to 4:
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
;        ---------------            -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;                   ----
; hund = b[9:7] + b[9]

; now just test bits 5 to 7 and add their decimal weights to
; tens only (bit 7 also affects hundreds). We can add maximum
; 11 to tens digit here, so it will be less than 16 and not overflow.
btfsc NumL, 5   ;2^5 = 32, so add 3 to the ten's
addlw 0x30     ;digit if bit 5 is set

btfsc NumL, 6   ;2^6 = 64, so add 6
addlw 0x60     ;if bit 6 is set

btfsc NumL, 7   ;2^7 = 128, so add 2 (the ten's
addlw 0x20     ;digit) if bit 7 is set

; do decimal correction for tens and propagate carry to hundreds
addlw 0x60      ;convert the ten's digit to bcd
clrf Hund
rlf Hund, f     ;if there's a carry, then the input
btfss Hund, 0   ;was greater than 99.
movwf Tens_Ones

; Here we are done with bits 5 to 7 (except bit 7 for hundreds):
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
;        ---------------            -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;        --------   ----   ------   ------
; hund = b[9:7] + b[9]

; test bit 8, and add what it contributes to ones and tens
movlw 0x66      ;2^8 = 256, so add 0x56 to Tens_Ones
btfsc NumH, 0
; do decimal correction
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f

; Here we are done with bit 8:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
;        ---------------           -----   -------  ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;        --------   ----   ------   ------   ------
; hund = b[9:7] + b[9]

; test bit 9 (it adds 2 to ones, 1 to tens, and 5 to hundreds),
; but ignore hundreds yet
movlw 0x66      ;2^9 = 512, so add 0x12 to Tens_Ones
btfsc NumH, 1
movlw 0x12 + 0x66
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f

; Now we have a ready result for ones and tens:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
;        ---------------   ------  -----   -------  ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;        --------   ----   ------   ------   ------  -----
; hund = b[9:7] + b[9]

; now just test bits 7, 8, and 9 and add their share to hundreds
; (without any BCD correction, because we assume input value is
; between 0 and 999, so hundreds can't be more than 9)

btfsc NumL, 7   ;finish with hundreds
incf Hund, f
movlw 2
btfsc NumH, 0
movlw 5
btfsc NumH, 1

That's it!

Wait, let's optimize the last few lines...

; hund = b[9:7] + b[9]

rlf NumL, w             ; copy bit 7 to carry
rlf NumH, w             ; load w with bits 9 to 7
btfsc NumH, 1           ; add b[9]

Questions:

I have not analyzed the code at http://www.piclist.com/techref/microchip/math/radix/b2a-16b3a2-ng.htm, but there seems to be an error somewhere. It works for numbers 0..299, but 300 comes up as "49:". From here on up, there are various points where it works as expected and others where it doesn't. Anyone have a fix?

I put your code back and still have a problem. I used the code you sent, which I compared with that on the website. They appear to be identical except that which you sent has more comments (or perhaps it's just that they are in the code instead of at the bottom).

Now, here's something I didn't mention before: I'm running this on an 18c452. I've never had problems with instruction changes before, but appear to be having the problem now. I don't fully understand your code, but looking through it a bit, I see where the comments say "test bit 8," and a little below that is "do decimal correction." The decimal correction includes "incf Hund, f". On the 16 series chips, incf and decf affect only Z while on the 18C they affects C, DC, Z, OC, N. A couple lines down is a skpc and a couple more lines down is a skpdc. These are probably relying on status bits set in the addwf Tens_Ones,f a few lines up, but are, instead getting the status caused by the incf.

I've added some conditional assembly to save away the status and restore it where I've seen the problems. The code now seems to work fine. My modified code is below.

Finally THANKS for contributing your code and providing great support! I hope I can return the favor some day!

Code:

```;Fast binary to decimal conversion (0..999)
;
;Input: NumH:NumL
;Output Hund:Tens_Ones (packed BCD)
;
;
;
;Size: 56 instructions
;Execution time (with return): 57
;
;8-July-2000 by Nikolai Golovchenko
;23-Aug-2001
;Based on 8bit BIN2BCD of Scott Dattalo
;-------------------------------------------
cblock
NumH
NumL
Hund
Tens_Ones
endc

ifdef __18C452
cblock
TempStatus ; Deal with instruction set changes from 16c to 18c
endc
endif

bin2dec999fast
; convert
; add b[3:0] + b[7:4] for ones
swapf NumL, w   ;Add the upper and lower nibbles
addwf NumL, w   ;to get the one's digit
andlw 0x0F
; if sum is bigger than 15 (DC is set), add 16 to BCD result
skpndc          ;Go through a binary to bcd
addlw 0x16     ;conversion for just the one's
; if lower digit overflowed again, add 16 again
skpndc          ;digit
; make sure the lower digit is in 0..9 range. If not, do BCD
skpdc

; add now 5*b[4] to ones accumulator and b[4] to tens, doing the
; BCD correction at the same time
btfsc NumL, 4   ;bit 4 is a special case
addlw 0x16 - 1 + 0x6
skpdc

; here we have converted already bits 0 to 4:
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
;        ---------------            -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;                   ----
; hund = b[9:7] + b[9]

; now just test bits 5 to 7 and add their decimal weights to
; tens only (bit 7 also affects hundreds). We can add maximum
; 11 to tens digit here, so it will be less than 16 and not overflow.
btfsc NumL, 5   ;2^5 = 32, so add 3 to the ten's
addlw 0x30     ;digit if bit 5 is set

btfsc NumL, 6   ;2^6 = 64, so add 6
addlw 0x60     ;if bit 6 is set

btfsc NumL, 7   ;2^7 = 128, so add 2 (the ten's
addlw 0x20     ;digit) if bit 7 is set

; do decimal correction for tens and propagate carry to hundreds
addlw 0x60      ;convert the ten's digit to bcd
clrf Hund
rlf Hund, f     ;if there's a carry, then the input
btfss Hund, 0   ;was greater than 99.
movwf Tens_Ones

; Here we are done with bits 5 to 7 (except bit 7 for hundreds):
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
;        ---------------            -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;        --------   ----   ------   ------
; hund = b[9:7] + b[9]

; test bit 8, and add what it contributes to ones and tens
movlw 0x66      ;2^8 = 256, so add 0x56 to Tens_Ones
btfsc NumH, 0
; do decimal correction
ifdef __18C452
movff status, tempstatus ; Save status so incf doesn't mess up C and DC
endif
skpnc
incf Hund, f
ifdef __18C452
movff tempstatus,status ; Restore the status
endif
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f

; Here we are done with bit 8:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
;        ---------------           -----   -------  ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;        --------   ----   ------   ------   ------
; hund = b[9:7] + b[9]

; test bit 9 (it adds 2 to ones, 1 to tens, and 5 to hundreds),
; but ignore hundreds yet
movlw 0x66      ;2^9 = 512, so add 0x12 to Tens_Ones
btfsc NumH, 1
movlw 0x12 + 0x66
ifdef __18C452
movff status, tempstatus ; Save so incf doesn't mess up C and DC
endif
skpnc
incf Hund, f
ifdef __18C452
movff tempstatus,status ; Restore saved status
endif
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f

; Now we have a ready result for ones and tens:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
;        ---------------   ------  -----   -------  ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
;        --------   ----   ------   ------   ------  -----
; hund = b[9:7] + b[9]

; now just test bits 7, 8, and 9 and add their share to hundreds
; (without any BCD correction, because we assume input value is
; between 0 and 999, so hundreds can't be more than 9)

;        btfsc NumL, 7   ;finish with hundreds
;         incf Hund, f
;        movlw 2
;        btfsc NumH, 0
;        movlw 5
;        btfsc NumH, 1

;That's it!

;Wait, let's optimize the last few lines...

; hund = b[9:7] + b[9]

rlf NumL, w             ; copy bit 7 to carry
rlf NumH, w             ; load w with bits 9 to 7
btfsc NumH, 1           ; add b[9]
return
```

:

 file: /Techref/microchip/math/radix/b2a-16b3a2-ng.htm, 25KB, , updated: 2013/6/6 09:14, local time: 2024/9/18 21:09, owner: NG--944, TOP NEW HELP FIND:  18.205.56.209:LOG IN

 ©2024 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 Radix Math Method Binary to ASCII, 16 bit to 3digits (0..999) FAST

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 a nice message (short messages are blocked as spam) 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"

 PICList 2024 contributors: o List host: MIT, Site host massmind.org, Top posters @none found - Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr.

.