PyRaspBeta

BME280 weather sensor

The BME280 is Bosch's temperature, humidity and barometric-pressure sensor, sold on a small breakout for $8. It talks I²C at 0x76 or 0x77 and runs happily from 3.3 V, which makes it the easiest way to add a full weather report to a build — and the reason it appears in the LCD weather station. It is a 6-pin part: power, ground, the two I²C lines, a chip-select that must stay high for I²C mode, and an address pin.

BME280 weather sensor

Pins

PinWhat it isType
VINSupply 1.8–3.6 V (3.3 V boards)power
GNDGroundground
SCLI²C clock (SCK)io
SDAI²C data (SDI)io
CSBChip select: leave high (or open) for I²Cio
SDOAddress select: GND 0x76, VIN 0x77io

In circuit.py:

CSB selects the interface: leave it open (or tie it to VIN, as here) and the chip speaks I²C; pull it low and it becomes an SPI device instead. SDO is the address pin: tied to ground the sensor answers at 0x76, tied to VIN at 0x77 — handy when two sensors share the bus.

Wiring it in circuit.py

circuit.py
from wiring import *

pi = Pi()

weather = BME280()

pi.V3_3 >> weather.vin
weather.gnd >> pi.GND
pi.SDA >> weather.sda
pi.SCL >> weather.scl
weather.sdo >> pi.GND                   # address 0x76

SDA and SCL are GPIO2 and GPIO3, the header's dedicated I²C pins; the board's on-board 1.8 kΩ pull-ups are already there, so no external resistors are needed. CSB is left unconnected in I²C mode. Changing the address is one wire: move weather.sdo from pi.GND to pi.V3_3 and the chip answers at 0x77.

Driving it in main.py

main.py
import time
import board
import adafruit_bme280.basic as adafruit_bme280

bme280 = adafruit_bme280.Adafruit_BME280_I2C(board.I2C(), address=0x76)

while True:
    print(f"{bme280.temperature:.1f} C  {bme280.humidity:.1f} %  {bme280.pressure:.1f} hPa")
    time.sleep(1)

The Adafruit driver handles the compensation formulas for you. If you would rather see the registers, the smbus2 notes show reading raw data, and things like sea_level_pressure on the Adafruit object let you correct pressure to sea level.

Electrical notes

  • Supply is 1.8–3.6 V. The breakout expects 3.3 V — do not power it from 5 V, and do not put the I²C lines on a 5 V bus.
  • Current is tiny: about 3.6 µA in normal 1 Hz operation and 0.1 µA asleep, so several can hang off the Pi's I²C with ease. CSB must be high or floating for I²C; pulling it low switches the chip to SPI.
  • Accuracy is ±1 °C, ±3 %RH and ±1 hPa; resolution is far finer (0.01 °C, 0.008 %RH, 0.0018 hPa).
  • Raw readings are meaningless without the factory trim registers at 0x88–0xA1 and 0xE1–0xE7 — always use a library, not read_byte_data.
  • It sleeps after power-on: a driver must write ctrl_hum (0xF2) then ctrl_meas (0xF4). ctrl_hum only takes effect on the following ctrl_meas write; that ordering catches hand-rolled drivers.
  • Its own heat makes it read slightly warm in continuous high-rate normal mode.

Simulator vs real hardware

  • The full register map is modelled: chip id 0x60 at 0xD0, the trim values, forced mode (measures once, then sleeps) and normal mode (fresh data latched at each read instant). A skipped measurement reads 0x80000 / 0x8000, as on the chip.
  • Values come from the feed for the sensor's zone. The feed's altitudeM knob lowers the pressure it measures with the barometric formula; the world's weather already varies the temperature and humidity it reports.
  • The I²C address follows the SDO net, so moving that one wire is enough to move the address.
  • Breakouts labelled BME280 are sometimes BMP280s (no humidity, chip id 0x58). The simulator only has the real BME280 — if a program checks the chip id, it sees 0x60.

Going deeper

Further reading