This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ASCII to BCD conversion

I am trying to use the following code to convert 2 digit ASCII numbers to BCD number, for setting RTC Clock DS1307.


unsigned char ASCII_TO_BCD(unsigned char ascii_text[2])
{
        unsigned char bcd_value;
        ascii_text[0] &= 0x0F;     // set high nibble(3) to 0 (may not be needed)
        ascii_text[0] <<= 4;       // shift lower nibble to higher

        ascii_text[1] &= 0x0F;     // set high nibble(3) to 0 (may not be needed)
        bcd_value = ascii_text[0] | ascii_text[1];  // mix both to get BCD
        return bcd_value;
}

When I pass '12' to the function, 0x33 is returned instead of 0x12. Is something wrong in this code? Thanks.

  • use "-'0'" to convert ASCII characters to numbers ('1' ->1, 'n'->n), on which the BCD transform should be made - not the ASCII values themselves!

  • try this.

    unsigned char ASCII_TO_BCD(unsigned char ascii_text[2])
            {
            unsigned char bcd_value;
    
            // left side
            if(ascii_text[0] >= '0' && ascii_text[0] <= '9')  // 0-9 range
                    {
                    bcd_value = ( ascii_text[0] - 48)  << 4 ; // 48 for '0' ASCII offset
                    }
            else if (ascii_text[0] >= 'A' && ascii_text[0] <= 'F') // A-F range
                    {
                    bcd_value = ( 10 + ascii_text[0] - 65 )  << 4 ; // 65 for 'A' ASCII offset
                    }
            else if (ascii_text[0] >= 'a' && ascii_text[0] <= 'f') // a-f range
                    {
                    bcd_value = ( 10 + ascii_text[0] - 97)  << 4 ; // 97 for 'a'  ASCII offset
                    }
    
            // right side
            if(ascii_text[1] >= '0' && ascii_text[1] <= '9')  // 0-9 range
                    {
                    bcd_value |= ( ascii_text[1] - 48); // 48 for '0' ASCII offset
                    }
            else if (ascii_text[1] >= 'A' && ascii_text[1] <= 'F') // A-F range
                    {
                    bcd_value |= ( 10 + ascii_text[1] - 65)   ; // 65 for 'A' ASCII offset
                    }
            else if (ascii_text[1] >= 'a' && ascii_text[1] <= 'f') // a-f range
                    {
                    bcd_value |= ( 10 + ascii_text[1] - 97 ) ; // 97 for 'a' ASCII offset
                    }
    
            return bcd_value;
            }
    

  • Thank you Sir! It is perfectly working. I am not using the alphabets a-f or A-F. Only numbers are used. So I tried skipping the 'if-else if', but it is not working. I will use the code as it is for now, & will study it later on.

            unsigned char bcd_value;
            bcd_value = ( ascii_text[0] - 48)  << 4 ; // 48 for '0' ASCII offset
            bcd_value |= ( 10 + ascii_text[1] - 97 ) ; // 97 for 'a' ASCII offset
            return bcd_value;
    

    I am also not getting why my code(which I posted) was not working. Anyway, THANK YOU VERY MUCH.

  • It is possible to appease a crocodile?
    Imagine the swarms of lazy, stupid, uneducated and rude idiots that are going to come down here asking for free code now that they see such a noble act of charity. Well done christian crosa, well done.

  • No Sir, I am not asking for free code. If you have read my post properly, I was asking to spot the mistake in my code. I even don't use any code in my design until I understand it. That's why I specially mentioned that I will use the code as it is for now, & will study it later on.

  • I was not specifically referring to you.

  • Now if you only use digits (0..9) - why then did you suddenly include the one line that makes use of character 'a' and was intended for the hexadecimal range 'a' .. 'f'?

    Next thing - the guy who did give you example code does something I don't like:

    bcd_value = ( ascii_text[0] - 48)  << 4 ; // 48 for '0' ASCII offset
    


    ascii_text contains characters ('0', '1', ... '9')
    48 is a magic number that requires the comment "48 for '0' ASCII offset".

    So a comment is explicitly needed just because the code is mixing between characters and the ordinal numbers of characters.

    It is way better to write:

    bcd_value = ( ascii_text[0] - '0')  << 4 ;
    


    Suddenly, no comment is needed since there is no longer any magic value 48 to explain.

    There is a big reason why the C language allows us to perform mathematical operations directly using characters.

  • Thanks Per, I had used wrong line of code. I also changed 48 to '0'. Certainly it is more readable & understandable.

  • I am also not getting why my code(which I posted) was not working. Anyway, THANK YOU VERY MUCH.

    Try some other arguments besides "12", and maybe you'll notice a pattern...

    It fails because of the difference between what you think an array-type function argument as in

    void func(int in[2])
    

    does, and what actually happens. You believe this behaves vaguely like

    void func(int in1, int in2)
    

    while it really is equivalent to

    void func(int *in)
    

    I'll also venture an educated guess that in the actuall call of your function, which you didn't show, the argument is a string literal, i.e. it looks like this:

    result = asciitobcd("12");
    

    , and that changing the call to

    { unsigned char tempstr[] = "12"; result = asciitobcd(temp);}
    

    magically cures it.

    A note to the experts in here: please don't spoil the OP's a-ha! experience. Let him figure this one out for himself.