BME280 and BMP280 pressure sensors

Bosch pressure sensors on a purple I2C breakout: the BMP280 reads pressure and temperature, and the BME280 adds humidity. Aliases: barometer, GY-BME280.

On the board the two look identical. The only way to tell them apart from a sketch is the chip-id register, 0xD0: 0x60 for a BME280 and 0x58 for a BMP280.

Pins

Pin What it does
VIN Supply. The module has its own regulator, so 3.3 V or 5 V.
GND Ground.
SCL I2C clock. The module carries the pull-ups.
SDA I2C data.

Properties

address is 0x76 or 0x77, the strap on the board. Most purple modules are at 0x76, and so is this part; Adafruit's own board and library default to 0x77. A tutorial written for a purple module says bme.begin(0x76), and when begin() fails the address is the first thing to check.

temperature (°C), pressure (hPa) and, on the BME280, humidity (%RH) are the weather, and the sliders on the part change them while the circuit runs. Standard sea-level pressure is 1013.25 hPa, and every 12 hPa less is about 100 m higher.

Counts, and a calibration you do yourself

The chip does not report degrees or pascals. It reports raw ADC counts, twenty bits for temperature and pressure and sixteen for humidity, and it carries its own factory-trimmed coefficients in registers 0x88 to 0xA1 and 0xE1 to 0xE7. Bosch's datasheet gives the integer arithmetic that turns the two into a reading, and every driver is that arithmetic. The temperature has to come first, because the pressure and humidity formulas both need a by-product of it, t_fine.

The part works those formulas backwards: from the sliders it finds the counts the datasheet's own compensation turns back into the same weather. A driver that gets the arithmetic right reads the sliders; one that gets a shift or a sign wrong reads nonsense, exactly as it would on a real sensor. The humidity coefficients dig_H4 and dig_H5 are twelve bits each and share register 0xE5, which is the line most hand-written drivers get wrong.

The libraries

Adafruit_BME280.h, Adafruit_BMP280.h and SparkFunBME280.h all work as their tutorials use them:

#include <Wire.h>
#include <Adafruit_BME280.h>

Adafruit_BME280 bme;

void setup() {
  Serial.begin(9600);
  if (!bme.begin(0x76)) {
    Serial.println("No BME280");
    while (1);
  }
}

void loop() {
  Serial.println(bme.readTemperature());       // C
  Serial.println(bme.readPressure());          // Pa
  Serial.println(bme.readAltitude(1013.25));   // m
  Serial.println(bme.readHumidity());          // %
  delay(1000);
}

The values are floats built from the datasheet's integer results, and the tutorials' bme.readPressure() / 100.0F works as written on every board; readPressureHPa(), which Mokxi adds, gives the same without the division. readAltitude() is worked in integers and lands within a few centimeters of the same formula in floating point.

What the model gets right

The register map and the reset values: asleep at power-up, data registers at 0x80000 and 0x8000 until something is measured, im_update set for the 2 ms the chip spends copying its coefficients. Forced mode takes one measurement and goes back to sleep; normal mode measures, waits the standby time, and repeats. A measurement takes the datasheet's typical time, from 8 ms at 1x oversampling to 113 ms at 16x, with measuring set while it runs.

ctrl_hum only takes effect at the next write to ctrl_meas, and humidity oversampling left at 0 means no humidity at all: the register reads its reset value. Both are straight from the datasheet and both catch people.

Resolution follows oversampling, 16 bits at 1x up to 20 at 16x, and the IIR filter blends each result into the last, so a slider moved with the filter on is followed smoothly rather than in a jump.

What it does not model

Noise. A real reading wanders by a few pascals and a few hundredths of a degree, which is what oversampling and the filter are for; here more samples change only the time and the number of bits. The drivers use Bosch's 32-bit pressure formula, since the smaller boards have no 64-bit multiply, and it reads a few pascals off the 64-bit one. SPI mode, and so CSB and SDO as pins, are not modeled: this is the I2C module. The humidity sensor's slow response to a change in the air is not modeled.

Common mistakes

The address: 0x76 on the purple modules, 0x77 in the libraries' defaults. Forgetting ctrl_hum in a hand-written driver and reading humidity as nonsense. Reading pressure without first reading temperature, so t_fine is stale.