Example project · Sensors
Pico 2 I2C weather station
A real RP2350 boots the pinned official MicroPython v1.29.0 image (the default Arm build, on its Cortex-M33 cores), scans a BME280 and OLED on I2C0 (GP4/GP5), then continuously reads, displays, and prints the live weather values. Both devices use direct machine.I2C operations; change the sensor or disconnect SDA to see the real bus respond.

What's on the bench
- 2× Resistor
- Battery
- BME280
- OLED 128×64
- Pi Pico 2
How it's wired
- Battery · pos→Pi Pico 2 · vsys
- Battery · neg→Pi Pico 2 · gnd
- Pi Pico 2 · 3v3→BME280 · vcc
- Pi Pico 2 · gnd→BME280 · gnd
- Pi Pico 2 · gp4→BME280 · sda
- Pi Pico 2 · gp5→BME280 · scl
- Pi Pico 2 · 3v3→Resistor · a
- Resistor · b→BME280 · sda
- Pi Pico 2 · 3v3→Resistor · a
- Resistor · b→BME280 · scl
- Pi Pico 2 · 3v3→OLED 128×64 · vcc
- Pi Pico 2 · gnd→OLED 128×64 · gnd
- BME280 · sda→OLED 128×64 · sda
- BME280 · scl→OLED 128×64 · scl
The code
This MicroPython script runs on the emulated board every boot; edit it in the Code tab.
from machine import I2C, Pin from time import sleep_ms import framebuf i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000) oled_buf = bytearray(1024) oled = framebuf.FrameBuffer(oled_buf, 128, 64, framebuf.MONO_VLSB) def oled_init(): for c in b'\xae\xd5\x80\xa8\x3f\xd3\x00\x40\x8d\x14\x20\x00\xa1\xc8\xda\x12\x81\xcf\xd9\xf1\xdb\x40\xa4\xa6\xaf': i2c.writeto(0x3c, bytes([0, c])) def oled_show(): i2c.writeto(0x3c, b'\x00\x21\x00\x7f\x22\x00\x07') i2c.writeto(0x3c, b'\x40' + oled_buf) def u16(b, n): return b[n] | (b[n + 1] << 8) def s16(v): return v - 65536 if v & 0x8000 else v def s12(v): return v - 4096 if v & 0x800 else v def s8(v): return v - 256 if v & 0x80 else v def fixed(v): return ('-' if v < 0 else '') + '%d.%02d' % (abs(v) // 100, abs(v) % 100) configured = False last_display = None while True: try: if not configured: scan = i2c.scan() chip = i2c.readfrom_mem(0x76, 0xD0, 1)[0] i2c.writeto_mem(0x76, 0xF2, b'\x01') i2c.writeto_mem(0x76, 0xF4, b'\x27') ctrl = i2c.readfrom_mem(0x76, 0xF4, 1)[0] cal = i2c.readfrom_mem(0x76, 0x88, 26) hcal = i2c.readfrom_mem(0x76, 0xE1, 7) t1, t2, t3 = u16(cal, 0), s16(u16(cal, 2)), s16(u16(cal, 4)) p1 = u16(cal, 6) p2, p3, p4 = s16(u16(cal, 8)), s16(u16(cal, 10)), s16(u16(cal, 12)) p5, p6, p7 = s16(u16(cal, 14)), s16(u16(cal, 16)), s16(u16(cal, 18)) p8, p9 = s16(u16(cal, 20)), s16(u16(cal, 22)) h1, h2, h3 = cal[25], s16(u16(hcal, 0)), hcal[2] h4 = s12((hcal[3] << 4) | (hcal[4] & 15)) h5, h6 = s12((hcal[5] << 4) | (hcal[4] >> 4)), s8(hcal[6]) configured = 0x3c in scan and 0x76 in scan and chip == 0x60 and ctrl == 0x27 if configured: oled_init() if configured: raw = i2c.readfrom_mem(0x76, 0xF7, 8) adc_p = (raw[0] << 12) | (raw[1] << 4) | (raw[2] >> 4) adc_t = (raw[3] << 12) | (raw[4] << 4) | (raw[5] >> 4) adc_h = (raw[6] << 8) | raw[7] v1 = (((adc_t >> 3) - (t1 << 1)) * t2) >> 11 v2 = (((((adc_t >> 4) - t1) * ((adc_t >> 4) - t1)) >> 12) * t3) >> 14 fine = v1 + v2 temp = (fine * 5 + 128) >> 8 pv1 = fine - 128000 pv2 = pv1 * pv1 * p6 + (pv1 * p5 << 17) + (p4 << 35) pv1 = (((1 << 47) + (((pv1 * pv1 * p3) >> 8) + (pv1 * p2 << 12))) * p1) >> 33 pressure = 0 if pv1: pressure = (((1048576 - adc_p) << 31) - pv2) * 3125 // pv1 pv1 = (p9 * (pressure >> 13) * (pressure >> 13)) >> 25 pv2 = (p8 * pressure) >> 19 pressure = ((pressure + pv1 + pv2) >> 8) + (p7 << 4) hx = fine - 76800 ha = ((adc_h << 14) - (h4 << 20) - h5 * hx + 16384) >> 15 hb1 = (((hx * h6) >> 10) * (((hx * h3) >> 11) + 32768)) >> 10 hb = ((hb1 + 2097152) * h2 + 8192) >> 14 humidity = ha * hb humidity -= (((humidity >> 15) * (humidity >> 15) >> 7) * h1) >> 4 humidity = max(0, min(419430400, humidity)) >> 12 humidity = (humidity * 100 + 512) >> 10 pressure = (pressure + 128) >> 8 temp_s, humidity_s, pressure_s = fixed(temp), fixed(humidity), fixed(pressure) display_values = (temp_s, humidity_s, pressure_s) if display_values != last_display: oled.fill(0) oled.text('PICO 2 WEATHER', 0, 0) oled.text('T ' + temp_s + ' C', 0, 16) oled.text('RH ' + humidity_s + ' %', 0, 32) oled.text('P ' + pressure_s + ' hPa', 0, 48) oled_show() last_display = display_values print('P2-I2C-OK scan=%s chip=0x%02x ctrl=0x%02x temp=%sC humidity=%s%% pressure=%shPa' % (scan, chip, ctrl, temp_s, humidity_s, pressure_s)) except OSError: configured = False last_display = None print('P2-I2C-FAIL OSError') sleep_ms(1000)



