Day 2 of 5
⏱ ~60 minutes
Raspberry Pi in 5 Days — Day 2

GPIO Basics

GPIO (General Purpose Input/Output) pins are what make the Pi a physical computing platform. Today you'll control the physical world from Python.

The GPIO Header

The Raspberry Pi 5 has a 40-pin GPIO header. Not all pins are GPIO — some are 3.3V power, 5V power, or ground. GPIO pins operate at 3.3V logic (NOT 5V — connecting 5V directly will damage the Pi). Pins can be configured as input (read voltage state) or output (set voltage high/low). Some pins have special functions: UART, SPI, I2C, PWM — we'll use those in Day 3.

Digital Output: LED Control

Digital output: set a pin HIGH (3.3V) or LOW (0V). Connect an LED with a 330Ω current-limiting resistor in series between the GPIO pin and ground. Without the resistor, you'll exceed the pin's 16mA max current and damage the GPIO controller. Use gpiozero (high-level) or RPi.GPIO (low-level). gpiozero is recommended — it handles cleanup automatically.

Digital Input and PWM

Digital input: read whether a pin is HIGH or LOW. Use the Pi's internal pull-up (pin pulled to 3.3V, button connects to ground) or pull-down resistors. PWM (Pulse Width Modulation): rapidly switch a pin on/off at a set frequency and duty cycle. 50% duty cycle = ~1.65V average. Use PWM to dim LEDs, control servo position, or set motor speed. Hardware PWM on GPIO12, 13, 18, 19 is more precise than software PWM.

python
#!/usr/bin/env python3
# GPIO examples: LED, button, PWM
# Run on Raspberry Pi: python3 gpio_demo.py

from gpiozero import LED, Button, PWMLED
from signal import pause
from time import sleep

# ── Digital Output: LED ─────────────────────────────────────
led = LED(17)  # GPIO17, pin 11

# Simple blink
for _ in range(5):
    led.on()   # 3.3V
    sleep(0.5)
    led.off()  # 0V
    sleep(0.5)

# ── Digital Input: Button ───────────────────────────────────
btn = Button(27)  # GPIO27, pin 13, internal pull-up enabled

print("Press button (GPIO27 to GND)...")
btn.wait_for_press(timeout=10)
print("Button pressed!")

# Event-driven: react to button
led2 = LED(17)
btn2 = Button(27)
btn2.when_pressed  = led2.on
btn2.when_released = led2.off

# ── PWM: LED brightness ─────────────────────────────────────
pwm_led = PWMLED(18)  # GPIO18 — hardware PWM capable

# Fade in
print("Fading LED...")
for v in [i/10 for i in range(11)]:
    pwm_led.value = v  # 0.0 to 1.0
    sleep(0.1)

# Fade out
for v in [i/10 for i in reversed(range(11))]:
    pwm_led.value = v
    sleep(0.1)

pwm_led.off()
print("Done. GPIO cleaned up automatically by gpiozero.")
💡
Always use a current-limiting resistor with LEDs on GPIO pins. The formula: R = (Vcc - Vled) / Iled = (3.3V - 2.0V) / 0.01A = 130Ω minimum. 330Ω is a safe default for most indicator LEDs. Forget the resistor and you'll burn out the GPIO pin controller.
📝 Day 2 Exercise
Build an LED Traffic Light
  1. Wire 3 LEDs (red, yellow, green) to GPIO17, 27, 22 with 330Ω resistors to ground on a breadboard.
  2. Write a Python script that cycles through: green 5s → yellow 2s → red 5s → repeat.
  3. Add a button on GPIO5 that triggers 'pedestrian crossing mode': force the sequence to jump to red immediately.
  4. Use PWM to make the yellow LED pulse instead of solid on — 2Hz blink using PWMLED.
  5. Add logging: print each state change with a timestamp. Pipe output to a file: python3 traffic.py >> traffic.log 2>&1 &

Day 2 Summary

  • GPIO pins are 3.3V logic — never connect 5V devices directly to GPIO pins
  • Always use a current-limiting resistor (330Ω) with LEDs — GPIO pins max at 16mA
  • gpiozero is the recommended library: Pythonic, auto-cleanup, event-driven callbacks
  • PWM dims LEDs and controls motors by rapidly switching between HIGH and LOW at a set duty cycle
Challenge

Connect a servo motor to GPIO18 (hardware PWM). Servos use 50Hz PWM signal: 1ms pulse = 0°, 1.5ms = 90°, 2ms = 180°. Use gpiozero's AngularServo class to sweep the servo from 0° to 180° and back. Then write a function that takes an angle as input and moves the servo to that position.

Finished this lesson?