# 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
809
6
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.

2. ### hgmjr Retired Moderator

Jan 28, 2005
9,030
218
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
18,198
5,717
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

Sep 21, 2011
809
6
5. ### MrChips Moderator

Oct 2, 2009
18,198
5,717
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
809
6
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?

7. ### hgmjr Retired Moderator

Jan 28, 2005
9,030
218
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
809
6
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.

9. ### MrChips Moderator

Oct 2, 2009
18,198
5,717
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
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
809
6
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.
18. SUBLW .1
19. BTFSS STATUS,C
22. INCF ones
23. BRA CONVERT_ONES
24.
25.
27.
28. MOVF tens                   ;add 48 to huns and ones to convert them to ASCII
30. MOVWF tens
31.
32. MOVF ones
34. MOVWF ones

Last edited: Feb 20, 2012
11. ### MrChips Moderator

Oct 2, 2009
18,198
5,717
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
809
6
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
18,198
5,717
Maybe you are correct. I am not a PIC programmer.

14. ### Markd77 Senior Member

Sep 7, 2009
2,796
595
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,973
1,834
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 AAC Fanatic!

Jul 5, 2008
1,731
345
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
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,430
1,311
// 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 Distinguished Member

Feb 14, 2010
838
161
How about five words in assembly language?

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

Code ( (Unknown Language)):
2. b2d99
3.         clrf    tens            ;
5.         rlf     tens,F          ;
6.         btfss   tens,0          ;
9.         rlf     tens,F          ;
10.         btfss   tens,0          ;
13.         rlf     tens,F          ;
14.         btfss   tens,0          ;
17.         rlf     tens,F          ;
18.         btfss   tens,0          ;
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
18,198
5,717
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 AAC Fanatic!

Jul 5, 2008
1,731
345
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