Go Down

Topic: How to convert 4 bytes into a long? (Read 6076 times) previous topic - next topic

prairiemystic

I have a 24-bit A/D and put four 8-bit reads into a byte array:

long adc_value;
byte d[4];

digitalWrite(ADC_CS,LOW);
d[0]=shiftIn(SPI_MISO,SPI_CLK,MSBFIRST);
d[1]=shiftIn(SPI_MISO,SPI_CLK,MSBFIRST);
d[2]=shiftIn(SPI_MISO,SPI_CLK,MSBFIRST);
d[3]=shiftIn(SPI_MISO,SPI_CLK,MSBFIRST);
digitalWrite(ADC_CS,HIGH);

adc_value=long(d[]);  // <-- sketch does not compile
adc_value=long(d[0]);  // <-- sketch compiles
Serial.println(adc_value); // I get FF

So the conversion function "long" does not seem to accept arrays :( and I wonder how to use it?

PaulS

Quote
So the conversion function "long" does not seem to accept arrays and I wonder how to use it?

You don't, because that is not what it is for.

The long that you want to construct is done by shifting one of the bytes in the array 24 places to the next. Then, the next byte is shifted 16 bits to the left, and added. Then, the next byte is shifted 8 bits to the left, and added. Then, the final byte is added.

Code: [Select]
long val = 0;
val += d[0] << 24;
val += d[1] << 16;
val += d[2] << 8;
val += d[3];


Depending on how the bytes were sent, the array may need to be used in the other order (3, 2, 1, 0).

retrolefty


gardner

Something like this should so the job.

Code: [Select]
long adc_value;
byte d[4];

/* Put the low byte in d[0].
*/
d[0]= shiftIn()  // THE LOW BYTE
  :
d[3] = shiftIn()  // THE HIGH BYTE

adc_value = *((long *)d);

prairiemystic

I do get interesting results and am still looking for a solution. It looks like the shift operator is only 16 bit. The cast to a long swaps nibbles on some of the bytes, which is strange. Thanks everyone for your help so far.

  byte d[4];
  long adc_value;

  d[0]=0x87; 
  d[1]=0x65; 
  d[2]=0x43; 
  d[3]=0x21; 

  adc_value=0;
  adc_value += d[0] << 24;
  adc_value += d[1] << 16;
  adc_value += d[2] << 8;
  adc_value += d[3];
  Serial.println(adc_value,HEX); //--> prints 4321 (expected 87654321)

  adc_value = *((long *)d);
  Serial.println(adc_value,HEX); // --> prints 21346587 (expected 21436587)

  d[0]=0x12; 
  d[1]=0x34; 
  d[2]=0x56; 
  d[3]=0x78; 

  adc_value=0;
  adc_value += d[0] << 24;
  adc_value += d[1] << 16;
  adc_value += d[2] << 8;
  adc_value += d[3];
  Serial.println(adc_value,HEX); //--> prints 5678 (expected 12345678)

  adc_value = *((long *)d);
  Serial.println(adc_value,HEX); // --> prints 78563412 (expected 87654321)

PaulS

What kind of results do you get if adc_value is unsigned long? Does it make sense for it not to be unsigned long?

prairiemystic

Yes it should be: unsigned long adc_value; but I get the same results.

AWOL

What if you cast the bytes to long before shifting?
"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.

jraskell


adc_value += d[0] << 24;
 adc_value += d[1] << 16;
 adc_value += d[2] << 8;
 adc_value += d[3];


these operations need to be cast to a long.  Your left operand is of type byte, and your right operand is a const that the compiler defaults to type int, so the operation is performed as a 16 bit operation.  change it to:

Code: [Select]
 adc_value += (long)d[0] << 24;
 adc_value += (long)d[1] << 16;
 adc_value += (long)d[2] << 8;
 adc_value += (long)d[3];


And you'll get the expected outcome.


 adc_value = *((long *)d);
 Serial.println(adc_value,HEX); // --> prints 21346587 (expected 21436587)

 adc_value = *((long *)d);
 Serial.println(adc_value,HEX); // --> prints 78563412 (expected 87654321)  


The printouts for these are as I would expect them.

gardner


I do get interesting results...

Code: [Select]
  d[0]=0x87; 
  d[1]=0x65; 
  d[2]=0x43; 
  d[3]=0x21; 

      :

  adc_value = *((long *)d);
  Serial.println(adc_value,HEX); // --> prints 21346587 (expected 21436587)



21346587

I do not believe this is possible.  If this is really what you got, there's something wonky about your methodology.

What I get is:  0x21436587 which is the right answer.

prairiemystic

byte d[4];
long adc_value;

<.... stuff deleted>

adc_value  =  (long)d[0] << 24;
adc_value += (long)d[1] << 16;
adc_value += (long)d[2] << 8;
adc_value += (long)d[3];

This code works fine now. (Without proper casting to a long, I get swapped nibbles i.e. 21346587)
Thanks to everyone, esp. jraskell for the help.

paulfer

OH MY WORD! I spent an entire evening searching thru many forum posts. If only I saw this one 1st!

septillion

Just shifting them as you go is way easier...

Code: [Select]

long adc_value = 0;

digitalWrite(ADC_CS,LOW);
for(byte i = 0; i < 4; i++){
  adc_value =<< 8;
  adc_value |= shiftIn(SPI_MISO,SPI_CLK,MSBFIRST);
}
digitalWrite(ADC_CS,HIGH);


And if you are already calling it SPI, why not USE the SPI? ;)
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

PaulMurrayCbr

#13
Jul 30, 2016, 03:35 am Last Edit: Jul 30, 2016, 03:41 am by PaulMurrayCbr
If you take care to get the order of the bytes correct (not sure about the AVR endianness), then you can cast the array as a pointer to long and dereference it:

Code: [Select]

adc_value=long(d[]);  // <-- sketch does not compile

adc_value = * (long *) d; // try this instead


An equivalent way to do this is using a union

Code: [Select]

union foo {
  byte as_array[4];
  long as_long;
}
d;

  d.as_array[0]=0x87;
  d.as_array[1]=0x65;
  d.as_array[2]=0x43;
  d.as_array[3]=0x21; 

Serial.println(d.as_long,HEX);


If you get weird values, just put in one byte to work out if it goes into element 0 or element 3 of the array.

http://paulmurraycbr.github.io/ArduinoTheOOWay.html

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy