16BIT BIN TO BCD 5 digits

Thread Starter

Dodgydave

Joined Jun 22, 2012
11,284
How can i modify this Asm file to give me a 5 files digit, TENK, THOU, HUNS,TENS, UNITS

for an 18f2321
Rich (BB code):
LEFT JUSTIFIED, UPPER 8 BITS IN ADRESH, LOWER 2 BITS IN ADRESL



 swapf   bcdH,w          ; unpack BCD digits 
        andlw   0x0F 
        movwf   thou 
        movf    bcdH,w 
        andlw   0x0F 
        movwf   huns 
        
        swapf   bcdL,w 
        andlw   0x0F 
        movwf   tens 
        movf    bcdL,w 
        andlw   0x0F 
        movwf   ones 
        goto    $ 
;------------------------------- 
; 
; Upper 10-bit Binary To Packed BCD Digits 
; 
Bin10ToBCD4 
        clrf    bcdL            ; clear result 
        clrf    bcdH 
        movlw   .10             ; set bit counter 
        movwf   count 
        
bcd_lp  movlw   0x33            ; adjust BCD result 
        addwf   bcdL 
        btfsc   bcdL,3 
        andlw   0xF0 
        btfsc   bcdL,7 
        andlw   0x0F 
        subwf   bcdL 
        
        movlw   0x03 
        addwf   bcdH 
        btfss   bcdH,3 
        subwf   bcdH 
        
        rlf     binL            ; shift out a binary bit 
        rlf     binH 
        rlf     bcdL            ; into BCD result 
        rlf     bcdH 
        
        decfsz  count           ; repeat for all bits 
        goto    bcd_lp 
        return                  ; exit
 

WBahn

Joined Mar 31, 2012
29,976
The first step is to study the program to understand what it does and how it does it. To do that, it might be helpful to walk through an example or two by hand. Then, armed with that knowledge, walk through what you need to do and identify how it is similar and how it differs. Then make your mods (or you may find it easier to just write your own from scratch if the mods are too extensive).
 

WBahn

Joined Mar 31, 2012
29,976
Yes, I know how to do it. I learned how to do it without having any code to use as a starting point, either. If you alway take the approach of asking someone else to just tell you how to modify yet someone else's code to do what you need, then you shouldn't be surprised if that becomes the only approach you know how to take.

I am more than willing to help you with your walk through, but only as you make efforts on your own to do it.
 

Thread Starter

Dodgydave

Joined Jun 22, 2012
11,284
Yes, I know how to do it. I learned how to do it without having any code to use as a starting point, either. If you alway take the approach of asking someone else to just tell you how to modify yet someone else's code to do what you need, then you shouldn't be surprised if that becomes the only approach you know how to take.

I am more than willing to help you with your walk through, but only as you make efforts on your own to do it.
Jut give me the answer then.
 

MrChips

Joined Oct 2, 2009
30,707
I can show you how to do it with another mcu such as Freescale, Atmel AVR or TI MSP430.
For Microchip PIC, I wouldn't touch it with a 10-foot pole.
 

Thread Starter

Dodgydave

Joined Jun 22, 2012
11,284
I can show you how to do it with another mcu such as Freescale, Atmel AVR or TI MSP430.
For Microchip PIC, I wouldn't touch it with a 10-foot pole.
ok, do i have to add another file on the end to rotate left, and then unpack it into 5, and increase the counter to 16 ?

I just wish people would give me the answer i need, instead of adding to my problem.
 

MrChips

Joined Oct 2, 2009
30,707
Here is a basic algorithm for any microcontroller.

Assuming that the mcu does not have 16-bit registers nor 16-bit operations, you will use two 8-bit registers to represent a 16-bit unsigned integer.

Count how many times you can repeatedly subtract 10,000. This will give you the TENK digit. Save the remainder.

Do the same with the remainder using 1000, 100, 10.

The last remainder is the UNITS.

Done.
 

