Convert Dec to BCD

Hi,

I am trying to convert a decimal value to the corresponding BCD code. However, this seems not to be working at all, because only gives the ‘tens’ part and the ‘unit’ is lost. Such as, 27 only return 2.
I want the result into a 8-bit array (the result will not be greater than 99)…

byte decToBcd(byte val)
{
  return ( (val/10*8) + (val%10) );
}

So you want 27 for example to come back as 0010 0111? (2 & 7)?

and 99 would be 1001 1001 (9 & 9)?

CrossRoads: So you want 27 for example to come back as 0010 0111? (2 & 7)?

and 99 would be 1001 1001 (9 & 9)?

Correct.

This is kinda crude, but could be a way to do it given the assumption above:

x = 0
stop = 0
while (x<10 and stop = 0){
value = value - x*10 // reduce by 10, keep count, stop when value is <10
if (value < 10){
upperbyte = x
stop = 1}
else {x=x+1}
}
lowerbyte = (value, HEX)

Thinking a little more, that doesn’t quite do it.

maybe need this to put the two together

lowerbyte = value & 0x0F // AND forces upper bits low, leaves hex value in lower nibble
upperbyte = x<<4 // moves the found nibble into the upper bits
newbyte = upperbyte | lowerbyte // OR them together

CrossRoads:
This is kinda crude, but could be a way to do it given the assumption above…

I added that code, but for some reason is not showing anything on the Serial Monitor?

      int x = 0;
      int sstop = 0;
      byte upperbyte;
      byte lowerbyte;
      byte newbyte;
      while (x<10 and sstop == 0)
      {
        DecResult = DecResult - x*10;  // reduce by 10, keep count, stop when value is <10
        if (DecResult < 10)
        { 
          upperbyte = x;
          sstop = 1;
        }
        else 
        {
          x=x+1;
        }
      }
      lowerbyte = DecResult & 0x0F;  // AND forces upper bits low, leaves hex value in lower nibble
      upperbyte = x<<4;  // moves the found nibble into the upper bits
      newbyte = upperbyte | lowerbyte; // OR them together
      Serial.print("Result: ");
      Serial.println(newbyte, BYTE);

It could be creating non-printing characters. Try using HEX instead of BYTE.

CrossRoads:
It could be creating non-printing characters.
Try using HEX instead of BYTE.

Thanks !

I am trying now to display the upperbyte but it says that is zero

      Serial.print("Lowerbyte: ");
      Serial.println(lowerbyte, HEX);
      Serial.print("Upperbyte: ");
      Serial.println(upperbyte, HEX);

I gotta get to bed.

Try putting some ()s in the while test:

while ((x<10) && (sstop == 0)){

Concept seems straight forward tho, yes? Keep playing with the code, you’ll get there.

G’night.

byte decToBcd(byte val)
{
  return ( (val/10*8) + (val%10) );
}

I don't see much wrong with that other than that the "8" should be a "16", and maybe some more parens:

byte decToBcd(byte val)
{
  return ( (val/10)*16) + (val%10) );
}

CrossRoads:
I gotta get to bed.
Try putting some ()s in the while test:
while ((x<10) && (sstop == 0)){
Concept seems straight forward tho, yes? Keep playing with the code, you’ll get there.
G’night.

You give me the idea. I made this way and works perfect. I will improve it tomorrow.

      int upint = 0;
      int lowint = 0;
      int upbits[4] = {0,0,0,0};
      int lowbits[4] = {0,0,0,0};
      
      upint = DecResult/10;
      lowint = DecResult%10;
      
      //Converting Decimal to Binary
      for (int i=3; i >= 0; i--)
      {
        upbits[i] = upint % 2;
        upint = upint/2;
        
        lowbits[i] = lowint % 2;
        lowint = lowint/2;
      }
      
      byte Result[8] = {0,0,0,0,0,0,0,0};
     
      // Reorganizing the bits
      Result[0] = lowbits[3];
      Result[1] = lowbits[2];
      Result[2] = lowbits[1];
      Result[3] = lowbits[0];
      Result[4] = upbits[3];
      Result[5] = upbits[2];
      Result[6] = upbits[1];
      Result[7] = upbits[0];

I want the result into a 8-bit array (the result will be greater than 99)…

byte decToBcd(byte val)
{
  return ( (val/10)*16) + (val%10) );
}

