Pages: [1]   Go Down
Author Topic: How to convert 4 bytes into a long?  (Read 2411 times)
0 Members and 1 Guest are viewing this topic.
Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 39
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-sad and I wonder how to use it?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 49071
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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).
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17292
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Or use a union?

Lefty

Logged

Ontario
Offline Offline
God Member
*****
Karma: 25
Posts: 875
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Something like this should so the job.

Code:
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);
Logged

Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 39
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 610
Posts: 49071
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 39
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 300
Posts: 26218
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What if you cast the bytes to long before shifting?
Logged

"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.

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
 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.
Logged


Ontario
Offline Offline
God Member
*****
Karma: 25
Posts: 875
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I do get interesting results...

Code:
  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.
Logged

Canada
Offline Offline
Newbie
*
Karma: 1
Posts: 39
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: [1]   Go Up
Jump to: