Electrical – Atmega328p: why button input is read as 0 when pressed

atmegaatmega328pavrgpiomicrocontroller

I'd like to turn on the board's LED (PB5) when I press its button (PB7).

DDRB = 0xFF; // set all B-ports as output
DDRB &= ~(1<<7); // change PB7 to input
while (1)
{
    if (PINB & (1<<7))
        PORTB |= (1<<5); // when button is pressed, turn on the LED
    else
        PORTB &= ~(1<<5); // when button is not pressed, turn off the LED
}

However, PINB & (1<<7) returns 1 when I except 0, and 0 when I press the button. I could add a not operator and it'd be fine, but I'd like to know what I missunderstand. Why is the 8th bit of PINB read as 0 when I press the button?

Best Answer

What PINB & (1<<7) will return depend on how the button is wired. It will return true (not 0) value if the voltage on the pin is in the range of the high logic level and false (0) if it is in the range of the low logic level.

In the first case, the GPIO pin is pulled up to VCC (logic high) by default, so if the button is not pressed PINB & (1<<7) will return true. If you press the button, the voltage at the pin will be GND (logic low), so your statement will return false (0).

In the second case the configuration is reversed. The pin is pulled down to GND by default and when the button is pressed the voltage will be VCC. So the input will be true on button presses.

schematic

simulate this circuit – Schematic created using CircuitLab

On your board, you probably have the first case.