Binary to ASCII (2 digits)

Discussion in 'Programmer's Corner' started by Dritech, Feb 18, 2012.

  1. Dritech

    Thread Starter Well-Known Member

    Sep 21, 2011
    756
    5
    Hi all,

    I want to convert an 8 bit binary value to a two digit ASCII value.

    Does anyone know of a tutorial to do this? or can someone guide me on how to do it?

    By the way, i am programming in assembly and the MC being used is a PIC 18F.

    Thanks in advance.
     
  2. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    You might want to take a look at some of the routines at this link. They may give you some ideas.

    hgmjr
     
  3. MrChips

    Moderator

    Oct 2, 2009
    12,437
    3,360
    As in any programming problem such as this one, you need to come up with a clear, precise algorithm. This particular problem is not so difficult.

    8-bit binary can represent unsigned integer values from 0 to 255. Hence you will need three decimal digits to cover the range. The result you are seeking is

    N = D2 x 100 + D1 x 10 + D0 x 1

    where N = 8-bit binary and D2, D1, D0 are the resulting decimal digits.

    If your MCU has an efficient integer division instruction you can use this to find D2, D1, D0 by dividing by 100 and by 10. Atmel and Freescale MCUs have integer division which makes this problem a trivial one.

    If you want to try this without a divide operation the algorithm is as follows.

    1. Find how many times (D2) you can subtract 100 from N without underflowing. Save the remainder R.

    2. Find how many times (D1) you can subtract 10 from R without underflowing. The remainder is D0.

    This is a classic programming exercise for every student learning to program in ASM and C.
    Try to do it in both languages.
     
    Last edited: Feb 18, 2012
  4. Dritech

    Thread Starter Well-Known Member

    Sep 21, 2011
    756
    5
  5. MrChips

    Moderator

    Oct 2, 2009
    12,437
    3,360
    Do yourself a favour and ignore someone else's code. You can learn a lot more by trying to do it yourself with the information I have given you.
     
  6. Dritech

    Thread Starter Well-Known Member

    Sep 21, 2011
    756
    5
    OK, i will try to do it by myself.

    I only need 2 decimal digits since i am going to use this to measure water temperature (which cannot exceed 100°C). The reason that i said 8 bits is that the ADC is 8 bit mode.

    Can you explain to me how this method exactly works? and how to display the 1's?

    Thanks in advance
     
  7. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    I agree that is always better to do it yourself. You will definitely learn more. The link I provided can serve as a guide to see how someone else has accomplished the coding task.

    hgmjr
     
  8. Dritech

    Thread Starter Well-Known Member

    Sep 21, 2011
    756
    5
    Hi,
    how can i separate the hundreds from the ones please?

    Lets assume we have 85 decimal, how to separate 8 from 5 ?

    If you can help me with this, i think i will be able to do the bin to ascii conversion.

    Thanks in advance.
     
  9. MrChips

    Moderator

    Oct 2, 2009
    12,437
    3,360
    If your MCU has an integer divide instruction the solution is trivial.
    Divide 85 by 10. The result is 8 and the remainder is 5.

    If you do not have a divide instruction, here is the software algorithm:

    Assume N = unknown number, 00-99

    1. Set COUNT = 0
    2. Test if N < 10, if yes go to step 6
    3. Add 1 to COUNT
    4. Subtract 10 from N
    5. Go to step 2
    6. Tens digit = COUNT, one's digit = N
    7. Done
     
  10. Dritech

    Thread Starter Well-Known Member

    Sep 21, 2011
    756
    5
    Hi,

    I am trying to do the coding on my own. The coding is the one below, but for some reason its not working. Can you please help me figure out what is wrong?

    Code ( (Unknown Language)):
    1. CLRF tens                   ;clear registers
    2. CLRF ones
    3.  
    4. CONVERT_TENS    ;convert the tens into ascii value routine
    5.  
    6. MOVF ADRESH                 ;move the a2d result to the working register
    7. SUBLW .10                      ;subtract by 10
    8. BTFSS STATUS,C              ;is the result still a positive number
    9. GOTO CONVERT_ONES    ;if its a negative, go to convert the ones
    10. MOVWF ADRESH           ;if still positive, move the new subtracted result to the ADRESH register
    11. INCF tens                        ;and increment the tens register by 1
    12. BRA CONVERT_TENS       ;keep looping until the result is a negative value
    13.  
    14.  
    15. CONVERT_ONES
    16.  
    17. MOVF ADRESH
    18. SUBLW .1
    19. BTFSS STATUS,C
    20. GOTO READY
    21. MOVWF ADRESH
    22. INCF ones
    23. BRA CONVERT_ONES
    24.  
    25.  
    26. READY
    27.  
    28. MOVF tens                   ;add 48 to huns and ones to convert them to ASCII
    29. ADDLW .48
    30. MOVWF tens
    31.  
    32. MOVF ones
    33. ADDLW .48
    34. MOVWF ones
     
    Last edited: Feb 20, 2012
  11. MrChips

    Moderator

    Oct 2, 2009
    12,437
    3,360
    Two problems.
    1) After you subtract 10 and find out that the number is negative, you have to add 10 back.
    2) After you have found the 10's digit you do not need to find the 1's digit. It is already what is remaining.
     
  12. Dritech

    Thread Starter Well-Known Member

    Sep 21, 2011
    756
    5
    Hi,

    Is there the need to add 10 back? since its only subtracting the working register and not the ADRESH register.

    Thanks
     
  13. MrChips

    Moderator

    Oct 2, 2009
    12,437
    3,360
    Maybe you are correct. I am not a PIC programmer.
     
  14. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Maybe part of the problem is SUBLW which subtracts W from a literal.
    If you want to subtract a literal from W, an option is to use ADDLW (256-literal), or maybe 255-literal - I'm not thinking straight at the moment.
     
  15. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    Now it happens that I am a PIC programmer. I did not test your code, but you can.

    Inside MPLAB there is a simulator where you can watch your code at work even if you do not have an PIC hardware connected. It simulates the PIC, meaning it follows your code and sets the registers accordingly. You can even add stimulus to change input pins.

    You enable the simulator on the menu by clicking Debugger | Select Tool | MPLAB SIM. You can view the registers and such by opening items in the VIEW menu.
     
  16. be80be

    Senior Member

    Jul 5, 2008
    431
    57
    Here you some code to look at it changes the whole 10 bits
    Code ( (Unknown Language)):
    1.  
    2.  
    3.  
    4. #include <p16f628a.inc>
    5.  
    6.              cblock 0x40
    7.                cflag
    8.                quotient
    9.                divisor:0, divisor_low, divisor_high
    10.                work:0, work_low, work_high
    11.  
    12.                wvalue:0, wvalue_low, wvalue_high
    13.              endc
    14.  
    15.  
    16.              org 0
    17.  
    18. start        movlw D'123'       ; "123"
    19.              call  B2Ascii
    20.  
    21.              movlw D'48'        ; "12345" (48 * 256) + 57
    22.              movwf wvalue_high
    23.              movlw D'57'      
    24.              movwf wvalue_low
    25.              call  W2Ascii
    26.  
    27. lp:          goto  lp
    28.  
    29. ;-------------------------------------------------------------------
    30. ; Convert byte value in W to 3 ASCII digits with leading zero
    31. ; suppression (12 = " 12"). W is destroyed
    32. ;-------------------------------------------------------------------
    33. B2Ascii:     movwf work         ; Move byte to work area
    34.              bcf   cflag, 0     ; Reset leading zero supression flag
    35.              movlw d'100'       ; -- Hundreds
    36.              movwf divisor      ;
    37.              call divide8       ;
    38.              call output        ; Output hundreds, digit is in W
    39.              movlw d'10'        ; -- Tens
    40.              movwf divisor      ;
    41.              call  divide8      ;
    42.              call  output       ; Output tens, digit in W
    43.              movlw d'1'     ; -- Ones
    44.              movwf divisor      ;
    45.              bsf   cflag, 0     ; Remove leading zero suppression in case of zero
    46.              call  divide8      ;
    47.              call  output       ; Output ones, digit is in W
    48.              return
    49.  
    50. divide8:     clrf quotient      ; Divide 8 bit dividend with 8 bit divisor
    51.              movfw divisor      ; using repetitive subtraction method
    52. div8_1:      subwf work, W      ; Test to see if division is complete
    53.              skpc               ;
    54.              goto divcommon     ;
    55.              incf quotient, F   ; Bump quotient and subtract divisor
    56.              movfw divisor      ; from what's left of the original
    57.              subwf work, F      ; dividend.
    58.              bsf cflag, 0       ; Indicate that we have a non-zero digit
    59.              goto div8_1        ; and continue
    60.  
    61. ;-------------------------------------------------------------------
    62. ; Convert word value stored in wvalue to 5 ASCII digits with leading
    63. ; zero suppression (1234 = " 1234"). wvalue is preserved.
    64. ;-------------------------------------------------------------------
    65. W2Ascii:     movfw wvalue_low   ; Copy word value to work area
    66.              movwf work_low     ;
    67.              movfw wvalue_high  ;
    68.              movwf work_high    ;
    69.              bcf   cflag, 0     ; Reset leading zero supression flag
    70.              movlw d'16'        ; -- Ten thousands
    71.              movwf divisor_low  ;
    72.              movlw d'39'        ;
    73.              movwf divisor_high ;
    74.              call  divide16     ;
    75.              call  output       ; Output ten thousands, digit is in W
    76.              movlw d'232'       ; -- Thousands
    77.              movwf divisor_low  ;
    78.              movlw d'3'         ;
    79.              movwf divisor_high ;
    80.              call  divide16     ;
    81.              call  output       ; Output thousands, digit is in W
    82.              movlw d'100'       ; -- Hundreds
    83.              movwf divisor_low  ;
    84.              clrf  divisor_high ;
    85.              call  divide16     ;
    86.              call  output       ; Output hundreds, digit is in W
    87.              movlw d'10'        ; -- Tens
    88.              movwf divisor_low  ;
    89.              clrf  divisor_high ;
    90.              call  divide16     ;
    91.              call  output       ; Output tens, digit in W
    92.              movlw d'1'     ; -- Ones
    93.              movwf divisor_low  ;
    94.              clrf  divisor_high ;
    95.              bsf   cflag, 0     ; Remove leading zero suppression in case of zero
    96.              call  divide16     ;
    97.              call  output       ; Output ones, digit is in W
    98.              return
    99.  
    100. divide16:    clrf  quotient     ; Divide 16 bit dividend with 16 bit divisor
    101. div16_1:     movfw divisor_high ; Test to see if division is complete
    102.              subwf work_high, W ;
    103.              skpc               ;
    104.              goto  divcommon    ;
    105.              bnz   div16_2      ;
    106.              movfw divisor_low  ;
    107.              subwf work_low, W  ;
    108.              skpc               ;
    109.              goto  divcommon    ;
    110. div16_2:     movfw divisor_high ; Subtract high part of divisor from the
    111.              subwf work_high, F ; remainder of the dividend
    112.              movfw divisor_low  ; Subtract low part of divisor from the
    113.              subwf work_low, F  ; rest of the dividend
    114.              skpc               ; If a carry, subtract from the upper
    115.              decf  work_high, F ; part of the remaining dividend
    116.              incf  quotient, F  ; Bump up the quotient
    117.              bsf   cflag, 0     ; Indicate that we have a non-zero digit
    118.              goto  div16_1      ; and continue
    119.  
    120.  
    121. divcommon:   movlw '0'           ; Add ASCII bias but blank out
    122.              addwf quotient, W   ; any leading zero digits
    123.              btfss cflag, 0      ; If we haven't seen any non-zero digits to
    124.              movlw ' '           ; this point, return a space instead of a '0'
    125.              return              ;
    126.  
    127. output:      nop
    128.              return              ; Send the digit to the serial port or whatever
    129.  
    130.  
    131.              end
    132.  
     
  17. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    // this code converts an 8bit number into 2 digits, range; 0 to 99
    digitH = 0;
    while(number >= 10)
    {
    digitH = digitH + 1;
    number = number - 10;
    }
    digitL = number;

    you should be able to write that as about 10 assembler instructions.
     
  18. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    How about five words in assembly language?

    Code ( (Unknown Language)):
    1. ;
    2. ;  Binary-to-Decimal, 00..99
    3. ;
    4.     radix   dec
    5. btod99
    6.     setf    Tens        ; tens = -1
    7. div10
    8.     movwf   Ones        ;
    9.     incf    Tens,F      ;
    10.     addlw   -10     ;
    11.     bc  div10       ;
    12.  
    13.  
    Or, if you need an isochronous solution (18 words/18 cycles);

    Code ( (Unknown Language)):
    1.     radix   dec
    2. b2d99
    3.         clrf    tens            ;
    4.         addlw   -80             ;
    5.         rlf     tens,F          ;
    6.         btfss   tens,0          ;
    7.         addlw   80              ;
    8.         addlw   -40             ;
    9.         rlf     tens,F          ;
    10.         btfss   tens,0          ;
    11.         addlw   40              ;
    12.         addlw   -20             ;
    13.         rlf     tens,F          ;
    14.         btfss   tens,0          ;
    15.         addlw   20              ;
    16.         addlw   -10             ;
    17.         rlf     tens,F          ;
    18.         btfss   tens,0          ;
    19.         addlw   10              ;
    20.         movwf   ones            ;
    21.  
    Here's another isochronous routine for 8-bits (0..255) from a brain-storming session on Forum.Microchip (16 words/16 cycles);

    Code ( (Unknown Language)):
    1. ;
    2. ;   input: WREG = 0x00..0xFF, 0..255
    3. ;
    4.         movwf   ones            ; save "ones"
    5.         mullw   .205            ; divide by 10
    6.         movf    PRODH, W        ;
    7.         mullw   .32             ;
    8.         movf    PRODH, W        ;
    9.         movwf   tens            ; save "tens", 0..25
    10.         mullw   .10             ; multiply by 10
    11.         movf    PRODL,W         ;
    12.         subwf   ones,F          ; ones -= (tens*10)
    13.         movf    tens,W          ; 0..25
    14.         mullw   .26             ; divide by 10
    15.         movf    PRODH,W         ; 0..2
    16.         movwf   huns        ; save "huns", 0..2
    17.         mullw   .10             ; multiply by 10
    18.         movf    PRODL,W         ;
    19.         subwf   tens,F          ; tens -= (huns*10)
    20.  
     
    Last edited: Feb 21, 2012
  19. MrChips

    Moderator

    Oct 2, 2009
    12,437
    3,360
    Nice, on both counts. Even I have not seen it done like this before. (Both the iso and non-iso versions)

    (Can you show the 7 words code as well for comparison?)
     
  20. be80be

    Senior Member

    Jul 5, 2008
    431
    57
    Rb I seen code just like what you posted can't remember where I seen it But it was using the same math but. But it was coded for intel 386 But there was nice code at the site maybe i'll find it agin LOL
     
Loading...