08. GPIO Input — Reading Buttons/Switches
Lesson 7 sent signals out; now we read them in. The 8051's quirk: its ports are quasi-bidirectional, so you must write 1 to a pin before reading it as input. We read a P3.2 button to control a P1.0 LED, and implement edge-detection that toggles on each press. Contact bounce (chatter) is covered in lesson 21.
What you'll learn
- 1Explain why you write 1 before reading on a quasi-bidirectional port
- 2Read an input pin via sbit and branch
- 3Understand pull-up/active-low buttons (1 idle, 0 pressed)
- 4Mirror button state onto an LED
- 5Detect edges (1→0) to catch only the press instant
Introduction
Reading digital signals from buttons·switches·sensors so the program reacts. Understanding the 8051 quasi-bidirectional-port trap is the heart of this lesson.
Key concepts
1) Quasi-bidirectional — write 1 before reading
8051 pins share an output latch and input buffer. With 0 latched, the pin is strongly held Low and external High won't read. Write 1 to "release" pins you'll use as input.
sbit BTN = P3 ^ 2;
BTN = 1; /* prepare input: pin to 1 (weak pull-up) */
if (BTN == 0) { } /* now external 0 reads */2) Pull-up + active-low button
| State | Pin |
|---|---|
| not pressed | 1 (pull-up) |
| pressed | 0 (GND) |
So "pressed" is `BTN == 0`.
3) Mirroring vs edge detection
if (prev_btn == 1 && btn == 0) { /* falling edge = just pressed */
led = !led; /* toggle (once) */
}
prev_btn = btn;Mirroring reacts while held (level); edge detection reacts only at the press instant. "Once per press" needs edge detection. Bounce is handled by debouncing in lesson 21.
Core example
#include <reg52.h>
sbit BTN = P3 ^ 2; /* input */
sbit LED = P1 ^ 0; /* output (active-low) */
void main(void) {
BTN = 1; /* prepare input */
while (1) {
if (BTN == 0) LED = 0; /* pressed → LED ON */
else LED = 1; /* released → LED OFF */
}
}Simulator: click the P3.2 bit in the Port 3 window to "press" the button and watch P1.0 follow in Port 1.
Common mistakes
Q. The input always reads the same value.
A. The quasi-bidirectional trap. If you ever wrote output 0 to that pin, input is blocked. Write BTN = 1; before reading.
Q. One press toggles the LED several times.
A. A too-fast loop mistakes "while held" for many toggles → use edge detection. If it's chatter, you need debouncing (lesson 21).
Q. if (P3 & 0x04 == 0) looks wrong.
A. Precedence trap: == binds before &, so 0x04==0 is first. Parenthesize: if ((P3 & 0x04) == 0), or use sbit: if (BTN == 0).
Summary
- A quasi-bidirectional port needs a 1 written before reading as input
- Pull-up + active-low button: 1 idle, 0 pressed — test BTN == 0
- Mirroring follows the current state; edge detection catches the press instant
- Edge detection compares previous and current state (prev==1 && cur==0)
- Contact bounce is solved by debouncing (lesson 21)
Exercises
- Write edge-detection code that moves the lit LED one step per press
- Predict the toggle result for {1,1,0,0,1,0} by hand, then verify in pc_test
- Read two buttons (P3.2/P3.3) to control two LEDs independently
All lecture materials and example code (with homework and answers) are openly available on GitHub.
View on GitHub ↗