bit-shifting to make integers sometimes goes negative (Wire library)

So, I have two Arduinos communicating via the Wire library. The master board requests two bytes, and the slave sends it. The slave board uses this code to ready the information for sending:

void pack(int n)
{
  datapacket[0]=(byte)(n>>8);
  datapacket[1]=(byte)(n);
}

And then it sends datapacket. The master board uses the following code to make the information useful:

void unpack(byte b[2]) 
{
  value = (b[0] << 8)+b[1];
}

The master board then outputs this via Serial.print().

However, sometimes this value comes out negative. This shouldn’t happen, as the slave board is getting its information from the ADC, and so, is always positive. I’m still testing to see if it’s just the negative of the proper value, or if the integer itself is going screwy.

The other caveat is that this happens twice per reading. The master board requests information from the slave’s ADC0, and then subsequently from the slave’s ADC1. The first reading is always accurate, with the correct sign and the correct value. It’s the second reading that goes occasionally negative.

If the number is just picking up a negative sign, that’s easy to fix. However, on the assumption that something is actually going wrong and the value itself is being altered, how would I go about fixing that?

  datapacket[1]=(byte)(n);

n is not truncated to fit. It will cause the value in datapacket[1] to overflow. You need to mask off the high order byte (or shift n left 8 places, then shift it back right 8 places).

how would I go about fixing that?

How about trying:

unsigned int value;

PaulS:

  datapacket[1]=(byte)(n);

n is not truncated to fit. It will cause the value in datapacket[1] to overflow. You need to mask off the high order byte (or shift n left 8 places, then shift it back right 8 places).

Then how come it happens only occasionally?

Then how come it happens only occasionally?

For what values of n does it happen?

I'm seeing it happen for all values. I get positive and negative results.

So, an update: I'm seeing the minus sign added arbitrarily. The absolute value of the result doesn't change, it only picks up a minus sign here and there. That's easy to code out, but does anyone have any ideas why that could be happening?

If you are going to ask questions like that, at least provide the data types. What type is datapacket? What type is value?

Verdris:
I’m seeing the minus sign added arbitrarily. The absolute value of the result doesn’t change

Those two statements are incongruous with the way ints handle/store negative numbers at the binary level.

For the “minus sign added arbitrarily”, in the absence of code, the only real way I see this happening is that your binary operations are occasionally settings the MSB of your int, which indicates a negative number. However, if this is the case, the actual negative value that the lower 15 bits represents is going to be completely different from the positive value those same 15 bits represents. Thus “The absolute value of the result doesn’t change” is inconsistent with such behavior.

This is because ints utilize what is called a two’s complement system for storing positive and negative numbers in binary form. So, the example code below:

  //define a char with a positive value
  char x = 23;
  //Set the MSB of that char
  bitSet(x, 7);
  //Display the new value.  It is not -23
  Serial.println(x, DEC);

will output -105. There really isn’t any accidental way of only flipping the sign of a value through binary manipulation of the variable. Any simple manipulation is going to significantly change the entire value, whether it’s a shift, a NOT, an AND, etc.

So, why does it output -105 instead of -23? Again, because values are represented using a two’s complement system, see here for http://en.wikipedia.org/wiki/Two’s_complement

In the above example, the value 23 in binary form is:
00010111

When we take this value and just set the MSB, we get:
10010111

And when we output the new decimal representation of this value, we get -105.

In order to get the binary representation of the negative value of 23, we have to take the complement of 23, add one to that complement, and then set the MSB. So,
!0010111 = 1101000 (we’re only complementing seven bits here, since the MSB doesn’t represent a value, only the sign of the value)
1101000 + 1 = 1101001
Then set MSB to get 11101001

We can easily verify that with the following snippet of code:

  char x = B11101001;
  Serial.println(x, DEC);

This code will output -23.

So the binary representation of the two values are:
00010111
11101001

so it is clear to see that, from a binary perspective, the two values are far more different than just a sign flip.

Now, having said all that, it does nothing to address your specific problem, merely provides indicators as to what the problem could be. As is the case with most of these problems though, we really can’t provide any useful answers without seeing the code. Vague descriptions of behavior are almost completely worthless. Small snippets of code are only slightly less worthless.