Sensors & I2C on Raspberry Pi Pico W

Sensors & I2C on Raspberry Pi Pico W

Use I2C to read temperature, humidity, and OLED displays.

I2C on the Pico W

I2C (Inter-Integrated Circuit) is a two-wire bus for connecting sensors and displays to a microcontroller. You only need two wires regardless of how many devices are connected:

  • SDA ߀” Serial Data
  • SCL ߀” Serial Clock

The Pico W has two I2C controllers. Common pin assignments:

I2C SDA pins SCL pins
I2C0 GPIO 0, 4, 8, 12, 16, 20 GPIO 1, 5, 9, 13, 17, 21
I2C1 GPIO 2, 6, 10, 14, 18, 26 GPIO 3, 7, 11, 15, 19, 27

Always add 4.7 k?© pull-up resistors to both SDA and SCL lines (many breakout boards include them).

Setting Up I2C

from machine import I2C, Pin

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)  # 400 kHz fast mode

Scanning for I2C Devices

devices = i2c.scan()
for addr in devices:
    print("Found I2C device at address:", hex(addr))

Common addresses:

  • 0x3C / 0x3D ߀” SSD1306 OLED display
  • 0x76 / 0x77 ߀” BME280 / BMP280 temperature/pressure sensor
  • 0x40 ߀” SHT31 humidity sensor
  • 0x68 ߀” MPU6050 accelerometer/gyro

Reading a BME280 (Temperature, Humidity, Pressure)

First, install the MicroPython BME280 library ߀” copy bme280.py to the Pico W.

from machine import I2C, Pin
import bme280

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
bme = bme280.BME280(i2c=i2c)

temp, pressure, humidity = bme.read_compensated_data()
print(f"Temp: {temp/100:.1f} ?°C")
print(f"Pressure: {pressure/25600:.1f} hPa")
print(f"Humidity: {humidity/1024:.1f} %")

Reading a DHT22 (Temperature & Humidity)

DHT sensors use a single-wire protocol, not I2C:

import dht
from machine import Pin

sensor = dht.DHT22(Pin(15))
sensor.measure()
print("Temperature:", sensor.temperature(), "?°C")
print("Humidity:", sensor.humidity(), "%")

DHT11 and DHT22 need at least 2 seconds between measurements.

SSD1306 OLED Display

The SSD1306 is a popular 128G—64 pixel OLED display. Install ssd1306.py on the Pico W.

from machine import I2C, Pin
import ssd1306

i2c = I2C(0, sda=Pin(0), scl=Pin(1))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)

oled.fill(0)                         # Clear screen (black)
oled.text("Hello, Pico W!", 0, 0)    # Text at x=0, y=0
oled.text("Temp: 22.5 C", 0, 16)
oled.show()                          # Push buffer to display

SPI Communication

For faster sensors or displays using SPI:

from machine import SPI, Pin

spi = SPI(0,
    baudrate=1000000,
    polarity=0,
    phase=0,
    sck=Pin(2),
    mosi=Pin(3),
    miso=Pin(4)
)

cs = Pin(5, Pin.OUT)
cs.value(0)                 # Select device
spi.write(b"\x00\x01")     # Send bytes
data = spi.read(2)          # Receive 2 bytes
cs.value(1)                 # Deselect

Combining Sensors with WiFi

A common pattern: read sensors and POST to a server.

import network, urequests, dht, ujson
from machine import Pin
from time import sleep

# Connect WiFi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("SSID", "Password")
while wlan.status() != 3:
    sleep(0.5)

sensor = dht.DHT22(Pin(15))

while True:
    sensor.measure()
    payload = ujson.dumps({
        "temperature": sensor.temperature(),
        "humidity": sensor.humidity()
    })
    r = urequests.post("https://yourserver.com/data",
                       data=payload,
                       headers={"Content-Type": "application/json"})
    r.close()
    sleep(60)