Reading a Push Button
Reading a button sounds trivial, but a mechanical switch is messier than it looks — this lesson covers pull resistors and the 'bounce' every button produces.
A push button is just a switch: press it, and it connects two points; release it, and the connection breaks. To read that state with a GPIO pin, the pin needs to have a well-defined voltage in both the pressed and unpressed positions — and a bare button wired to only one side of the circuit doesn't guarantee that.
The fix is a pull resistor. A pull-up resistor connects the pin to the supply voltage through a large resistance (commonly ten thousand ohms or more); when the button is not pressed, the pin reads high through that resistor, and when the button is pressed and connects the pin to ground, the small resistance of the closed switch overwhelms the pull-up and the pin reads low. A pull-down resistor does the reverse, defaulting the pin to low and pulling it high when pressed. Many PIC chips include configurable internal pull-up resistors on their pins, removing the need for an external one entirely.
| Button state | Pin reads |
|---|---|
| Not pressed | High (1) — pulled up through the resistor |
| Pressed | Low (0) — pulled directly to ground |
The second issue is switch bounce: the metal contacts inside a mechanical button don't close cleanly — they physically bounce for a few milliseconds, producing several rapid on/off transitions before settling. Read the pin during that window and your code may see one press as five or six. The simplest software fix, called debouncing, is to detect a change and then wait a short, fixed time — typically ten to twenty milliseconds — before trusting the new reading as stable.
void main(void) {
TRISB1 = 1; // RB1 as input (button)
TRISB0 = 0; // RB0 as output (LED)
while(1) {
if (PORTBbits.RB1 == 0) { // pressed (active-low)
__delay_ms(15); // wait out the bounce
if (PORTBbits.RB1 == 0) { // still pressed?
LATB0 = ~LATB0; // toggle the LED
while (PORTBbits.RB1 == 0); // wait for release
}
}
}
}