Binary to ASCII (2 digits)

Thread Starter

Dritech

Joined Sep 21, 2011
901
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.
 

MrChips

Joined Oct 2, 2009
30,810
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:

MrChips

Joined Oct 2, 2009
30,810
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.
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
OK, i will try to do it by myself.

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.
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.

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.
Can you explain to me how this method exactly works? and how to display the 1's?

Thanks in advance
 

hgmjr

Joined Jan 28, 2005
9,027
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.
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
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
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.
 

MrChips

Joined Oct 2, 2009
30,810
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
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
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?

Rich (BB code):
CLRF tens                   ;clear registers
CLRF ones
 
CONVERT_TENS    ;convert the tens into ascii value routine
 
MOVF ADRESH                 ;move the a2d result to the working register
SUBLW .10                      ;subtract by 10
BTFSS STATUS,C              ;is the result still a positive number
GOTO CONVERT_ONES    ;if its a negative, go to convert the ones
MOVWF ADRESH           ;if still positive, move the new subtracted result to the ADRESH register
INCF tens                        ;and increment the tens register by 1 
BRA CONVERT_TENS       ;keep looping until the result is a negative value
 
 
CONVERT_ONES
 
MOVF ADRESH
SUBLW .1
BTFSS STATUS,C
GOTO READY
MOVWF ADRESH
INCF ones
BRA CONVERT_ONES
 
 
READY
 
MOVF tens                   ;add 48 to huns and ones to convert them to ASCII
ADDLW .48
MOVWF tens
 
MOVF ones
ADDLW .48
MOVWF ones
 
Last edited:

MrChips

Joined Oct 2, 2009
30,810
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.
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
1) After you subtract 10 and find out that the number is negative, you have to add 10 back.
Hi,

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

Thanks
 

Markd77

Joined Sep 7, 2009
2,806
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.
 

ErnieM

Joined Apr 24, 2011
8,377
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.
 

be80be

Joined Jul 5, 2008
2,072
Here you some code to look at it changes the whole 10 bits
Rich (BB code):
#include <p16f628a.inc>

             cblock 0x40
               cflag
               quotient
               divisor:0, divisor_low, divisor_high
               work:0, work_low, work_high

               wvalue:0, wvalue_low, wvalue_high
             endc


             org 0

start        movlw D'123'       ; "123"
             call  B2Ascii

             movlw D'48'        ; "12345" (48 * 256) + 57
             movwf wvalue_high 
             movlw D'57'       
             movwf wvalue_low
             call  W2Ascii

lp:          goto  lp

;-------------------------------------------------------------------
; Convert byte value in W to 3 ASCII digits with leading zero
; suppression (12 = " 12"). W is destroyed
;-------------------------------------------------------------------
B2Ascii:     movwf work         ; Move byte to work area
             bcf   cflag, 0     ; Reset leading zero supression flag
             movlw d'100'       ; -- Hundreds
             movwf divisor      ;
             call divide8       ;
             call output        ; Output hundreds, digit is in W
             movlw d'10'        ; -- Tens
             movwf divisor      ;
             call  divide8      ;
             call  output       ; Output tens, digit in W
             movlw d'1'		; -- Ones
             movwf divisor      ;
             bsf   cflag, 0     ; Remove leading zero suppression in case of zero
             call  divide8      ;
             call  output       ; Output ones, digit is in W
             return

divide8:     clrf quotient      ; Divide 8 bit dividend with 8 bit divisor
             movfw divisor      ; using repetitive subtraction method
div8_1:      subwf work, W      ; Test to see if division is complete
             skpc               ;
             goto divcommon     ;
             incf quotient, F   ; Bump quotient and subtract divisor
             movfw divisor      ; from what's left of the original
             subwf work, F      ; dividend.
             bsf cflag, 0       ; Indicate that we have a non-zero digit
             goto div8_1        ; and continue

