Question

I'm to stupid right now to solve this problem...

I get a BCD number (every digit is an own 4Bit representation)

For example, what I want:

  • Input: 202 (hex) == 514 (dec)
  • Output: BCD 0x415

  • Input: 0x202

  • Bit-representation: 0010 0000 0010 = 514

What have I tried:

unsigned int uiValue = 0x202;
unsigned int uiResult = 0;
unsigned int uiMultiplier = 1;
unsigned int uiDigit = 0;


// get the dec bcd value
while ( uiValue > 0 )
{
    uiDigit= uiValue & 0x0F;
    uiValue >>= 4;
    uiResult += uiMultiplier * uiDigit;
    uiMultiplier *= 10;
}

But I know that's very wrong this would be 202 in Bit representation and then split into 5 nibbles and then represented as decimal number again

I can solve the problem on paper but I just cant get it in a simple C-Code

Was it helpful?

Solution

You got it the wrong way round. Your code is converting from BCD to binary, just as your question's (original) title says. But the input and output values you provided are correct only if you convert from binary to BCD. In that case, try:

#include <stdio.h>

int main(void) {

   int binaryInput = 0x202; 
   int bcdResult = 0;
   int shift = 0;

   printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );

   while (binaryInput > 0) {
      bcdResult |= (binaryInput % 10) << (shift++ << 2);
      binaryInput /= 10;
   }

   printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
   return 0;
}

Proof: http://ideone.com/R0reQh

OTHER TIPS

Try the following.

unsigned long toPackedBcd (unsigned int val)
{
  unsigned long bcdresult = 0; char i;


  for (i = 0; val; i++)
  {
    ((char*)&bcdresult)[i / 2] |= i & 1 ? (val % 10) << 4 : (val % 10) & 0xf;
    val /= 10;
  }
  return bcdresult;
}

Also one may try the following variant (although maybe little inefficient)

/*
Copyright (c) 2016 enthusiasticgeek<enthusiasticgeek@gmail.com> Binary to Packed BCD
This code may be used (including commercial products) without warranties of any kind (use at your own risk)
as long as this copyright notice is retained.
Author, under no circumstances, shall not be responsible for any code crashes or bugs.
Exception to copyright code: 'reverse string function' which is taken from http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
Double Dabble Algorithm for unsigned int explanation

255(binary) - base 10 -> 597(packed BCD) - base 16
     H|    T|    U|        (Keep shifting left)
               11111111
             1 1111111
            11 111111  
           111 11111
          1010 11111    <-----added 3 in unit's place (7+3 = 10) 
        1 0101 1111  
        1 1000 1111     <-----added 3 in unit's place (5+3 = 8)
       11 0001 111
      110 0011 11       
     1001 0011 11       <-----added 3 in ten's place (6+3 = 9)
   1 0010 0111 1  
   1 0010 1010 1        <-----added 3 in unit's place (7+3 = 10)
  10 0101 0101  -> binary 597 but bcd 255
  ^    ^    ^  
  |    |    |
  2    5    5   
*/
#include <stdio.h>   
#include <string.h>

//Function Prototypes
unsigned int binaryToPackedBCD (unsigned int binary); 
char * printPackedBCD(unsigned int bcd, char * bcd_string);

// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str);

//Function Definitions
unsigned int binaryToPackedBCD (unsigned int binary) {
  const unsigned int TOTAL_BITS = 32;
  /*Place holder for bcd*/
  unsigned int bcd = 0;
  /*counters*/
  unsigned int i,j = 0;
  for (i=0; i<TOTAL_BITS; i++) {
     /*
      Identify the bit to append  to LSB of 8 byte or 32 bit word -
      First bitwise AND mask with 1. 
      Then shift to appropriate (nth shift) place. 
      Then shift the result back to the lsb position. 
     */
      unsigned int binary_bit_to_lsb = (1<<(TOTAL_BITS-1-i)&binary)>>(TOTAL_BITS-1-i);
      /*shift by 1 place and append bit to lsb*/
      bcd = ( bcd<<1 ) | binary_bit_to_lsb;       
      /*printf("=> %u\n",bcd);*/
      /*Don't add 3 for last bit shift i.e. in this case 32nd bit*/
      if( i >= TOTAL_BITS-1) { 
      break;
      }
      /*else continue*/
      /* Now, check every nibble from LSB to MSB and if greater than or equal 5 - add 3 if so */
      for (j=0; j<TOTAL_BITS; j+=4) {
        unsigned int temp = (bcd & (0xf<<j))>>j;
        if(temp >= 0x5) {
        /*printf("[%u,%u], %u, bcd = %u\n",i,j, temp, bcd);*/
        /*Now, add 3 at the appropriate nibble*/
         bcd = bcd  + (3<<j);
        // printf("Now bcd = %u\n", bcd);
        }
      }
  }
  /*printf("The number is %u\n",bcd);*/
  return bcd;
}   

char * printPackedBCD(unsigned int bcd, char * bcd_string) {
  const unsigned int TOTAL_BITS = 32;
  printf("[LSB] =>\n");
   /* Now, check every nibble from LSB to MSB and convert to char* */
  for (unsigned int j=0; j<TOTAL_BITS; j+=4) {
  //for (unsigned int j=TOTAL_BITS-1; j>=4; j-=4) {
      unsigned int temp = (bcd & (0xf<<j))>>j;
      if(temp==0){
    bcd_string[j/4] = '0';      
      } else if(temp==1){
    bcd_string[j/4] = '1';
      } else if(temp==2){
    bcd_string[j/4] = '2';
      } else if(temp==3){
    bcd_string[j/4] = '3';
      } else if(temp==4){
    bcd_string[j/4] = '4';
      } else if(temp==5){
    bcd_string[j/4] = '5';
      } else if(temp==6){
    bcd_string[j/4] = '6';
      } else if(temp==7){
    bcd_string[j/4] = '7';
      } else if(temp==8){
    bcd_string[j/4] = '8';
      } else if(temp==9){
    bcd_string[j/4] = '9';
      } else {
    bcd_string[j/4] = 'X';
      }
      printf ("[%u - nibble] => %c\n", j/4, bcd_string[j/4]);
  }      
  printf("<= [MSB]\n");
  reverse(bcd_string);
  return bcd_string;
}

// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str)
{ 
    if (str != 0 && *str != '\0') // Non-null pointer; non-empty string
    {
    char *end = str + strlen(str) - 1; 
    while (str < end)
    {
        char tmp = *str; 
        *str++ = *end; 
        *end-- = tmp;
    } 
    }
}

int main(int argc, char * argv[])
{
  unsigned int number = 255;
  unsigned int bcd = binaryToPackedBCD(number);
  char bcd_string[8];
  printPackedBCD(bcd, bcd_string);
  printf("Binary (Base 10) = %u => Packed BCD (Base 16) = %u\n OR \nPacked BCD String = %s\n", number, bcd, bcd_string);
  return 0;
}

The real problem here is confusion of bases and units

The 202 should be HEX which equates to 514 decimal... and therefore the BCD calcs are correct

Binary code decimal will convert the decimal (514) into three nibble sized fields: - 5 = 0101 - 1 = 0001 - 4 = 0100

The bigger problem was that you have the title the wrong way around, and you are converting Uint to BCD, whereas the title asked for BCD to Unint

My 2 cents, I needed similar for a RTC chip which used BCD to encode the time and date info. Came up with the following macros that worked fine for the requirement:

#define MACRO_BCD_TO_HEX(x) ((BYTE) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)))

#define MACRO_HEX_TO_BCD(x) ((BYTE) (((x / 10 ) << 4) | ((x % 10))))

A naive but simple solution:

char buffer[16];
sprintf(buffer, "%d", var);
sscanf(buffer, "%x", &var);

This is the solution that I developed and works great for embedded systems, like Microchip PIC microcontrollers:

#include <stdio.h>
void main(){
    unsigned int output = 0;
    unsigned int input;
    signed char a;
    //enter any number from 0 to 9999 here:
    input = 1265;
    for(a = 13; a >= 0; a--){
        if((output & 0xF) >= 5)
            output += 3;
        if(((output & 0xF0) >> 4) >= 5)
            output += (3 << 4);
        if(((output & 0xF00) >> 8) >= 5)
            output += (3 << 8);
        output = (output << 1) | ((input >> a) & 1);
    }
    printf("Input decimal or binary: %d\nOutput BCD: %X\nOutput decimal: %u\n", input, output, output);
}

This is my version for a n byte conversion:

//----------------------------------------------
// This function converts n bytes Binary (up to 8, but can be any size)
// value to n bytes BCD value or more.
//----------------------------------------------

void bin2bcdn(void * val, unsigned int8 cnt)
{
    unsigned int8  sz, y, buff[20];         // buff = malloc((cnt+1)*2);
    
    if(cnt > 8) sz = 64;                    // 8x8
    else        sz = cnt * 8 ;              // Size in bits of the data we shift
    
    memset(&buff , 0, sizeof(buff));        // Clears buffer
    memcpy(&buff, val, cnt);                // Copy the data to buffer

    while(sz && !(buff[cnt-1] & 0x80))      // Do not waste time with null bytes,
    {                                       // so search for first significative bit
        rotate_left(&buff, sizeof(buff));   // Rotate until we find some data
        sz--;                               // Done this one
    }
    while(sz--)                             // Anyting left?
    {
        for( y = 0; y < cnt+2; y++)         // Here we fix the nibbles
        {
            if(((buff[cnt+y] + 0x03) & 0x08) != 0) buff[cnt+y] += 0x03;
            if(((buff[cnt+y] + 0x30) & 0x80) != 0) buff[cnt+y] += 0x30;
        }
        rotate_left(&buff, sizeof(buff));   // Rotate the stuff
    }
    memcpy(val, &buff[cnt], cnt);           // Copy the buffer to the data
//  free(buff);       //in case used malloc
}   // :D Done
long bin2BCD(long binary) { // double dabble: 8 decimal digits in 32 bits BCD
  if (!binary) return 0;
  long bit = 0x4000000; //  99999999 max binary
  while (!(binary & bit)) bit >>= 1;  // skip to MSB

  long bcd = 0;
  long carry = 0;
  while (1) {
    bcd <<= 1;
    bcd += carry; // carry 6s to next BCD digits (10 + 6 = 0x10 = LSB of next BCD digit)
    if (bit & binary) bcd |= 1;
    if (!(bit >>= 1)) return bcd;
    carry = ((bcd + 0x33333333) & 0x88888888) >> 1; // carrys: 8s -> 4s
    carry += carry >> 1; // carrys 6s  
  }
}

Simple solution

#include <stdio.h>

int main(void) {

   int binaryInput = 514 ;      //0x202 
   int bcdResult = 0;
   int digit = 0;
   int i=1;

   printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );

   while (binaryInput > 0) {
 
      digit = binaryInput %10;          //pick digit
      bcdResult = bcdResult+digit*i;
      i=16*i;
      binaryInput = binaryInput/ 10;
   }
   printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
   return 0;
}

Binary: 0x202 (dec: 514)

BCD: 0x514 (dec: 1300)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top