// macro version
#define DEC2BCD(dec) (((dec / 10) << 4) + (dec % 10))

works for values 0…99, how for bigger values 100-255?

how for bigger values 100-255?

I don't understand the question - you can't fit three BCD digits in a byte.

@AWOL
The input of the function can …

Not sure I understand the question. Do you mean your decimal interpretation of a value in a register? ie does “15” =0x0F? isn’t the example “27” stored internally as 0x1B? if so then what you want is Binary to BCD. Here is my take on using the ADD3 algorithm for converting binary to BCD. I only needed two BCD digits but it can be easily expanded.

//-------------- binary to BCD using add3 algorithm -----------
byte binaryToBcd(byte binSource){
  byte bcdResult=0;

  byte tempA=0;
  byte tempB=0;
  byte tempC=0;

  for (int y=0;y<8;y++){
    tempC=binSource & B10000000;
    binSource=binSource<<1;
    bcdResult=bcdResult<<1;
    if(tempC>0){
      bcdResult=bcdResult | B00000001;
    }

    if (y<7){                             //don't check or do add 3 on last shift
      tempA=bcdResult & B00001111;        //check lo nibble
      if (tempA >= 5) {  
        bcdResult=bcdResult+3;
      }

      tempB=bcdResult&B11110000;
      tempB=tempB>>4;                     // check hi nibble
      if(tempB>=5) { 
        tempB=tempB+3;
      }

      tempB=tempB<<4;
      tempA=bcdResult & B00001111;
      bcdResult= tempB | tempA ;          // reassemble nibbles
    }
  }
  return   bcdResult;

Would this help?

/* Encode the input number into BCD into the output buffer, of
 * the specified length.  The BCD encoded number is right-justified
 * in the field.  Return the number of digits converted, or -1 if the
 * buffer was not big enough for the whole conversion.
 */
int bcd_encode(unsigned long number, unsigned char *buffer, int length)
{
  unsigned char *p;
  unsigned char n, m, bval, digit;

   n = 0;     /* nibble count */
   m = 0;     /* converted digit count */
   bval = 0;  /* the bcd encoded value */


   /* Start from the righthand end of the buffer and work
    * backwards
    */
   p = buffer + length - 1;
   while (p >= buffer) {

       if (number != 0) {
          digit = number % 10;
          number = number / 10;
          m++;
       } else
          digit = 0;

       /* If we have an odd-numbered digit position
        * then save the byte and move to the next buffer
        * position.  Otherwise go convert another digit
        */
       if (n & 1) {
          bval |= digit << 4;
          *p-- = bval;
          bval = 0;
       } else
          bval = digit;

       n++;
   }

   /* If number is not zero, then we have run out of room
    * and the conversion didn't fit.  Return -1;
    */
   if (number)
      return(-1);

   /* return the number of converted digits
    */
   return(m);
}

Not guaranteed to be super fast – it does do long division. But it should work.

If you just want to print BCD to the serial terminal, just use the Serial.print(x, HEX). It will work this is because BCD base 16 is the same as HEX.

Here are two quick and crude functions. The only work for two digits, but you can modify as needed. Arduino byte only supports two digit anyway.

byte dec_to_bcd(byte dec)
{
	byte result = 0;
	
	result |= (dec / 10) << 4;
	result |= (dec % 10) << 0;
	
	return result;
}

byte bcd_to_dec(byte bcd)
{
	byte result = 0;
	
	result += ((bcd & 0b11110000) >> 4) * 10;
	result += (bcd & 0b00001111);

	return result;	
}

Enjoy.

Here a discussion about a fast dec2bcd and some more - http://forum.arduino.cc/index.php?topic=185235.0 -

fastest functions so far

uint8_t bcd2dec2(uint8_t n)  // takes 1384 usec for 1000 calls
{
  return n - 6 * (n/16); 
}

uint8_t dec2bcd2(uint8_t n)  // takes 2244 usec for 1000 calls
{
  uint16_t a = n;
  byte b = (a*103) >> 10;  // this equals:  b = a/10; 
  return  n + b*6;
}

update: - removed faulty code - figures from UNO & IDE1.5.8