;-------------------------------------------------------------------
; Convert word value stored in wvalue to 5 ASCII digits with leading 
; zero suppression (1234 = " 1234"). wvalue is preserved.
;-------------------------------------------------------------------
W2Ascii:     movfw wvalue_low   ; Copy word value to work area
             movwf work_low     ;
             movfw wvalue_high  ;
             movwf work_high    ;
             bcf   cflag, 0     ; Reset leading zero supression flag
             movlw d'16'        ; -- Ten thousands
             movwf divisor_low  ;
             movlw d'39'        ;
             movwf divisor_high ;
             call  divide16     ;
             call  output       ; Output ten thousands, digit is in W
             movlw d'232'       ; -- Thousands
             movwf divisor_low  ;
             movlw d'3'         ;
             movwf divisor_high ;
             call  divide16     ;
             call  output       ; Output thousands, digit is in W
             movlw d'100'       ; -- Hundreds
             movwf divisor_low  ;
             clrf  divisor_high ;
             call  divide16     ;
             call  output       ; Output hundreds, digit is in W
             movlw d'10'        ; -- Tens
             movwf divisor_low  ;
             clrf  divisor_high ;
             call  divide16     ;
             call  output       ; Output tens, digit in W
             movlw d'1'		; -- Ones
             movwf divisor_low  ;
             clrf  divisor_high ;
             bsf   cflag, 0     ; Remove leading zero suppression in case of zero
             call  divide16     ;
             call  output       ; Output ones, digit is in W
             return

divide16:    clrf  quotient     ; Divide 16 bit dividend with 16 bit divisor
div16_1:     movfw divisor_high ; Test to see if division is complete
             subwf work_high, W ;
             skpc               ;
             goto  divcommon    ;
             bnz   div16_2      ;
             movfw divisor_low  ;
             subwf work_low, W  ;
             skpc               ;
             goto  divcommon    ;
div16_2:     movfw divisor_high ; Subtract high part of divisor from the
             subwf work_high, F ; remainder of the dividend
             movfw divisor_low  ; Subtract low part of divisor from the
             subwf work_low, F  ; rest of the dividend
             skpc               ; If a carry, subtract from the upper
             decf  work_high, F ; part of the remaining dividend
             incf  quotient, F  ; Bump up the quotient
             bsf   cflag, 0     ; Indicate that we have a non-zero digit
             goto  div16_1      ; and continue


divcommon:   movlw '0'           ; Add ASCII bias but blank out
             addwf quotient, W   ; any leading zero digits
             btfss cflag, 0      ; If we haven't seen any non-zero digits to
             movlw ' '           ; this point, return a space instead of a '0'
             return              ;

output:      nop
             return              ; Send the digit to the serial port or whatever


             end
 

THE_RB

Joined Feb 11, 2008
5,438
// 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.
 

MMcLaren

Joined Feb 14, 2010
861
How about five words in assembly language?

Rich (BB code):
;
;  Binary-to-Decimal, 00..99
;
	radix	dec
btod99
	setf	Tens		; tens = -1
div10
	movwf	Ones		;
	incf	Tens,F		;
	addlw	-10		;
	bc	div10 		;
Or, if you need an isochronous solution (18 words/18 cycles);

Rich (BB code):
	radix	dec
b2d99
        clrf    tens            ;
        addlw   -80             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   80              ;
        addlw   -40             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   40              ;
        addlw   -20             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   20              ;
        addlw   -10             ;
        rlf     tens,F          ;
        btfss   tens,0          ;
        addlw   10              ;
        movwf   ones            ;
Here's another isochronous routine for 8-bits (0..255) from a brain-storming session on Forum.Microchip (16 words/16 cycles);

Rich (BB code):
;
;   input: WREG = 0x00..0xFF, 0..255
;
        movwf   ones            ; save "ones"
        mullw   .205            ; divide by 10
        movf    PRODH, W        ;
        mullw   .32             ;
        movf    PRODH, W        ;
        movwf   tens            ; save "tens", 0..25
        mullw   .10             ; multiply by 10
        movf    PRODL,W         ;
        subwf   ones,F          ; ones -= (tens*10)
        movf    tens,W          ; 0..25
        mullw   .26             ; divide by 10
        movf    PRODH,W         ; 0..2
        movwf	huns		; save "huns", 0..2
        mullw   .10             ; multiply by 10
        movf    PRODL,W         ;
        subwf   tens,F          ; tens -= (huns*10)
 
Last edited:

MrChips

Joined Oct 2, 2009
30,810
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?)
 

be80be

Joined Jul 5, 2008
2,072
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
 
Top