Thread Starter

Dodgydave

Joined Jun 22, 2012
11,284
As I said, I'm more than willing to help you as you make efforts to work through it yourself. But if all you want is a handout, then look to someone else to do your work for you.
do i add an extra file at the end to unpack into and alter the counter to 16, if so how are the digits stored is it 655 in the bcdh and 35 in the bcdl, i just cant work it out?
 

JohnInTX

Joined Jun 26, 2012
4,787
The routines given to you in last week's thread do exactly what you asked and are asking - convert 16 bit binary to 5 BCD digits packed and unpacked. Its written for baseline but works in midrange and 18F with minor revs to the FSR references.

For 18F:
In adjDEC, change movlw to lfsr 0,R2ADDR etc
In adjBCD, omit movwf FSR, its already set by the preceding
change INDF to INDF0
change rlf to rlcf
Delete clrf FSR at the end of unpackit

You can easily run this in MPSIM to see how it works and how the results are represented.
 
Last edited:

THE_RB

Joined Feb 11, 2008
5,438
Dodgydave, while you are still in the steep learning curve where simple things cause long problems, you should really REALLY consider switching to C and using a C compiler instead of coding in assembler.

The task you are asking about (which is a long complex hassle in assembler) can be done this easily in C;
WordToStr(num,txt);

:)
 

WBahn

Joined Mar 31, 2012
29,976
do i add an extra file at the end to unpack into and alter the counter to 16, if so how are the digits stored is it 655 in the bcdh and 35 in the bcdl, i just cant work it out?
I'm not sure I'm following what you are talking about, so tell me if this is close:

Given the value 65536 (i.e., a 16-bit unsigned value with all 16 bits HI), how would that be represented in an unpacked BCD representation?

If so, then you would have five file registers (using the names from your first post) with the contents as shown below:

TENK = 0x06
THOU = 0x05
HUNS = 0x05
TENS = 0x03
UNITS = 0x05

I would tend to call them bcd0 (for UNITS) and bcd4 (for TENK). But it's arbitrary.

In your question here you seem to be asking about a packed BCD representation. Since you seem to be talking about 8-bit bytes, you can only store two digits in each byte. So you would need three bytes with the following values:

bcdh = 0x06 (.6)
bcdm = 0x55 (.85)
bcdl = 0x35 (.53)

If you were talking about a 16-bit machine, then a packed BCD representation would be like this:

bcdh = 0x0006 (.6)
bcdl = 0x5535 (.21813)

First, it is important that you understand the fundamental representations involved.

The 16-bit unsigned binary value is represented using 16 bits in which the weight of each bit is a different power of two, starting with 2^0 for the least significant bit (lsb) and ending with 2^15 for the most significant bit (msb). The value represented is then just the sum of 16 terms in which each term is the product of the value of a bit and that bit's weight.

The BCD value is represented by a sequence of 4-bit groups. Within each group, the four bits are represented using unsigned binary with weights running from 2^0 to 2^3. However, the constraint is added that the value represented by any group cannot be outside the range of 0 to 9. Each of these groups is therefore used to represent a decimal digit and each group as a whole is given a decimal weight starting with 10^0 for the least significant digit (lsd) and going up from there. For your 5-digit system, your most significant digit (msd) would have a weight of 10^4. Hence you can see the meaning behind the term "binary-coded decimal".

Restricting the discussion to systems that work with 8-bit bytes (at least for now), we have a couple of options. We can allocate one byte per BCD digit. This is called "unpacked BCD". It has the advantage that it is easy (or at least easier) to work with and runs faster for most purposes. It has the disadvantage that in each byte you have four bits that are always zero. In fact, of the 256 possible values that can be represented using that byte of storage, you are only using 10. So it is pretty wasteful and in many microcontrollers, even today, storage is at a premium.

