4 Byte Little Endian -> How to shift Bit's on Arduino?

Hello there,

i have a dummy Question. I want to convert an 4 byte (Little Endian) to a Decimal Number.

For Example:

I have the folowing bytes.

  1. 34
  2. 86
  3. 0
  4. 0

This means the following bits:

  1. 00100010
  2. 01010110
  3. 00000000
  4. 00000000

So i know, that the bytes are stored in little endian order!
So i need to use the bytes in the following Order: 4,3,2,1

This results in the following bits:
00000000000000000101011000100010

This bits are representing the number i want to store as u.long. So my calculations on the paper are fine, but i stuck how to bit shift the bytes correctly.

I’d be happy for help. :slight_smile:

You don’t explain the source for bytes. Are they in ram? Received from comms? If you detail how these bytes exist in your program, it would make it easier to show you how create the output. Yes, the shift operators “<<” and “>>” immediately come to mind but there may be others ways too, like a union.

By "decimal number" do you really mean a C++ long type in the AVR implementation? Signed or Unsigned?

If you have an array of bytes

byte vals[4] = { 34, 86, 0, 0 };

you can make a 32 bit value:

uint32_t value = (uint32_t)vals[3] << 24 +
                         (uint32_t)vals[2] << 16 +
                         (uint32_t)vals[1] << 8 +
                         vals[0];

Hello Avr Fred,

well, my Bytes are part of an Riff/Wave File on an SD Card. I read the Bytes by SDfat Library / File Class to a Byte Buffer. The Buffer itself contains all the Header Bytes of the Riff File.

byte   byteBuffer[43];

One Value (4 Bytes) are Stored at Index 24 to 27.

This 4 Bytes i would like to save as an

unsigned long waveHeaderSampleRate = -1;

I hope that this explains the way i get / store the bytes.

........PaulS was faster than my answer! I test it...... back in a min!

Well, i have implemented the calculation. i changed the desired type to uint32_t.

uint32_t      waveHeaderSampleRate = -1;
waveHeaderSampleRate = (uint32_t)byteBuffer[27] << 24 + (uint32_t)byteBuffer[26] << 16 + (uint32_t)byteBuffer[25] << 8 + byteBuffer[24];

I’m sending the Result to the Serial Console with

Serial.println("waveHeaderSampleRate: " + (String)waveHeaderSampleRate);

I receive the Value 0. Did i miss something?

Did i miss something?

Some proof that byteBuffer[27], byteBuffer[26], byteBuffer[25], and byteBuffer[24] are not all 0.

Perhaps you need some parentheses…

waveHeaderSampleRate = 
  ((uint32_t)byteBuffer[27] << 24) +
  ((uint32_t)byteBuffer[26] << 16) +
  ((uint32_t)byteBuffer[25] << 8) +
  byteBuffer[24];
uint32_t      waveHeaderSampleRate = -1;

Minus one in an unsigned variable? Hmmm…

Minus one in an unsigned variable? Hmmm…

:smiley: :smiley: :smiley:

I have changed the Variable from int to uint32_t…but forgot to change the initial value!

Well, i double checked the code, i cant find the error.

uint32_t testValue = (uint32_t)byteBuffer[27] << 24 + (uint32_t)byteBuffer[26] << 16 + (uint32_t)byteBuffer[25] << 8 + byteBuffer[24];

To check the bytes i have send the calculation to Serial Out. The Bytes are seam to be correct.

uint32_t testValue = (uint32_t)0 << 24 + (uint32_t)0 << 16 + (uint32_t)86 << 8 + 34;
testValue: 0

Hmm, got it!

Adding the Bytes ‘inline’ does not work on my Arduino MKR Zero.

uint32_t testValue = (uint32_t)byteBuffer[27] << 24 + (uint32_t)byteBuffer[26] << 16 + (uint32_t)byteBuffer[25] << 8 + (uint32_t)byteBuffer[24];

This Code works now:

      uint32_t testValue = 0;
      testValue += (uint32_t)byteBuffer[27] << 24;
      testValue += (uint32_t)byteBuffer[26] << 16;
      testValue += (uint32_t)byteBuffer[25] << 8;
      testValue += (uint32_t)byteBuffer[24];

Do u know why?!

In case anybody’s interested, there’ also swapping with XOR.

// algorithm at : http://:graphics.stanford.edu/~seander/bithacks.html#SwappingValuesXOR

void setup() {
  int a[] ={1,2,3,4};
  
  // put your setup code here, to run once:
int i;
Serial.begin(9600);
Serial.print("a before: ");
for (i=0;i<4;i++){
Serial.print(a[i]);
}
Serial.println();
//
// swap outer two then inner two bytes
//
(((a[0]) ^= (a[3])), ((a[3]) ^= (a[0])), ((a[0]) ^= (a[3])));
(((a[1]) ^= (a[2])), ((a[2]) ^= (a[1])), ((a[1]) ^= (a[2])));
Serial.print("a after: ");
for (i=0;i<4;i++){
Serial.print(a[i]);
}
Serial.println();
}

arduino forum 2.PNG

Pray tell, what is the advantage there?

I don't know if there is one. Just offering it as alternative.

dougp:
I don’t know if there is one. Just offering it as alternative.

It converts from little to big endian and vice versa. An alternative to what?

Untested, but it does compile. Will try on hardware when I get a chance:

uint32_t value;

value = *((uint32_t *) &byteBuffer[24])

To the algorithm in post #8.

If they're read in from a file, it's easiest to just consecutively read each byte into the appropriate buffer location. There is no need for any bit shifting or other fancy dancing.

Anyone else see what I mean?

dougp:
To the algorithm in post #8.

I don’t see the relevance. in post #8, the buffer locations are hard coded, and can easily read in a little or big endian format. So there is no need to ever reverse them.

aarg:
Pray tell, what is the advantage there?

Your question nagged at me. Per the url included with the code is this quote "This is an old trick to exchange the values of the variables a and b without using extra space for a temporary variable." So there's that.

Also, from what I can make out in the instruction set manual XOR will execute faster than shifting.

dougp:
Your question nagged at me. Per the url included with the code is this quote "This is an old trick to exchange the values of the variables a and b without using extra space for a temporary variable." So there's that.

Also, from what I can make out in the instruction set manual XOR will execute faster than shifting.

There is no need for shifting when doing a little-big endian conversion. It's just swapping the contents of memory locations.

There is another way of changing the order of the given data bytes using union:

34 86 00 00 ---> 00 00 86 34

Serial.begin(9600);

union {
             byte xAr[4];
             unsigned long Q;
         }  value;

 value.Q = 0x34860000;

Serial.println(value.xAr[3], HEX);   // shows 34
Serial.println(value.xAr[2], HEX);   // shows 86

//xAr[] contains 00 00 86 34