Who can spot what's wrong with this code?

Ok, I give up. I can’t figure out why the following 2 snippets of code behave differently.

This doesn’t work, and generates a byte of mangled characters when reading from a serial port (pin 7).
Note, in both cases, I’ve removed the timing delays for readability.

uint8_t val;

// This does NOT work...generates mangled characters
for (int offset = 0; offset < 8; offset++) {
  val |= (PIND & 1<<PD7) << offset; // this does NOT work
}

while, the following snippet DOES work.

uint8_t val;

// This DOES work
for (int offset = 0; offset < 8; offset++) {
  val |= digitalRead(7) << offset;
}

I thought that both constructs would be functionally equivalent…but they aren’t. Does anyone know why they behave differently?

digitalRead returns a value of 0 or 1
PIND & 1<<PD7 returns a value of 0 or 128

Try this:

for (int offset = 0, val = 0; offset < 8; offset++) {
if( PIND & 1<<PD7)
val |= 1 << offset;
}

As mem has said, digitalRead(7) is equivalent to:

PIND & (1 << PD7) ? 1 : 0;

Otherwise, PIND & (1 << PD7) equals 0 if the pin is low and equals (1 << PD7) = 128 if the pin is high.

One additional warning I want to point out:

The bitshift operators << and >> have very low orders of precedence. I think they’re still higher than bitwise and (&) and bitwise or (|), so your code should still work correctly, but they are lower than things like + and -, and this can lead to trouble. For example:

1 + 1 << PD7 = 2 << PD7

For that reason, I recommend you put parentheses around bitshift expressions if there’s any doubt at all about order of precedence.

  • Ben

Thanks very much for the explanations guys. Much appreciated.