Go Down

Topic: Convert byte array to uint32_t (Read 2 times) previous topic - next topic

jphs

Hello,

I'm trying to convert a byte array into uint32_t value. Can anyone give me an help?

Thanks ;)

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Tom Carpenter

#2
Aug 19, 2012, 09:23 pm Last Edit: Aug 19, 2012, 09:26 pm by Tom Carpenter Reason: 1
Sounds like a job for a union.

Code: [Select]
union ArrayToInteger {
  byte array[4];
 uint32_t integer;
};

void setup(){
 Serial.begin(115200);
 
 ArrayToInteger converter; //Create a converter

 converter.array[0] = 1 ; //save something to each byte in the array
 converter.array[1] = 1 ; //save something to each byte in the array
 converter.array[2] = 1 ; //save something to each byte in the array
 converter.array[3] = 1 ; //save something to each byte in the array

 Serial.println(converter.integer); //Read the 32bit integer value.  
}

void loop(){

}


This would convert the array {1,1,1,1} into the long integer 16843009.

Basically the union defines a type which is made up in this case of a uint32_t member called 'integer' and a member which is an array of four bytes. The clever thing about unions is, both these two variables share the same memory space, which means no conversion is necessary - if you change one, the other changes to match.

Interestingly, you can also use array constructors with this (same code as before, but simplified):
Code: [Select]
union ArrayToInteger {
  byte array[4];
  uint32_t integer;
};

void setup(){
  Serial.begin(115200);
 
  ArrayToInteger converter = {1,1,1,1}; //Create a converter
  Serial.println(converter.integer); //Read the 32bit integer value. 
}

void loop(){

}
~Tom~

jphs

Thanks for your replies guys.

@AWOL it's big-endian.

@Tom Carpenter I've tried your code, but it's not working :(. I have "letters" in my byte array.

I'll explain what I'm trying to do so you can understand better.

I'm trying to make a connection between an Android device and an Arduino (with a XBee attached) and then a connection between that Arduino and another Arduino (with another XBee attached).
The Android device sends the data in bytes and the Arduino stores that data in a byte array. Sometimes I need to retrieve the address of a XBee to send a message to it. The XBee address it's in uint32_t (I'm using the XBee library from here http://code.google.com/p/xbee-arduino/). An example of a XBee address: sh=13A200 sl=40214AC5.

Thanks once again ;)

drone

Use the 'left shift' operator:

Code: [Select]

byte[4] x = {...};
uint32_t foo;

...

foo = (uint32_t) x[0] << 24;
foo |=  (uint32_t) x[1] << 16;
foo |= (uint32_t) x[2] << 8;
foo |= (uint32_t) x[3];


There are other ways to skin the cat, you can use addition instead of the 'or' operator, etc.

Tom Carpenter

#5
Aug 19, 2012, 10:46 pm Last Edit: Aug 19, 2012, 10:51 pm by Tom Carpenter Reason: 1
drone, the union achieves the same, but with a much smaller Ram and program memory footprint - unions are ace! :D

Those numbers are just the hexadecimal equivalent. You don't need them to have the letters as really everything is stored inside the atmega chip as binary anyway.

I presume you are trying to convert it into an XBeeAddress64 class instance?

Code: [Select]
union ArrayToInteger {
 byte array[4];
 uint32_t integer;
};

void setup(){
 Serial.begin(115200);
 
 ArrayToInteger sh; //Create a converter. 4 bytes of the high address
 ArrayToInteger sl; //Create a converter. 4 bytes of the low address

 ...
 //Set the 4 bytes...
 sh.array[0] = ...; //high
 sh.array[1] = ...;
 ...
 sl.array[0] = ...;//low
 sl.array[1] = ...;
 ...

 XBeeAddress64 address(sh.integer,sl.integer); //create the address.
 Serial.println(address.getMsb(),HEX); //Print it to the serial monitor.
 Serial.println(address.getLsb(),HEX); //Print it to the serial monitor.
}

void loop(){

}
~Tom~

jphs

#6
Aug 20, 2012, 01:53 am Last Edit: Aug 20, 2012, 01:54 am by jphs Reason: 1
@Tom Carpenter

Oh my god, I was being so stupid lol. I forgot that every "pair" was a byte. I was doing every single "character" as a byte. Example: 00 13 A2 00, every pair is a byte and I was doing 0 0 1 3 A 2 0 0 as a single byte. I feel so ashamed.

Yes, you presume it right ;)

But now I'm having a problem with my code. It's switching the order of 0x13 and 0xA2. I'll paste my code (for now I'm just simulating)

Tom you are being a big help, thank you so much ;)

Code: [Select]


byte inputStream[]={0x00 ,0x13, 0xA2, 0x00};

uint32_t expectedValue=0x0013A200;


union ArrayToInteger {
 uint32_t integer;
 byte array[4];
};

void setup(){
 Serial.begin(115200);
}
 
 
void loop(){
 
 ArrayToInteger converter; //Create a converter
 
 
 for(int i=0; i < sizeof(inputStream); i++){
   converter.array[i]=inputStream[i];
 }
 
 
 Serial.println();
 Serial.print("UNION RESULT: ");
 
 Serial.println(converter.integer, HEX);
 
 Serial.print("EXPECTED VALUE: ");
 Serial.println(expectedValue, HEX);
 Serial.println();
 Serial.print("Is it the same? ");
 Serial.println(converter.integer==expectedValue);

 
 while(true){
 }
}


Edit:
Of course I can switch the order manually, but I want to know if I'm doing something wrong

Tom Carpenter

Yeah, it will do, should have mentioned that. gcc uses Little Endian, which means the byte 0 in the array is the least significant (i.e. the right most byte in the integer).

In fact it is not just the 0x13 and 0xA2 that are being switched, but the two 0x00's as well.

All you need to do is reverse the byte order to convert from big to little endian. This should do it:
Code: [Select]
  for(int i=0; i < sizeof(inputStream); i++){
   converter.array[sizeof(inputStream) - i - 1]=inputStream[i]; //reverse the byte order here.
 }
~Tom~

GoForSmoke

OP, are you trying to convert ascii text to a numeric value?
I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

jphs

Thank you Tom, it's working great and you were a great help, thank you so much ;)

Go Up