Go Down

Topic: Converting unix time to byte array (Read 2421 times) previous topic - next topic


I am transmitting data wirelessly via two XBee wireless modules in API mode. This works by sending a packet consisting of a series of bytes. I am attempting to pass a unix time (number of seconds past since 1/1/1970 ~ currently around 1,280,xxx,xxx) to the Arduino as a series of bytes. Then the Arduino would convert it back to a usable number. Here's what I tried:

Code: [Select]

// the 4 byte array containing the Unix time is stored in incomingData
unsigned long unixTime = (incomingData[1] << 24) + (incomingData[2] << 16) + (incomingData[3] << 8) + incomingData[4];

But it appears that Arduino can't handle a bitshift more than 8. Is there another way to do this?


If you cast each byte as a 32 bit value it will work.

Code: [Select]

((uint32_t)incomingData[1]<<24) + ((uint32_t)incomingData[2] ...

Alternatively a union will work --

Code: [Select]

union U {
 uint32_t unixTime;
 uint8_t   data[4];

(* jcl *)

www: http://www.wiblocks.com
twitter: http://twitter.com/wiblocks
blog: http://luciani.org

(* jcl *)


Jul 29, 2010, 03:34 am Last Edit: Jul 29, 2010, 03:42 am by davekw7x Reason: 1
If you cast each byte as a 32 bit value it will work.
It assembles the bytes in the order in which they were received.  This is probably what you want to do.  (Note to the Original Poster: If array has size 4, the byte index values are 0, 1, 2, 3 not 1, 2, 3, 4.)

Alternatively a union will work --

The bytes are stored in memory in the order in which they are received, but the integer result depends on the endianness of the machine's architecture.

This is a problem with ATmega chips (and Intel/AMD chip architectures used on PC platforms these days), in which the bytes of multi-byte integers are stored least-significant byte first.

Code: [Select]

union {
 unsigned long ul;
 byte data[sizeof(unsigned long)];
} ulc;

void setup ()
   // Pretend the data came in here
   ulc.data[0] = 0x12;
   ulc.data[1] = 0x34;
   ulc.data[2] = 0x56;
   ulc.data[3] = 0x78;


void loop()
   char buf[30];
   unsigned long x;
   Serial.print("Here are the bytes: ");
       for (int i = 0; i < 4; i++) {
       sprintf(buf, "0x%02x ", ulc.data[i]);
   Serial.println(); Serial.println();
   x = (unsigned long)ulc.data[0] << 24 |
       (unsigned long)ulc.data[1] << 16 |
       (unsigned long)ulc.data[2] << 8  |
       (unsigned long)ulc.data[3];
   Serial.print("Here is the long int from the shift operations: ");
   sprintf(buf, "0x%08lx\n", x);
   Serial.print("Here is the long int from the union           : ");
   sprintf(buf, "0x%08lx\n", ulc.ul);


Here are the bytes: 0x12 0x34 0x56 0x78

Here is the long int from the shift operations: 0x12345678
Here is the long int from the union           : 0x78563412

For compatibility with just about all network communications with platforms of any architecture I think you should always figure on sending (and receiving) big-endian order.  (Like the shift stuff, not the union.)

Regardless of whether you decide to follow ubiquitous networking standards, programmers should at least be aware that the two methods (union versus shifting) give different integer results from the same byte stream for some system architectures (including the ATmega chips).



Go Up