Serial Print variable giving different results by the way it is read.

I have three variables to represent RGB colour values and I am getting an unexpected result. When I start to debug I notice that the readings were also unexpected.

Here is my problem:

  int senseR, senseG, senseB;
  int boost = 30;
  
  for (int i = 0; i < numReadings; i++) {
    senseR += (1023 - analogRead(sensorPinR)) / 1023 * 255;
    senseG += (1023 - analogRead(sensorPinG)) / 1023 * 255;
    senseB += (1023 - analogRead(sensorPinB)) / 1023 * 255;
  }

  senseR = senseR / numReadings;
  senseG = senseG / numReadings;
  senseB = senseB / numReadings;

  Serial.println(senseR); //reads 0 - expected
  Serial.println(senseG); //reads 2167 - unexpected
  Serial.println(senseB); //reads 51 - unexpected

The readings of G and B should be at 0. If it was at value B then I would be fine with that.

But here is where the code gets interesting when I just grab the high G value:

  //Serial.println(senseR);
  Serial.println(senseG); //reads 51
  //Serial.println(senseB);

If I just read G it now reads 51.
If I read any of the three variables seperately they read 51.
If I read G and B it reads 0 and 51 respectively.
If I read R and G it reads 51 and 0 respectively.
If I read B, R and G it reads 0, 51 and 2167 respectively. B and R swapped values.

FYI all three analogRead() equal an expected 1023.

My question is how can the variables change just by the way they are read?

  int senseR, senseG, senseB;
  int boost = 30;
 
  for (int i = 0; i < numReadings; i++) {
    senseR += (1023 - analogRead(sensorPinR)) / 1023 * 255;
    senseG += (1023 - analogRead(sensorPinG)) / 1023 * 255;
    senseB += (1023 - analogRead(sensorPinB)) / 1023 * 255;
  }

Is this all inside a function? If it is, then senseR, senseG, senseB are all undefined, so adding to them is undefined, and the results are undefined.

You are lucky you didn't get nasal demons. Undefined behavior - Wikipedia

If those variables are at global scope, then pffft.

http://snippets-r-us.com/

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  int a, b, c;
  for (int i = 0; i < 20; i++) {
    a += 1;
    b++;
    c++;
  }
  Serial.print(a);
  Serial.print(" ");
  Serial.print(b);
  Serial.print(" ");
  Serial.println(c);
}

This code works fine for me. Why is it undefined?

Why is it undefined?

The value of local variables declared but not initialised in a function is undefined, ie they could have any value and that value could be different in subsequent calls to the function.

Variables declared as global (and local static variables) have an initial value of zero unless another value is defined for them

Not sure what the calculations are supposed to be doing, but they are certainly not going to do what you expect. You are doing integer divide of a number between 0 and 1023, by 1023. The only result you'll ever see from that division is 0 (for any analogRead result between 0 and 1022) or 1 (for and analogRead result of 1023).

Regards,
Ray L.

Efly:

    senseR += (1023 - analogRead(sensorPinR)) / 1023 * 255;

analogRead returns an integer.
1023-analogRead() will still be an integer.
Therefore, the divinsion will be an integer division and it will round down to zero.
This means that the result of the expresssion will be 255 if analogRead() is zero, 255 otherwise.

Use map()

Thanks for all of your quick responses, but I do find that the responses thus far have been difficult to accept as truth. I will make a few changes (using map()) - though the code runs fine.

My original question was why am I getting different results from my Serial print but no one seems to have come across this issue before. I suspect that the Baud rate slows the program upon Serial print thus shifting the results. I also forgot to mention that the problem occurs when I switch off the analog device and get a 1023 result on each of the analogRead() inputs. Though the results dont account for the wrong results that I am getting. (1023 -1023)/1023*255 = 0

Ray & Pauls comment confuses me - are you saying that the scope of the formula (1023 - analogRead(sensorPinR)) / 1023 * 255 is considered integer during calculation? - I always assumed it became integer once stored in senseR. Im geting good results here so my assumption seems sound.

This type of programming is unforgiving and consideration of chip architecture processes is needed.

try

  senseR = 0;
  senseG = 0;
  senseB = 0;

  for (int i = 0; i < numReadings; i++) {
    senseR += 255 * (1023 - analogRead(sensorPinR)) / 1023;
    senseG += 255 * (1023 - analogRead(sensorPinG)) / 1023;
    senseB += 255 * (1023 - analogRead(sensorPinB)) / 1023;
  }

or simpler (with a minimal rounding error)

  senseR = 0;
  senseG = 0;
  senseB = 0;

   for (int i = 0; i < numReadings; i++) {
    senseR += (1023 - analogRead(sensorPinR)) / 4;
    senseG += (1023 - analogRead(sensorPinG)) / 4;
    senseB += (1023 - analogRead(sensorPinB)) / 4;
  }

if numReadings might become big you should define senseR[BG] as a long

Efly:
This code works fine for me. Why is it undefined?

Undefined does not mean "not zero". It might be zero, it might not. Adding extra code might make it non-zero.

My question is how can the variables change just by the way they are read?

Ah, reading it a different way, changes the contents of the undefined variables.

I do find that the responses thus far have been difficult to accept as truth.

Read this, again: Undefined behavior - Wikipedia

For example, in C the use of any automatic variable before it has been initialized yields undefined behavior, ...

Which is exactly what you are doing.

And:

In the C community, undefined behavior may be humorously referred to as "nasal demons", after a comp.std.c post that explained undefined behavior as allowing the compiler to do anything it chooses, even "to make demons fly out of your nose".

So, as I mentioned, you are lucky that demons did not fly out of your nose. Very lucky.

... no one seems to have come across this issue before ...

Are you saying we haven't seen undefined behaviour before?

I do find that the responses thus far have been difficult to accept as truth.

And that is the fundamental problem.

That is why you fail

Efly:
This type of programming is unforgiving and consideration of chip architecture processes is needed.

It's C++. Forgiving or not, you need to learn it. People programming Macs, Windows, Androids - they all need to learn how C++ works. It has fundamental rules about the way integers are treated. The compiler implements them. If it didn't people would complain.

robtillaart:
try

  senseR = 0;

senseG = 0;
  senseB = 0;

for (int i = 0; i < numReadings; i++) {
    senseR += 255 * (1023 - analogRead(sensorPinR)) / 1023;
    senseG += 255 * (1023 - analogRead(sensorPinG)) / 1023;
    senseB += 255 * (1023 - analogRead(sensorPinB)) / 1023;
  }

Which still doesn't work.... How is 255 * 1023 going to fit into an int?

Regards,
Ray L.

How is 255 * 1023 going to fit into an int?

Sideways? However, 255 * 1023 / 1023 will have no problem fitting.

PaulS:
Sideways? However, 255 * 1023 / 1023 will have no problem fitting.

Really?? Please explain, given that * and / have equal precedence, and group left-to-right....

Let's ignore, for now, how c really works, and assume it evaluates strictly left-to-right. We get:

(255 * 1023) / 255 Oops! 255 * 1023 does not fit into an int!

OK, so let's assume c evaluates right-to-left. We get:

255 * (1023 - 0 / 1023) = 255 or, perhaps
255 * (1023 - (put any value between 0 and 1022 here...)) / 1023 = 0

None of those outcomes look particularly useful, much less correct....

Regards,
Ray L.

RayLivingston:
Which still doesn't work.... How is 255 * 1023 going to fit into an int?

Regards,
Ray L.

Good catch!

What I wanted to type was - senseR += 255L * (1023 - analogRead(sensorPinR)) / 1023;

Furthermore I posted the simpler version also in #7 too which does work :wink: