BCD to Decimal and vica versa

Does anyone have C# methods in their toolbox to convert BCD to Decimal and Decimal to BCD ?

Thanks,
Eric

Is this for the DS1307

I use this RTC all the time because if it is, I convert all 8 bytes at a time then write or I read then convert them back…

Is this the code you need?

Cheers Ian

Indeed, it’s for a DS1307.

Its in c but its easy to convert

void bcdBin(char* array)
	{
	char x;
	unsigned char tmp;
	for(x=0;x<8;x++)
		{
		tmp = *array  >> 4;
		tmp *= 10;
		tmp = tmp + (*array & 0xf);
		*array++ = tmp;
		}
	}

void binBcd(char* array)
	{
	char x;
	unsigned char tmp;
	for(x=0;x<8;x++)
		{
		tmp = *array  / 10;
		tmp = tmp << 4;
		tmp = tmp + (*array % 10);
		*array++ = tmp;
		}
	}

I use the same array throughout

Cheers Ian

Ok,

I’m trying to learn this. Can you show me how a BCD message from the DS1307 looks like? (Don’t have my Fez board yet)

Thanks

Ok !


                byte[] DateTime = new Byte[8];

                DateTime[0] = 0; //seconds
                DateTime[1] = 41; //minutes
                DateTime[2] = 13; //Hours
                DateTime[3] = 7; //Day
                DateTime[4] = 10; //Date
                DateTime[5] = 10; //Month
                DateTime[6] = 10; //Year
                DateTime[7] = 0; //Settings

then use the BinBcd( DateTime) and write all 8 bytes to the RTC…

Is this what you mean?

Or it looks like this as raw data " 0x00, 0x41, 0x13, 0x07, 0x10, 0x10,0x10, 0x00 "

Ian

I un-dusted my arduino and hooked up the RTC.
I found some code that dumps the data returned from the RTC to the serial console:

Byte 0 contains the seconds: 1011000 or 58 seconds.

I figured out the way to convert from BCD to INT:


    static void Main(string[] args)
    {
      Console.WriteLine(bcdToDec("1011000"));
      Console.ReadKey();
    }
    public static int bcdToDec(string val)
    {
      return int.Parse(Convert.ToInt32(val, 2).ToString("X"));
    }

I’m a bit stuck at how to convert in the opposite way: INT to BCD.

No you can’t do that!

0x10 in hex equates to 16 decimal
0x10 in BCD equates to 10 decimal

You have to shift 0x10 >> 4 to get 1 then * 10 to get 10.

Ie… 0x10 = 16 decimal but you must make it read 0x0A decimal thats why I shift it

to get a decimal… return ((BCD >> 4) * 10) + BCD & 0xf;

and a BCD… return ((DEC / 10) << 4) + DEC % 10;

A BCD is not the same as a decimal.

Cheers Ian

Thanks guys, for bringing this thread up. And I’m trying to get acquainted with I2C as well,
so this would be a good learning curve to me too.

I’m looking into using DS1307 to add to my Panda as well.

Eric:

[quote]I un-dusted my arduino and hooked up the RTC.
I found some code that dumps the data returned from the RTC to the serial console:[/quote]

I wonder how you read the data from the RTC? Is it MSB or LSB?
I look in the DS1307 datasheet and stated that

IanR:

Is this the right approach to convert BCD to Dec.


// Convert DateTime[6] - Year 

int YearVal;

byte HighBCD = 0xF0;
byte LowBCD  = 0x0F;

YearVal = (10 * ((DateTime[6] & HighBCD) >> 4)) + (DateTime[6] & LowBCD);
YearVal += 2000;


Sam,

I took the code for the arduino from here: [url]Error and changed

Serial.println(test, DEC);

to

Serial.println(test, BIN);

that provided me with the output from above.

I have this created:


    static void Main(string[] args)
    {
      Console.WriteLine(bcdToInt("1011000"));
      for (int x = 0; x <= 59; x++)
      {
        Console.WriteLine(x + " = " + intToBcd(x.ToString()) + " => " + bcdToInt(intToBcd(x.ToString())));
      }
      Console.ReadKey();
    }
    public static int bcdToInt(string val)
    {
      return int.Parse(Convert.ToInt32(val, 2).ToString("X"));
    }
    public static string intToBcd(string val)
    {
      return Convert.ToString(Convert.ToInt32(val, 16), 2);
    }

and when run returns:


58
0 = 0 => 0
1 = 1 => 1
2 = 10 => 2
3 = 11 => 3
4 = 100 => 4
5 = 101 => 5
6 = 110 => 6
7 = 111 => 7
8 = 1000 => 8
9 = 1001 => 9
10 = 10000 => 10
11 = 10001 => 11
12 = 10010 => 12
13 = 10011 => 13
14 = 10100 => 14
15 = 10101 => 15
16 = 10110 => 16
17 = 10111 => 17
18 = 11000 => 18
19 = 11001 => 19
20 = 100000 => 20
21 = 100001 => 21
22 = 100010 => 22
23 = 100011 => 23
24 = 100100 => 24
25 = 100101 => 25
26 = 100110 => 26
27 = 100111 => 27
28 = 101000 => 28
29 = 101001 => 29
30 = 110000 => 30
31 = 110001 => 31
32 = 110010 => 32
33 = 110011 => 33
34 = 110100 => 34
35 = 110101 => 35
36 = 110110 => 36
37 = 110111 => 37
38 = 111000 => 38
39 = 111001 => 39
40 = 1000000 => 40
41 = 1000001 => 41
42 = 1000010 => 42
43 = 1000011 => 43
44 = 1000100 => 44
45 = 1000101 => 45
46 = 1000110 => 46
47 = 1000111 => 47
48 = 1001000 => 48
49 = 1001001 => 49
50 = 1010000 => 50
51 = 1010001 => 51
52 = 1010010 => 52
53 = 1010011 => 53
54 = 1010100 => 54
55 = 1010101 => 55
56 = 1010110 => 56
57 = 1010111 => 57
58 = 1011000 => 58
59 = 1011001 => 59

