Serial Protocols

Protocol Comparison

PropertySerial (UART)SPII2CPWM
Wires2 (TX, RX)4+ (SCK, COPI, CIPO, CS×n)2 (SDA, SCL)1
ClockNo (async)Yes (sync)Yes (sync)N/A
Max devices2Many (1 CS per device)10081
SpeedSlowFastMediumN/A
ComplexityLowMediumMediumLow
Python librarypyserialsmbus2gpiozero

Synchronous vs Asynchronous

  • Synchronous (SPI, I2C): shared clock wire — devices stay in sync
  • Asynchronous (UART): no clock — both sides must agree on baud rate

UART / Serial

  • Point-to-point only (2 devices)
  • Raspberry Pi GPIO14 = TX, GPIO15 = RX
  • Device path: /dev/ttyS0 or /dev/serial0
  • No clock wire — agree on baud rate in advance
import serial
 
# Context manager pattern (recommended)
with serial.Serial('/dev/serial0', 9600) as ser:
    while True:
        line = ser.readline()          # reads until '\n'
        print(f'Line: {line}')
        if line == b'hello\n':
            break
    ser.write(b'there\n')

MicroPython (Pico side)

from machine import UART, Pin
uart0 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
uart0.write('hello\n')

SPI (Serial Peripheral Interface)

  • Has clock wire (SCK) — synchronous
  • Full-duplex (simultaneous bidirectional data)
  • CS (Chip Select) = active LOW — controller pulls CS low to select peripheral
  • One CS pin needed per peripheral device
SignalMeaning
SCKClock (generated by controller)
COPIController-Out Peripheral-In (data to peripheral)
CIPOController-In Peripheral-Out (data from peripheral)
CSChip Select (active LOW, one per peripheral)

Old names (deprecated): MOSI/MISO/SS

I2C (Inter-Integrated Circuit)

  • Only 2 wires: SDA (data) + SCL (clock)
  • Up to 1008 peripheral devices on same bus
  • Each device has unique hexadecimal address
  • Slower than SPI

Detect I2C devices

i2cdetect -y 1
# Shows grid of hex addresses; UU = in use by kernel driver

Python with smbus2

from smbus2 import SMBus
 
with SMBus(1) as bus:
    b = bus.read_byte_data(80, 0)     # read 1 byte from addr 80, register 0
    print(b)
    bus.write_byte_data(80, 0, 45)    # write byte 45 to addr 80, register 0

In practice: use device-specific libraries (e.g., grove_temperature_humidity_aht20)

I2C Devices in Course

  • AHT20 temperature & humidity sensor
  • reTerminal accelerometer
  • reTerminal light sensor
  • reTerminal LCD driver

PWM (Pulse Width Modulation)

Digital signal that simulates analog by varying duty cycle.

  • Signal always HIGH (3.3V) or LOW (GND) — never in between
  • Duty cycle = % of time HIGH in one period
  • 0% = always off, 50% = half, 100% = always on

Applications

  • LED dimming: fast on/off tricks the eye
  • Servo motors: pulse width = arm position
from gpiozero import PWMLED, Servo
from time import sleep
 
# LED brightness (0=off, 1=full)
led = PWMLED(17)
led.value = 0      # off
led.value = 0.5    # half brightness
led.value = 1      # full brightness
 
# Servo
servo = Servo(17)
servo.min()    # minimum position
servo.mid()    # middle position
servo.max()    # maximum position

See Also