How to convert BCD to decimal?

How to convert a binary coded decimal number to a decimal number in terms of representation? I do not want to transform its meaning, but rather its representation, that is what I mean.

I want to convert 0x11to decimal 11(not 17) and 0x20to 20(not 32).

unsigned char day = 0x11;
unsigned char month = 0x12;

int dayDecimal, monthDecimal;

I want dayDecimal to be 11monthDecimal = 12. I will work with a range from 0x00 to 0x60, so this should be possible. There will be "A", "B", "C", "D", "E", "F.

Update:

I really read the time from the RTCC chip as part of the embedded project I'm working on. Hours, minutes, day and month are returned in this form. For example, if the minutes are 0x40, then this means 40 minutes, not 64, so I need to be able to interpret it correctly. I need to somehow convert 0x40 to 40, not 64. I hope this is possible.

Thank!

+4
source share
6 answers

You need to work with two nybbles, multiplying the more significant nybble by ten and adding the less significant:

uint8_t hex = 0x11;
assert(((hex & 0xF0) >> 4) < 10);  // More significant nybble is valid
assert((hex & 0x0F) < 10);         // Less significant nybble is valid
int dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);

If statements are disabled, but the input is dummy (for example, 0xFF), you get what you deserve: GIGO - garbage, garbage. You can easily wrap this in a (built-in) function:

static inline int bcd_decimal(uint8_t hex)
{
    assert(((hex & 0xF0) >> 4) < 10);  // More significant nybble is valid
    assert((hex & 0x0F) < 10);         // Less significant nybble is valid
    int dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
    return dec;
}       

BCD - .

+9

:

int bcd_to_decimal(unsigned char x) {
    return x - 6 * (x >> 4);
}
+2

Put the desired value in the function and you will get an integer in response.

#include <stdio.h>
#include <math.h>

typedef int                 INT32;

typedef short int           INT16;

typedef unsigned short int  UINT16;

typedef unsigned long int   UINT32;

UINT32 BCDToDecimal(UINT32 nDecimalValue){
    UINT32 nResult=0;
    INT32  nPartialRemainder, ncnt,anHexValueStored[8];
    UINT16 unLengthOfHexString = 0,unflag=0;

    for(ncnt=7 ;ncnt>=0 ; ncnt--){
        anHexValueStored[ncnt]=nDecimalValue & (0x0000000f << 4*(7-ncnt));
        anHexValueStored[ncnt]=anHexValueStored[ncnt] >> 4*(7-ncnt);
        if(anHexValueStored[ncnt]>9)
        unflag=1;
    }
    if(unflag==1){
        return 0;
    }
    else{
        for(ncnt=0 ;ncnt<8 ; ncnt++)
        nResult= nResult +anHexValueStored[ncnt]*pow(10,(7-ncnt));
        return nResult;
    }
}
int main() {
    printf("%ld\n",BCDToDecimal(0X20));
    return 0;
}
+1
source

You can not. 0x1A is not valid in decimal system. With this anomaly, many transformations will be invalid.

As a simple approach, you can use sprintf, then atoi.

-1
source
#include <stdlib.h>
#include <type_traits>
#include <boost/lexical_cast.hpp>

//template params:N number digits. S start position
//sample data  {0x12, 0x34, 0x56, 0x78, 0x9F}   if (N=4,S=3) then result = 4567
template <int N,int S=0>
class bcd_to_int
{
public:
    static int parse(char* src)
    {
        static_assert(sizeof(int)==4, "int must be 4 byte");
        static_assert(N <= 10,"int not exceed 10 digits");

        char buff[N + 1] = { 0 };

        if (S%2==0){
            parse_helper_even<N>(src + S/2, buff);
        }
        else{
            parse_helper_odd<N>(src + S/2, buff);
        }

        return boost::lexical_cast<int>(buff); ;
    }

    template<int N>
    static void parse_helper_even(char* src, char* buff)
    {   
        buff[0] = ((*src & 0xF0) >> 4) + 0x30;
        parse_helper_odd<N-1>(src, buff + 1);
    }

    template<>
    static void parse_helper_even<0>(char* src, char* buff)
    {}

    template<int N>
    static void parse_helper_odd(char* src, char* buff)
    {
        buff[0] = (*src & 0x0F) + 0x30;
        parse_helper_even<N-1>(src + 1, buff + 1);
    }

    template<>
    static void parse_helper_odd<0>(char* src, char* buff)
    {}
};


int main()
{
    char src[] = { 0x89,0x89,0x89,0x89,0x89 };

    int ret = bcd_to_int<9>::parse(src);  //999999999

    //bcd_to_int<10>::parse(src);  will throw error

    ret = bcd_to_int<3,1>::parse(src);   //989

    return 0;
}

Avoid using a loop. its faster.

-1
source

Simple CPP code written by me:

==============================

unsigned int BCD= 0x68, BCD_H, BCD_L, decimal;

std::cout<< BCD << std::endl;

BCD_H = BCD >> 4;
BCD_L = BCD & 0b00001111;
decimal = 10 * BCD_H + BCD_L;

std::cout << decimal << std::endl;
-2
source

All Articles