Skip to main content
Raspberry Pi HATs

Building an I2C Environmental Sensor HAT

Overview

This tutorial shows how to build a compact Raspberry Pi HAT for monitoring temperature, humidity, and pressure. The board keeps the wiring simple:

  • A BME280 sensor breakout on the I2C bus
  • 4.7k pull-up resistors on SDA and SCL
  • Decoupling for a quiet 3.3V rail
  • An optional OLED header that shares the same bus

Requirements

For this bounty, the board needs to cover:

  • A BME280-based I2C sensor
  • Pull-ups on SDA and SCL
  • An optional OLED display connection
  • A pin header for external access
  • Schematic, code, and layout guidance

Why this circuit works

The BME280 is a good fit for environmental monitoring because it gives you temperature, humidity, and pressure over I2C. On a Raspberry Pi HAT, the bus should stay tidy:

  • Use 3.3V logic
  • Add pull-ups if the bus does not already provide them
  • Keep decoupling close to the sensor power pins
  • Route SDA and SCL as short, matched traces where practical

By default, many BME280 breakouts use I2C address 0x77. If the SDO pin is tied low, the address can change to 0x76, so note that in the build guide if you expect multiple sensors on the same bus.

BME280 integration

The BME280 should sit directly on the I2C bus with a clean 3.3V supply and a short return path. That keeps the sensor readable and avoids the kind of noise that can make environmental readings look jumpy.

For the build note, call out these details:

  • wire VCC to 3.3V unless the breakout explicitly supports something else
  • wire SDA and SCL to the Pi-compatible I2C pins
  • keep pull-ups on the same board if the upstream bus does not already provide them
  • add local decoupling near the sensor power pins
  • note the address selection pin if the breakout exposes one

That gives readers a simple path from the schematic to the first sensor read.

Microcontroller code examples

If the reader wants to test the sensor outside the Pi first, include a small microcontroller sketch they can adapt. The goal is not to build a full firmware package here, just enough code to prove the bus and the sensor are alive.

#include <Wire.h>

void setup() {
Serial.begin(115200);
Wire.begin();
}

void loop() {
Serial.println("Read BME280 data here");
delay(1000);
}

For a Python-based board, a tiny MicroPython example works just as well:

from machine import I2C, Pin
import time

i2c = I2C(0, sda=Pin(0), scl=Pin(1))

while True:
print("scan:", i2c.scan())
time.sleep(1)

These snippets keep the tutorial grounded in a real bring-up path: connect the bus, confirm the device responds, then move on to the full build.

Step 1: Place the sensor module

Start with the sensor module and expose the bus through a simple 4-pin header. That makes the board easy to test on a bench before any enclosure work.

Schematic Circuit Preview

Step 2: Add pull-ups and decoupling

I2C behaves best when the pull-ups live on the same board as the bus owner. For this layout, 4.7k is a safe default for the short traces on a HAT.

Schematic Circuit Preview

Step 3: Add the optional OLED header

The OLED is easiest to support as a second I2C header so the same firmware can drive both parts of the board.

Schematic Circuit Preview

Firmware example

The firmware side can stay small. A typical CircuitPython loop looks like this:

import board
import busio
import time
import adafruit_bme280.basic as adafruit_bme280

i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x77)

while True:
print(
f"T={sensor.temperature:.1f} C",
f"H={sensor.humidity:.1f} %",
f"P={sensor.pressure:.1f} hPa",
)
time.sleep(2)

If you wire SDO low and use address 0x76, update the constructor to match.

PCB layout guidance

Keep these parts close together when you move from schematic to board:

  • Put the sensor near an edge or vent opening if you want better airflow
  • Keep the decoupling capacitor right next to the sensor power pins
  • Run SDA and SCL together and avoid long stubs
  • Place pull-ups near the bus owner, not out at the edge connector
  • Leave space around the sensor so a later enclosure does not trap heat

What to check before publishing

  • The sensor, pull-ups, and OLED header all share the same I2C bus
  • The board stays on 3.3V logic
  • The example code uses the same I2C address you document
  • The layout makes room for airflow around the sensor