07. GPIO Output — Blinking LEDs
Embedded's "Hello, World" is blinking an LED. What value lights it (active-low/high wiring), how long to wait (delay), and how to make patterns with multiple LEDs (bit masks) — the essence of GPIO output is all here. We make a running light on 8 LEDs at P1 and observe the pin waveform in μVision's Logic Analyzer.
What you'll learn
- 1Control LEDs via GPIO output and explain active-low/high wiring
- 2Blink LEDs by changing the port value inside while(1)
- 3Understand software delay loops and their imprecision
- 4Make a running-light pattern with ~(1u<<pos)
- 5Observe pin toggles in the Logic Analyzer
Introduction
We repeat lesson 6's port writes inside an infinite loop to make patterns. Many 8051 boards wire LEDs active-low (on when the pin is 0), so the "only the bit you want = 0" sense matters.
Key concepts
1) LED wiring — active-low vs high
| Type | LED ON when |
|---|---|
| active-high (pin→LED→GND) | pin = 1 |
| active-low (VCC→LED→pin) | pin = 0 |
8051 sinks more current when outputting 0, so boards often wire LEDs active-low. This lesson assumes active-low.
2) Light one LED — ~(1u<<pos)
/* active-low: only bit pos = 0, rest = 1 */
pos=0 -> ~(1<<0) = 0xFE = 11111110 (LED0 ON)
pos=3 -> ~(1<<3) = 0xF7 = 11110111 (LED3 ON)
/* sweeping pos 0->7 makes the light flow one step at a time */3) Software delay
static void delay(unsigned int n) {
unsigned int i;
for (i = 0; i < n; i++) { } /* imprecise! exact time → timer (lesson 9) */
}The compiler may optimize away an empty loop. Mark the loop variable volatile to keep it, or use a timer (lesson 9) for precise delays.
Core example
#include <reg52.h>
#define LED_PORT P1
static void delay(unsigned int n){ unsigned int i; for(i=0;i<n;i++){} }
void main(void) {
unsigned char pos = 0;
while (1) {
LED_PORT = (unsigned char)~(1u << pos); /* one LED ON (active-low) */
delay(20000);
if (++pos >= 8) pos = 0;
}
}The running light produces 0xFE → 0xFD → 0xFB → 0xF7 → 0xEF → 0xDF → 0xBF → 0x7F. Add P1.0–P1.7 to the Logic Analyzer to see each pin drop Low in turn (a staircase waveform).
Common mistakes
Q. I wrote 1 to the port but the LED won't light.
A. On active-low boards, 1 is OFF — write 0 to turn it on. Check the schematic if unsure (this example is active-low).
Q. The LED stays on instead of blinking.
A. No delay or too short for the eye. Increase delay, or check the toggle itself on the Logic Analyzer's time axis.
Q. My empty delay loop vanished from optimization.
A. Declare the loop variable volatile, or use a timer (lesson 9) for an exact delay.
Summary
- The lighting value depends on wiring — active-low is ON at 0
- Light one LED: ~(1u << pos)
- while(1)+delay makes blinks/patterns, but software delay is imprecise
- Control multiple LEDs by ORing masks (invert if needed)
- Use the Logic Analyzer for waveforms, the Port window for bit values
Exercises
- Extend the running light into a back-and-forth (knight rider) pattern 7→0 as well
- Write a mask that lights two adjacent LEDs while flowing
- Explain and apply the change needed for an active-high board
All lecture materials and example code (with homework and answers) are openly available on GitHub.
View on GitHub ↗