Page 1 of 1

BCD - dec2hex

Posted: Sat Oct 28, 2006 1:36 am
by inflater
Hi ;)
this is a lame question:
How I can convert decimal number to hexadecimal and vice-versa? :D

thanx, i need this for BCD decoding (time from CMOS).
inflater

Posted: Sat Oct 28, 2006 1:45 am
by omin0us
well, if its an actual data value...its the same thing. hex and decimal are just different ways to represent data.
if you mean a string of hex to a decimal string, then it shouldn't be to hard to write a function to convert ascii hex to data.

Re: BCD - dec2hex

Posted: Sat Oct 28, 2006 2:28 am
by Brendan
Hi,
inflater wrote:How I can convert decimal number to hexadecimal and vice-versa? :D
I'll assume you want to convert BCD to an integer and back again. For e.g. "00010010b" (BCD for 12) becomes "00001100b" (binary for 12).

If you can use the FPU and the BCD is 20 digits (zero extended), you can do something like this:

Code: Select all

    fbld tword [address_of_BCD]
    fistp qword [address_of_binary]

Code: Select all

    fild qword [address_of_binary]
    fbstp tword [address_of_BCD]
If you can't do this, then you could do generic routines like this:

Code: Select all

int convert_BCD_to_int(void *address) {
    unsigned char temp;
    int multiplier = 1;
    int value;

    for( i = 0; i < length; i++) {
        temp = *(unsigned char*)address;
        address++;
        value = value + multiplier * (temp & 0x0F);
        multiplier = multiplier * 10;
        value = value + multiplier * (temp >> 4);
        multiplier = multiplier * 10;
    }
    return value;
}

void convert_int_to_BCD(int value, void *address) {
    unsigned char temp;
    int i;

    while(value != 0) {
        temp = value % 10
        value = value / 10;
        temp = temp | ((value % 10) << 4);
        value = value / 10;
        ((unsigned char*)address)[i++] = temp;
    }
    while(i < length) {
        ((unsigned char*)address)[i++] = 0;
    }
}
This is incredibly slow though. For the CMOS you know each value fits in a byte and is only 2 digits. In this case you could do something like this:

Code: Select all

unsigned char convert_BCD_to_byte(unsigned char BCD) {
    return ((BCD >> 4) * 10) + (BCD & 0x0F);
}

unsigned char convert_byte_to_BCD(unsigned char value) {
    return (value % 10) | ( (value / 10) << 4);
}
Of course if you want the fastest possible method, you might consider using tables with 256 entries:

Code: Select all

unsigned char convert_BCD_to_byte(unsigned char BCD) {
    return BCD_to_byte_converstion_table[BCD];
}

unsigned char convert_byte_to_BCD(unsigned char value) {
    return byte_to_BCD_converstion_table[value];
}
This is fast, but predefining those 256 entry tables is a pain. Another alternative would be:

Code: Select all

convert_BCD_to_byte:
    mov ah,al
    shr ah,4
    and al,0x0F
    aad
    or al,ah
    ret

convert_byte_to_BCD:
    aam
    shl ah,4
    or al,ah
    ret
This is probably the fastest way that doesn't involve tables (as long as input values are valid and are in range).


Cheers,

Brendan

Posted: Sat Oct 28, 2006 2:57 am
by AJ
Hi,

I know the question has been answered, but another site I use, http://www.avrbeginners.net/, has a section called 'converting numbers'. Although the site is for AVR-based programs, I have always found it quite useful for number conversion algorithms.

HTH
Adam