16BIT BIN TO BCD 5 digits

Discussion in 'Embedded Systems and Microcontrollers' started by Dodgydave, Jul 28, 2013.

  1. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
    How can i modify this Asm file to give me a 5 files digit, TENK, THOU, HUNS,TENS, UNITS

    for an 18f2321
    Code ( (Unknown Language)):
    1.  
    2.  
    3. LEFT JUSTIFIED, UPPER 8 BITS IN ADRESH, LOWER 2 BITS IN ADRESL
    4.  
    5.  
    6.  
    7.  swapf   bcdH,w          ; unpack BCD digits
    8.         andlw   0x0F
    9.         movwf   thou
    10.         movf    bcdH,w
    11.         andlw   0x0F
    12.         movwf   huns
    13.        
    14.         swapf   bcdL,w
    15.         andlw   0x0F
    16.         movwf   tens
    17.         movf    bcdL,w
    18.         andlw   0x0F
    19.         movwf   ones
    20.         goto    $
    21. ;-------------------------------
    22. ;
    23. ; Upper 10-bit Binary To Packed BCD Digits
    24. ;
    25. Bin10ToBCD4
    26.         clrf    bcdL            ; clear result
    27.         clrf    bcdH
    28.         movlw   .10             ; set bit counter
    29.         movwf   count
    30.        
    31. bcd_lp  movlw   0x33            ; adjust BCD result
    32.         addwf   bcdL
    33.         btfsc   bcdL,3
    34.         andlw   0xF0
    35.         btfsc   bcdL,7
    36.         andlw   0x0F
    37.         subwf   bcdL
    38.        
    39.         movlw   0x03
    40.         addwf   bcdH
    41.         btfss   bcdH,3
    42.         subwf   bcdH
    43.        
    44.         rlf     binL            ; shift out a binary bit
    45.         rlf     binH
    46.         rlf     bcdL            ; into BCD result
    47.         rlf     bcdH
    48.        
    49.         decfsz  count           ; repeat for all bits
    50.         goto    bcd_lp
    51.         return                  ; exit  
    52.  
    53.  
     
  2. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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).
     
  3. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
    If i knew what to do i would not be asking questions would i !

    do you know how to do it?
     
  4. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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.
     
  5. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
    Jut give me the answer then.
     
  6. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    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.
     
    absf likes this.
  7. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
    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.
     
  8. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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.
     
    absf and JohnInTX like this.
  9. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    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.
     
    Dodgydave likes this.
  10. absf

    Senior Member

    Dec 29, 2010
    1,492
    372
  11. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
    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?
     
  12. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
  13. JohnInTX

    Moderator

    Jun 26, 2012
    2,341
    1,024
    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: Jul 28, 2013
    Dodgydave likes this.
  14. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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);

    :)
     
  15. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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.
     
  16. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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.
     
  17. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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.
     
  18. MrChips

    Moderator

    Oct 2, 2009
    12,432
    3,360
    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.
     
  19. WBahn

    Moderator

    Mar 31, 2012
    17,720
    4,788
    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.
     
  20. Dodgydave

    Thread Starter Distinguished Member

    Jun 22, 2012
    4,974
    744
    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,
     
Loading...