Can Serial.println(...) cause a Heisenbug?

Is there a common reason that executing a Serial.println(…) statement would change the value of the variable printed?

I have:-

void sampleADC(unsigned char samples) {
  for (unsigned char i = 0; i < samples; i++) {
    unsigned char z = 42;
    unsigned char reading = analogRead(ADC_PORT);
    Serial.println(z);         <-------------------------------- this one.
    z = U[(reading ^ z)];
    sampleBuffer[i] = z;
  }
}

As shown, z changes as it should and the contents of sampleBuffer change. However, if I comment out the Serial.println(z) statement (and absolutely nothing else), z no longer changes and stays constant. And therefore the contents of sampleBuffer remain constant. Honestly! This must be a quintessential example of a Heisenbug, but is there a common explanation for this that I’m not getting?

Is there a common reason that executing a Serial.println(...) statement would change the value of the variable printed?

No.

That is not a complete sketch. Please post a complete sketch that shows this issue. Without that, only guessing like the size of the U[] array or the size of the sampleBuffer[] array is smaller than samples...

Okay, but simply executing a print statement wouldn't cause a change in variable values would it? So it's nothing like weird but simple compiler optimisation? Honestly, all it takes are those two slashy comment lines and the values either change or remain the same...

How large is your U array?

OP, post an MCVE. Otherwise, there is no proof that what you say is happening is actually happening.

Could be timing issue, memory exhausted, pointer aliasing error, various things not specifically related to printing, but which cannot be diagnosed from a snippet, only from the whole sketch.

cossoft: Okay, but simply executing a print statement wouldn't cause a change in variable values would it? So it's nothing like weird but simple compiler optimisation? Honestly, all it takes are those two slashy comment lines and the values either change or remain the same...

That's one of the classic signs of a array overrun. That behavior is undefined. It often does weird things just by adding or removing one statement.

Well it's getting crazier :o I started a new sketch with just this, after stripping out everything:-

void setup() {
  Serial.begin(57600);
}


void loop() {
  unsigned char z = 42;
  z = analogRead(0) ^ z;
  Serial.println(z);
  delay(1000);
}

It produces a continuous sequence of identical 8 bit numbers. Although, the sequence changes every time the Arduino is reset. That means the ADC is being read just once per boot, and then stays constant unless reset again. This is illogical, but always reproducible on my gear.

I only have one development machine, so if someone could please have a go at reproducing it. You don't need anything connected; noise should show up as a wobble in 1 or 2 bits. It doesn't on mine unless I remove the XOR operator, when it starts working as expected.

Wouldn't virtually anything to the power of 42 end up being a monstrous number that can't be meaningfully captured in an 8-bit char?

NM, jut remembered ^ isn't exponential here... facepalm

I use my own functions for the ADC so I can't really comment about how the Arduino function handles the peripheral. I do recall from somewhere though that you should read the analog twice and throw away the first result. Just on spec, I threw a preliminary read in,

void setup() {
  Serial.begin(57600);
}

void loop() {
  unsigned char z = 42;
  byte a = analogRead(0);
  z = analogRead(0) ^ z;
  Serial.println(z);
  delay(1000);
}

I think now you get results that you might expect.

DKWatson: I do recall from somewhere though that you should read the analog twice and throw away the first result.

That's only necessary if you switch between different analog channels (e.g. analogRead(A0) followed by analogread(A1)). The first result after switching is affected by the previous voltage stored in the s/h capacitor.

Well, the output looks good.

Of course! Once you cut down all the trees, you can finally see the forest!

unsigned char z

Change it to int (which it always should have been) and life is good.

gfvalvo: OP, post an MCVE. Otherwise, there is no proof that what you say is happening is actually happening.

He said it's a Heisenbug. I'm not sure how much a MCVE will help. Besides which, it being a Heisenbug, it might be hard to come up with a MCVE in the first place.

Probably better for him simply to post his entire sketch. That means the whole thing, not just a snippet or two.

odometer: He said it's a Heisenbug. I'm not sure how much a MCVE will help. ...entire sketch...

So I did. This is now the entire sketch I'm running. It does not work.

Everybody would expect the numbers to change for every pass of the loop. There is a random signal on pin 0. Even it there wasn't, the reading would change by a couple of bits due to simple thermal noise. All it is doing is printing (varying signal) xor (constant). It must change every pass.

void setup() {
  Serial.begin(57600);
}


void loop() {
  unsigned char z = 42;
  z = analogRead(0) ^ z;
  Serial.println(z);
  delay(1000);
}

The output should vary with every pass of the loop. In my case it remains constant, only changing with every reset. This is the output:-

69
69
69
69
69
69
69
69
119
119
119
119
119
119
119
119
119

The change from 69 to 119 only happened at reset. This is impossible. Is the funny hat thing (^) not the XOR operator?

If you change z = analogRead(0) ^ z; to z = analogRead(0); by removing XOR zed, it works as expected. It must be something so simple that I can't see the wood for the...

DKWatson:
I think now you get results that you might expect.

Yes, that works for me. Why does my sketch not work with one read??? There is nothing in the literature at all implying that an Aduino Uno can only read analogue values in pairs. Nothing at all. No where. Nada…

And your explanation isn’t quite right anyway. My sketch with one read can work if the ^ x function is removed. That’s the real issue here. It’ driving me mad. I could be shopping instead…

an unsigned char can hold from 0 to 255 analogRead() returns an int with a value of 0 to 1023 Could that be a factor ?

If you declare z as an int all seems OK

  unsigned char z = 42;
  z = analogRead(0) ^ z;

should be the same as

  unsigned char z = analogRead(0) ^ 42;

only more convoluted.

If you expext something alternating

  static unsigned char z = 42;
  z = analogRead(0) ^ z;

could do what you expect.

Anyway it is very strange to xor the low part of a measurement with itself and 42.

@Whandall , nope although it gets more interesting :confused: Your program generates:-

42
91
42
91
42
91
42
91
42
91
42
91

All it does is alternate! The numbers should be randomish.

The issue is that this is mathematically impossible. A continuously varying quantity XORed with a constant varies. That's unequivocal. Why doesn't the code's behaviour reflect mathematics..? What is causing z to be sticky?


PS. XORing with itself was part of a Pearson Hash I was using to roll up entropy samples for a random number generator.