A simple interface to GPIO devices with Raspberry Pi
—
SPI-connected devices including analog-to-digital converters (ADCs) from the MCP3xxx family. These devices enable reading analog sensor values and can be used as sources for other devices.
Base class for all SPI-connected devices.
class SPIDevice(Device):
def __init__(self, *, port=0, device=0, pin_factory=None):
"""
Base class for SPI devices.
Parameters:
- port: int - SPI port number (usually 0)
- device: int - SPI device number (chip select)
- pin_factory: Factory or None - Pin factory for advanced usage
"""
@property
def closed(self) -> bool:
"""Returns True if device is closed."""
def close(self):
"""Close the device and release resources."""Base class for analog-to-digital converter devices.
class AnalogInputDevice(SPIDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
Base class for ADC devices.
Parameters:
- channel: int - ADC channel number to read from
- differential: bool - True for differential reading, False for single-ended
- max_voltage: float - Maximum input voltage for scaling
- **spi_args: Additional SPI configuration arguments
"""
@property
def value(self) -> float:
"""Current analog reading scaled to 0.0-1.0 range."""
@property
def voltage(self) -> float:
"""Current reading as voltage (0.0 to max_voltage)."""
@property
def raw_value(self) -> int:
"""Raw ADC reading as integer."""
@property
def channel(self) -> int:
"""ADC channel being read."""
@property
def differential(self) -> bool:
"""True if using differential reading mode."""
@property
def max_voltage(self) -> float:
"""Maximum input voltage for scaling."""Single-channel 10-bit ADC.
class MCP3001(AnalogInputDevice):
def __init__(self, *, max_voltage=3.3, **spi_args):
"""
MCP3001 10-bit single-channel ADC.
Parameters:
- max_voltage: float - Maximum input voltage (default 3.3V)
- **spi_args: SPI configuration (port, device, etc.)
"""Dual-channel 10-bit ADC.
class MCP3002(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3002 10-bit dual-channel ADC.
Parameters:
- channel: int - Channel number (0 or 1)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""4-channel 10-bit ADC.
class MCP3004(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3004 10-bit 4-channel ADC.
Parameters:
- channel: int - Channel number (0-3)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""8-channel 10-bit ADC (most commonly used).
class MCP3008(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3008 10-bit 8-channel ADC.
Parameters:
- channel: int - Channel number (0-7)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration (port=0, device=0)
"""Single-channel 12-bit ADC.
class MCP3201(AnalogInputDevice):
def __init__(self, *, max_voltage=3.3, **spi_args):
"""
MCP3201 12-bit single-channel ADC.
Parameters:
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""Dual-channel 12-bit ADC.
class MCP3202(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3202 12-bit dual-channel ADC.
Parameters:
- channel: int - Channel number (0 or 1)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""4-channel 12-bit ADC.
class MCP3204(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3204 12-bit 4-channel ADC.
Parameters:
- channel: int - Channel number (0-3)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""8-channel 12-bit ADC.
class MCP3208(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3208 12-bit 8-channel ADC.
Parameters:
- channel: int - Channel number (0-7)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""Single-channel 13-bit signed ADC.
class MCP3301(AnalogInputDevice):
def __init__(self, *, max_voltage=3.3, **spi_args):
"""
MCP3301 13-bit single-channel signed ADC.
Parameters:
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""4-channel 13-bit signed ADC.
class MCP3302(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3302 13-bit 4-channel signed ADC.
Parameters:
- channel: int - Channel number (0-3)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""8-channel 13-bit signed ADC.
class MCP3304(AnalogInputDevice):
def __init__(self, channel=0, *, differential=False, max_voltage=3.3, **spi_args):
"""
MCP3304 13-bit 8-channel signed ADC.
Parameters:
- channel: int - Channel number (0-7)
- differential: bool - True for differential mode
- max_voltage: float - Maximum input voltage
- **spi_args: SPI configuration
"""from gpiozero import MCP3008
from time import sleep
# Single channel reading
adc = MCP3008(channel=0)
while True:
value = adc.value # 0.0 to 1.0
voltage = adc.voltage # 0.0 to 3.3V (or max_voltage)
raw = adc.raw_value # Raw ADC counts
print(f"Value: {value:.3f}, Voltage: {voltage:.2f}V, Raw: {raw}")
sleep(0.5)from gpiozero import MCP3008
# Create ADC objects for different channels
channels = [MCP3008(channel=i) for i in range(4)]
while True:
readings = [adc.value for adc in channels]
print(f"Channels 0-3: {readings}")
sleep(0.1)from gpiozero import MCP3008, PWMLED
from signal import pause
pot = MCP3008(channel=0)
led = PWMLED(17)
# LED brightness follows potentiometer
led.source = pot
pause()from gpiozero import MCP3008, LED
from time import sleep
sensor = MCP3008(channel=0)
warning_led = LED(17)
alarm_led = LED(18)
while True:
value = sensor.value
if value > 0.8:
warning_led.off()
alarm_led.on()
print("ALARM: High reading!")
elif value > 0.6:
warning_led.on()
alarm_led.off()
print("Warning: Elevated reading")
else:
warning_led.off()
alarm_led.off()
print(f"Normal: {value:.3f}")
sleep(0.5)from gpiozero import MCP3008
from time import sleep
# TMP36 temperature sensor on channel 0
temp_sensor = MCP3008(channel=0)
while True:
voltage = temp_sensor.voltage
# TMP36: 10mV per degree C, 500mV offset, 0°C = 0.5V
temperature_c = (voltage - 0.5) * 100
temperature_f = temperature_c * 9/5 + 32
print(f"Temperature: {temperature_c:.1f}°C ({temperature_f:.1f}°F)")
sleep(1)from gpiozero import MCP3008, LED
from signal import pause
# Photoresistor voltage divider on channel 0
light_sensor = MCP3008(channel=0)
night_light = LED(17)
def update_light():
light_level = light_sensor.value
# Turn on LED when it's dark (low light reading)
night_light.value = 1 - light_level
# Update every 100ms
light_sensor.when_changed = update_light
pause()from gpiozero import MCP3008
# Differential reading between channels 0 and 1
diff_adc = MCP3008(channel=0, differential=True)
while True:
# This reads the voltage difference between CH0+ and CH0- (CH1)
diff_voltage = diff_adc.voltage
print(f"Differential voltage: {diff_voltage:.3f}V")
sleep(0.1)from gpiozero import MCP3008
import csv
import time
sensors = [MCP3008(channel=i) for i in range(3)]
with open('sensor_data.csv', 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['timestamp', 'channel_0', 'channel_1', 'channel_2'])
try:
while True:
timestamp = time.time()
readings = [sensor.voltage for sensor in sensors]
writer.writerow([timestamp] + readings)
print(f"Logged: {readings}")
time.sleep(1)
except KeyboardInterrupt:
print("Data logging stopped")from gpiozero import MCP3008
# Using 5V reference instead of default 3.3V
adc_5v = MCP3008(channel=0, max_voltage=5.0)
while True:
voltage = adc_5v.voltage # Now scaled to 0-5V range
print(f"Voltage (5V ref): {voltage:.2f}V")
sleep(0.5)All MCP3xxx devices support additional SPI configuration parameters:
# Custom SPI configuration
adc = MCP3008(
channel=0,
port=0, # SPI port (usually 0)
device=1, # Chip select (CE1 instead of CE0)
max_voltage=5.0, # Voltage reference
differential=False # Single-ended reading
)Common SPI connections on Raspberry Pi:
Install with Tessl CLI
npx tessl i tessl/pypi-gpiozero