Here’s a quick, practical guide to hooking sensors to a Raspberry Pi’s GPIO—covering digital, I²C, SPI, UART, and analog (via ADC), plus sample Python.
Golden rules (before you wire anything)
- 3.3 V only. Pi GPIO is not 5 V tolerant. Use level shifters for 5 V sensors.
- GND first. Always share ground between Pi and the sensor.
- Use the right pins. Prefer the BCM numbering in code.
- Pull-ups/downs. Inputs need a defined idle level (use Pi’s internal pulls or external resistors).
- Power budget. Don’t draw big loads from 3.3 V pin; high-current sensors need external supply.
Pin essentials (BCM)
- 3V3 power: Pin 1 (3V3), Pin 17 (3V3)
- 5V power: Pins 2, 4 (avoid for logic)
- Ground: Pins 6, 9, 14, 20, 25, 30, 34, 39
- I²C: SDA1 = GPIO2 (Pin 3), SCL1 = GPIO3 (Pin 5)
- SPI0: CE0 = GPIO8 (Pin 24), CE1 = GPIO7 (Pin 26), MOSI = GPIO10 (Pin 19), MISO = GPIO9 (Pin 21), SCLK = GPIO11 (Pin 23)
- UART: TXD = GPIO14 (Pin 8), RXD = GPIO15 (Pin 10)
- Any free GPIO for simple digital inputs/outputs
Common connection patterns
1) Simple digital input (e.g., button, PIR)
Wiring
- One side → GPIO (e.g., GPIO17/Pin 11)
- Other side → GND
- Use Pi’s internal pull-up
Python (gpiozero)
from gpiozero import Button
from signal import pause
btn = Button(17, pull_up=True) # internal pull-up
btn.when_pressed = lambda: print("Pressed")
btn.when_released = lambda: print("Released")
pause()
2) Digital output (e.g., LED via resistor)
Wiring
GPIO → resistor (220–1kΩ) → LED → GND
Python
from gpiozero import LED
from time import sleep
led = LED(18)
while True:
led.toggle()
sleep(0.5)
3) I²C sensor (e.g., BME280, MPU6050)
Wiring
- Sensor VCC → 3V3, GND → GND
- SDA → GPIO2 (Pin 3), SCL → GPIO3 (Pin 5)
- Most breakout boards include pull-ups; if not, add 4.7 kΩ to 3V3 on SDA/SCL
Enable & test
sudo raspi-config # Interface Options → I2C → Enable
sudo apt update && sudo apt install -y i2c-tools python3-smbus
i2cdetect -y 1 # should show the device address (e.g., 0x76)
Python (smbus2 + BME280 example)
import smbus2, time
BUS = smbus2.SMBus(1)
ADDR = 0x76
# Use a driver library for real projects; this is just a placeholder ping:
chip_id = BUS.read_byte_data(ADDR, 0xD0)
print("Chip ID:", hex(chip_id))
4) SPI sensor (e.g., MCP3008 ADC, ADS795x, some IMUs)
Wiring (MCP3008 example)
- VDD/VREF → 3V3, AGND/DGND → GND
- CLK → GPIO11, DOUT → GPIO9 (MISO), DIN → GPIO10 (MOSI), CS/SHDN → GPIO8 (CE0)
Enable & test
sudo raspi-config # Interface Options → SPI → Enable
sudo apt install -y python3-spidev
Python (read MCP3008 CH0)
import spidev
spi = spidev.SpiDev(); spi.open(0,0); spi.max_speed_hz = 1_000_000
def read_ch0():
# MCP3008 protocol: start(1) single-ended(1) ch(3) + 5 dummy bits
resp = spi.xfer2([0b00000001, 0b10000000, 0])
val = ((resp[1] & 0x03) << 8) | resp[2]
return val # 0..1023
print(read_ch0())
5) UART sensor/module (e.g., GPS, PM2.5)
Wiring
- 3V3 logic only (use level shifter if module is 5 V)
- Sensor TX → Pi RX (GPIO15), Sensor RX → Pi TX (GPIO14)
- GND → GND
Enable UART (disable serial console)
sudo raspi-config # Interface Options → Serial: login shell? No; enable HW serial? Yes
sudo apt install -y python3-serial
Python
import serial
ser = serial.Serial('/dev/serial0', 9600, timeout=1)
print(ser.readline().decode(errors='ignore'))
6) “Analog” sensors (pots, some gas/light sensors)
Pi has no built-in ADC, so use an external ADC (e.g., MCP3008 via SPI or ADS1115 via I²C).
ADS1115 (I²C) quick read (library-based)
# pip install adafruit-circuitpython-ads1x15
import board, busio
from adafruit_ads1x15.analog_in import AnalogIn
from adafruit_ads1x15.ads1115 import ADS1115
i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS1115(i2c)
chan = AnalogIn(ads, 0)
print(chan.voltage)
Troubleshooting checklist
- i2cdetect shows nothing? Check power/ground, SDA/SCL swapped, pull-ups, enable I²C.
- SPI returns zeros/noise? Wrong CS line, MISO/MOSI crossed, forgot to enable SPI, speed too high.
- UART gibberish? Wrong baud/format, serial console still enabled, 5 V logic without shifter.
- Random input flicker? Add/enable pull-ups/downs; debounce in software or RC network.
- Sensor is 5 V-only? Use a level shifter and, if needed, a separate 5 V supply.
Quick safety add-ons