Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Number <-> ASCII Conversion

Status
Not open for further replies.

dknguyen

Well-Known Member
Most Helpful Member
Does anyone know of an algorithm to change a binary number into an decimel ASCII? I don't need an algorithm per se, but an idea about how to go about it.

Decimel ASCII->Binary Number isn't so bad since you can just isolate each ASCII numerical symbol and change it into it's numerical binary equivelant, scale it by the order of magnitude and then add them all up.

But I have no idea how to take a binary number like 0b1111101000 and change it into '1000', without a horrid repetitive function where you subtract the largest power of 10 from the binary number that is still less than the number until it becomes less than the power, and then you reduce the power of 10 by one, and then repeat over and over again until you get to 10^0 and the number equals zero.
 
Last edited:
Shift the bits into a 16 bit variable and do DecToAsc or itoa.

Maybe I have misunderstood what you have said as there is no difference between a binary and a decimal number except when you display them.

Mike.
 
ie. I need to change an the '8' you see right here which is represented as 0x38 into 0b100 and vice versa.
 
Last edited:
hi,
;This is the subroutine I use, I am not the author.
;I sometimes need to convert a 24 bit binary to ascii, just edit the bits
;for a 16bit binary.
;If you just want bin to bcd drop the end bcd to ascii.


Code:
;Using 16F877 
;ASCBFR is located in RAM, len= 8 for 8 digit option
;latest convert 16bit bin to 5 asci in ASCBFR0
;can be modified for 8 digits.
BIN2ASC:
    CLRF    ASCBFR0
    CLRF    ASCBFR1
    CLRF    ASCBFR2
    CLRF    ASCBFR3
    CLRF    ASCBFR4
    CLRF    ASCBFR5
    CLRF    ASCBFR6
    CLRF    ASCBFR7
	 	 
    MOVLW   0X18;24 bits,,,16 bits to do 5 digit
    MOVWF   TMPCNT1

BITLP:;shift msb into carry
    RLF     B2AVL,F ; this is binary value to convert lo,med,hi
    RLF     B2AVM,F
    RLF     B2AVH,F
	 
    MOVLW   ASCBFR7;0=msd 1st
    MOVWF   FSR;fsr=pointer to digits
    MOVLW   0X8;digits to do
    MOVWF   TMPCNT2
ADJLP:
    RLF     INDF,F;shift digit 1 bit left
    MOVLW   0X0A
    SUBWF   INDF,W;check and adjust for decimal overflow
    BTFSC STATUS,C
    MOVWF   INDF

    DECF    FSR,F;incf=msd 1st next digit
    DECFSZ  TMPCNT2,F
    GOTO    ADJLP
    DECFSZ  TMPCNT1,F;next bit
    GOTO    BITLP

    MOVLW 0X30;make ascii option
    IORWF ASCBFR0,F
    IORWF ASCBFR1,F
    IORWF ASCBFR2,F
    IORWF ASCBFR3,F
    IORWF ASCBFR4,F
    IORWF ASCBFR5,F
    IORWF ASCBFR6,F
    IORWF ASCBFR7,F

    RETURN
 
This takes a number (1000 decimal), converts it to a string "1000" then to a 16 bit variable 0x3e8 and then into binary "1111101000".

Code:
    itoa(1000,Message);
    pos=0;
    value=0;
    while(pos<strlen(Message)){
        value*=10;
        value+=Message[pos++]-0x30;
    }
    pos=0;
    for(mask=0x8000;mask!=0;mask=mask>>1){
        if(value&mask){
            Message[pos++]=0x31;
        }else{
            Message[pos++]=0x30;
        }
    }

Edit, to go from the binary string back to a 16 bit variable you would do,
Code:
    value=0;
    pos=0;
    for(mask=0x8000;mask!=0;mask=mask>>1){
        if(Message[pos++]==0x31)
            value|=mask;
    }

Is this what you are after.

Mike.
 
Last edited:
I'm having trouble understanding the code because I've...uhhh...retired for the night. THis is for a UART interface where numbers are being sent in ASCII form (so they are compatible with a human using hyperterminal), but then they need to be changed into actual numbers so operations can be performed on them and sent back to the user.

BUt from what I can make it at this point in time, the first example's first half looks similar to what I need.
 
Last edited:
The repetitive subtraction with a lookup table for each magnetude of conversion sure takes a lot of space. I started to replace that with a standard division subroutine that keeps the remainder of each iteration. I then realized that was still more cumbersome than necessary.

I realized that the denominator never changed, so my division was limited to subtraction of a single byte. I justified it to one bit right of the 4MSB (b'01010000'). There were a few quick tests before each iteration. First test for the MSB being set, which indicates the operation will succeed and the routine continues to do so. The second detects bit 6 being cleared, and if so aborts to the next cycle. If 7 is clear and 6 is set the next test determines if 5 or 4 is set, and if that fails the cycle is aborted. All of these pre-emptive tests save me from restoring a value on a failed iteration.

On each successful iteration a is rotated into another set of registers and on each failed cycle a '0'. When the numerator has a value less than b'00001010' it is output as a BCD digit, which a different subroutine handles for conversion to text. (addlw "0")

It's still slow, but not so bad as standard division.
 
Okay, so I wrote a special atoi() function for my purposes (though it's standard I guess but it was simple enough and how I need it is a bit weird).

But the itoa() which is the harder of the two, and apparently not standard...doesn't exist in C30! It exists in C18, but I've been unable to find source code for it and it's one of the thorniest functions in the code and I'm trying to do in 3 days what my lab partner been workin on for 3 weeks so I'd like not to introduce any more errors into the thing (he insist on coding for a processor we aren't using for our design project for some reason so now I have to pick up his slack...AGAIN).

EDIT: Oh wait, what am I smoking. Pommie just gave it to be didn't he in his post.
 
Last edited:
Here is what I came up with, but I can't test it yet. Please review it for any glaring errors:

Code:
void TX_i2a(long Num)
{
	long Magnitude = 1;	//the base of the digit being decomposed from the number
	long Digit;		//the digit extracted from the number

	//find the order of magnitude of the number (the base of the largest digit)
	while(Magnitude < Num)
	{
		Magnitude *= 10;
	}
	Magnitude /= 10;	//but the magnitude is now one order too large, so reduce it by one

	//start decomposing the number starting with the largest digit
	do
	{
		Digit = Num / Magnitude;	//extract the largest digit remaining in the number
		Num %= Magnitude;		//remove the largest digit from the number
		TX(Digit + 48);			//convert digit to ASCII and transmit over UART
		Magnitude /= 10;		//move onto next largest digit
	}while(Num != 0);			//decompose the entire number into ASCII digits
}}
 
Last edited:
That should work, you might want to change Num%=Magnitude to Num-=Digit*Magnitude, as multiplication is in hardware. That is, unless your target has hardware divide.

Mike.
 
Pommie said:
That should work, you might want to change Num%=Magnitude to Num-=Digit*Magnitude, as multiplication is in hardware. That is, unless your target has hardware divide.

Mike.

Hmm. It's a dsPIC30F4011. I'd hope it would have a divide? THe datasheet doesn't mention a hardware divider, just a fractional multiplier.
 
Last edited:
dknguyen said:
It doesn't appear to have a hardware divider. So I will do that.
There is a div instruction but it takes 18 cycles compared to 1 for multiply. Not worth worrying about really.

Mike.
 
That algorithm won't work if you feed it a 0 or a 1; it'll try to divide by zero after reducing Magnitude to 0. I like the ANSI C (without architecture enhancements) example given here: **broken link removed**

It does fewer multiplies and divides as well but does sacrifice a bit of space.


Torben
 
Last edited:
I couldn't resist, I had to write one,

Code:
void Mikes_itoa(int Num,char* String){
int Temp;
char* Pos;
char* Pointer;
    Pointer=&String[0];
    if(Num<0){              //handle negative numbers
        Num=-Num;
        *Pointer++='-';
    }
    Pos=Pointer;            //start of actual number
    do{                     //generate number backwards
        Temp=Num/10;
        *Pos++=(Num-Temp*10)+0x30;
        Num=Temp;
    }while(Num>0);
    *Pos=0;                 //string terminator
    while(Pos>Pointer+1){   //swap string around
        *--Pos^=*Pointer;
        *Pointer^=*Pos;
        *Pos^=*Pointer++;
    }
}
Note the dastardly xor swap at the end.:D

Mike.
 
Hi Mike,

The code is fairly straight forward once you realise what the pointers are doing.

The swap at the end is basically doing,
Code:
    A=A xor B;
    B=B xor A;   //B is now the original A value.
    A=A xor B;   //A is now the original B value
It swaps two values without needing an intermediate variable.

Mike.
 
Status
Not open for further replies.

Latest threads

Back
Top