Go Down

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

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);

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?

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.

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.

Go Up