But with an 8-bit byte we have enough room to store two BCD digits in a single byte. This is called "packed BCD". We do this by storing one BCD digit in the lower four bits and one BCD digit in the upper four bits. Thus, we are now using 100 of the possible patterns that can be represented by each byte of storage, which is much better. But our processing gets more complicated and so is generally slower. Evening in engineering is a compromise.

On a processor with a 16-bit word we can store four BCD digits and if we are working with a 32-bit word we can store eight.

When you are first getting your feet wet, keep things simple for as long as possible. Use unpacked BCD where you need access to the individual digits. Also, figure out how to convert back and forth between binary and unpacked BCD and then, separately, how to convert back and forth between packed and unpacked BCD. Don't even mess with trying to convert directly between binary and packed BCD until you have a compelling reason to do so.

Since you have indicated that you want to work with unpacked BCD (by way of indicating five different file registers for the five different decimal digits), let's forget about packed BCD, at least for now.

One of the best ways to come up with an algorithm is to consider how you would do something manually. See the next post.
 

WBahn

Joined Mar 31, 2012
29,976
So consider this algorithm for a "game" we might play:

1) I take five cards and I label them, in ink, TENK, THOU, HUND, TENS, UNITS. I write, in pencil, zeros on all of them. I give you the UNITS card while I keep the other four.

2) I ask you to come up with a number between 0 and 65535, inclusive but don't tell me what it is. I tell you to write that number on the UNITS, in pencil.

3) I then pick up the TENK card.

4) I ask you if the number presently on UNITS is at least 50,000. If you say YES, then I tell you to replace the number on the card with the number minus 50,000 and I replace the number on my card with the number that is currently there plus 5. If you say NO, I do nothing.

5) I ask you if the number presently on UNITS is at least 20,000. If you say YES, then I tell you to replace the number on the card with the number minus 20,000 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

6) I ask you if the number presently on UNITS is at least 20,000. If you say YES, then I tell you to replace the number on the card with the number minus 20,000 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

7) I ask you if the number presently on UNITS is at least 10,000. If you say YES, then I tell you to replace the number on the card with the number minus 10,000 and I replace the number on my card with the number that is currently there plus 1. If you say NO, I do nothing.

8) I then set the TENK card aside and pick up the THOU card.

9) I ask you if the number presently on UNITS is at least 5,000. If you say YES, then I tell you to replace the number on the card with the number minus 5,000 and I replace the number on my card with the number that is currently there plus 5. If you say NO, I do nothing.

10) I ask you if the number presently on UNITS is at least 2,000. If you say YES, then I tell you to replace the number on the card with the number minus 2,000 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

11) I ask you if the number presently on UNITS is at least 2,000. If you say YES, then I tell you to replace the number on the card with the number minus 2,000 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

12) I ask you if the number presently on UNITS is at least 1,000. If you say YES, then I tell you to replace the number on the card with the number minus 1,000 and I replace the number on my card with the number that is currently there plus 1. If you say NO, I do nothing.

13) I then set the THOU card aside and pick up the HUND card.

14) I ask you if the number presently on UNITS is at least 500. If you say YES, then I tell you to replace the number on the card with the number minus 500 and I replace the number on my card with the number that is currently there plus 5. If you say NO, I do nothing.

15) I ask you if the number presently on UNITS is at least 200. If you say YES, then I tell you to replace the number on the card with the number minus 200 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

16) I ask you if the number presently on UNITS is at least 200. If you say YES, then I tell you to replace the number on the card with the number minus 200 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

17) I ask you if the number presently on UNITS is at least 100. If you say YES, then I tell you to replace the number on the card with the number minus 100 and I replace the number on my card with the number that is currently there plus 1. If you say NO, I do nothing.

18) I then set the HUND card aside and pick up the TENS card.

19) I ask you if the number presently on UNITS is at least 50. If you say YES, then I tell you to replace the number on the card with the number minus 50 and I replace the number on my card with the number that is currently there plus 5. If you say NO, I do nothing.

20) I ask you if the number presently on UNITS is at least 20. If you say YES, then I tell you to replace the number on the card with the number minus 20 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

21) I ask you if the number presently on UNITS is at least 20. If you say YES, then I tell you to replace the number on the card with the number minus 20 and I replace the number on my card with the number that is currently there plus 2. If you say NO, I do nothing.

22) I ask you if the number presently on UNITS is at least 10. If you say YES, then I tell you to replace the number on the card with the number minus 10 and I replace the number on my card with the number that is currently there plus 1. If you say NO, I do nothing.

23) Finally, I ask you to give me the UNITS card back.

I now have five cards that contain the five decimal digits of the number you originally picked.

All we did was start with a value on one side and zero on another side and then subtract an amount from the first side whille adding that same amount to the other side using the appropriate representation for each side along the way. If you think about it, this was true even for the UNITS card at the end. You giving it to me effectively subtracted it from your side, using the binary representation, while adding it to mine, using the BCD representation. We could do this by a simple handover because, of a one decimal digit values, the representations are the same.

The above algorithm is one of the fastest ones you can imagine (short of a lookup table) but is longer codewise because it has no loops.

You can easily make a loop for each card by changing the algorithm. See the next post.
 

WBahn

Joined Mar 31, 2012
29,976
1) I take five cards and I label them, in ink, TENK, THOU, HUND, TENS, UNITS. I write, in pencil, zeros on all of them. I give you the UNITS card while I keep the other four.

2) I ask you to come up with a number between 0 and 65535, inclusive but don't tell me what it is. I tell you to write that number on the UNITS, in pencil.

3) I then pick up the TENK card.

4) I ask you if the number presently on UNITS is at least 10,000. If you say YES, then I tell you to replace the number on the card with the number minus 10,000 and I replace the number on my card with the number that is currently there plus 1. I then repeat this step. If you say NO, I do nothing.

5) I then set the TENK card aside and pick up the THOU card.

6) I ask you if the number presently on UNITS is at least 1,000. If you say YES, then I tell you to replace the number on the card with the number minus 1,000 and I replace the number on my card with the number that is currently there plus 1. I then repeat this step. If you say NO, I do nothing.

7) I then set the THOU card aside and pick up the HUND card.

8) I ask you if the number presently on UNITS is at least 100. If you say YES, then I tell you to replace the number on the card with the number minus 100 and I replace the number on my card with the number that is currently there plus 1. I then repeat this step. If you say NO, I do nothing.

9) I then set the HUND card aside and pick up the TENS card.

10) I ask you if the number presently on UNITS is at least 10. If you say YES, then I tell you to replace the number on the card with the number minus 10 and I replace the number on my card with the number that is currently there plus 1. I then repeat this step. If you say NO, I do nothing.

11) Finally, I ask you to give me the UNITS card back.

I now have five cards that contain the five decimal digits of the number you originally picked.

I could tighten this up even more by using another file register, called WEIGHT, that starts out at 10,000 and then gets reduced by an order of magnitude in each pass until it is equal to 1. This algorithm works best with an array representation for the file registers that make up the BCD value.
 

MrChips

Joined Oct 2, 2009
30,707
Of course there are more than one ways to skin a cat.

Write a routine to divide a 16-bit unsigned integer by 10, saving the quotient and remainder.
The first division by 10 will reveal the UNITS in the remainder.
Keep on doing this until the quotient is zero.
 

WBahn

Joined Mar 31, 2012
29,976
Yep, and if your part has hardware divide that is sufficiently fast this is a good option. Or, if speed isn't a consideration it has the advantage of being simple and easy to implement and maintain. But in most cases, the software divide is pretty costly performance wise.
 

Thread Starter

Dodgydave

Joined Jun 22, 2012
11,284
Wbahn,i have no idea what the hell your on about with the cards, How do i alter my programme to make add two 8bit files, and put them into five decimal ones, THOUK, THOU,HUNS,TENS,UNITS,
 
Top