So I don’t understand why this shouldn’t work, but then again, I’m not a C# expert neither a bit shifting master.

@ Sam Yes spot on

@ Eric I have not been very clear… bear with me…

I just assume everyone is familiar with HEX. If you familarise yourself with HEX

Hex is shorthand for binary ie 0x55 = 01010101, 5…0101 and 5… 0101
When you read the RTC its in BCD binary coded decimal

An example take this BCD… 0x12345 is equal to 12345 in decimal but it’s actually 0x3039 in the hex world (binary) if you displayed this it woul’nt be correct… We need to turn 0x12345 into 0x3039 so you can tostring() it for visual purposes…

so take the first digit and shift it enought times to get it in the Least Signifiacant nibble
16 shifts
0x00001 then multiply by (in this example) 10000
then repeat with 12 shifts
0x00012 mask the 1( & 0xf ) multiply by 1000
then 8
0x00123 mask (0xf) and multiply by 100
4
0x01234 mask (0xf)and multiply by 10
last … add in the last digit

you have now converted 0x12345 into 0x3039 ( 12345 decimal )

I don’t think there’s an easier way Intel chips have BCD to decimal add, subtract and convert.

But I dont think ARM does

ToString(“x”) only returns the hexidecimal not the BCD

the convert function takes a value and converts to a radix ie hex to deci

I hope this is more understandable

Cheers Ian

Eric:


static void Main(string[] args) 
{ 
Console.WriteLine(bcdToDec("1011000")); 
Console.ReadKey(); 
} 
public static int bcdToDec(string val) 
{ 
	return int.Parse(Convert.ToInt32(val, 2).ToString("X")); 
}

Ian is right!
Your method would not worked! I mean we would not really obtain decimal value from the method. for example, if we want to pass the BCD value of 58. We are expecting to get the value of 88 in decimal .

BCD format is only a high nibble [bit 7 - 4] of hexadecimal,
stick in front of a low nibble [bit 3 - 0] of hexadecimal. 5 [0101] 8 [1000],
and the value equivalent in decimal is 88.
I hope this would make it more clearer to you too.

BTW,

[quote] I took the code for the arduino from here: RTC1307 - Real Time Clock - Combustory and changed
[/quote]
While I was looking at this link, I also found the solution for you too!
Here are the method they used to convert back and forth from BCD.


// Convert normal decimal numbers to binary coded decimal 
byte decToBcd(byte val) 
{ 
	return ( (val/10*16) + (val%10) ); 
}
 // Convert binary coded decimal to normal decimal numbers 
byte bcdToDec(byte val) 
{ 
	return ( (val/16*10) + (val%16) ); 
} 

Ian:

I have a question regarding I2C related to DS1307.
What is the Control Register I have to use, when I initialize the DS1307 device transaction?

private static I2CDevice ds1307;
byte ControlReg = 0x07;	
// Do I have to use this value, or value contain in this byte, i.e 0x03

I2CDevice.I2CTransaction[] ds1307InitTrans = new I2CDevice.I2CTransaction[1];
ds1307InitTrans[0] = I2CDevice.CreateWriteTransaction(new byte[] {ControlReg, 0x00});

Thanks

Initialise the DS1307 by clearing bit 7 of the seconds register (very first byte)

The control register is only for the square wave output on pin 7

Bit 7 = out ( not really used)
bit 4 = Square wave out

Bit 1 & bit 0 = four speeds from 1hz to 32Khz

Regards Ian

PS the reason I shift is because of speed… on smaller processors you need as much speed as you can get

Yeah, got my DS1307 working. Will create a project page after I cleaned up my code.

Greetings,
Eric

@ Eric I would have done this some time ago but I use the Cobra and it already has an RTC
If you need any more help… I’ll be glad to…

Cheers Ian

Well,

DateTime.Now; returns the time of the Fez. How can i get the time from the pc to set the rtc?

You need to write a small program in the C# environment to send 8 bytes to the FEZ board
or you can use teraterm then convert to the right format.

Its quite easy to do I’m sure someone has a program you can hack

Cheers Ian

Eric:

Great! Congratulation.
You also should do the code sharing at www.FEZZer.com/ too.

IanR:

Thanks for all your help! :wink:

Don’t mention it Sam

Oh and by the way Congrats on becoming a master…

Seems as you acknowledged every one else becoming a master and no-one did the same for you.

Cheers Ian

Thanks Ian,
Sooner or later you’ll be one too, Keep on contributing!