-
Notifications
You must be signed in to change notification settings - Fork 0
BMP280 BME280
BME280 5V 3.3V Digital Sensor Temperature Humidity Barometric Pressure Sensor Module I2C SPI 1.8-5V
Note: Cheap Chinese clones do not work reliably on SPI
The BMP280 sensor is an environmental sensor with temperature, barometric pressure that is the next generation upgrade to the BMP085/BMP180/BMP183. This sensor is great for all sorts of weather sensing and can even be used in both I2C and SPI!
This precision sensor from Bosch is the best low-cost, precision sensing solution for measuring barometric pressure with ±1 hPa absolute accuracy, and temperature with ±1.0°C accuracy. Because pressure changes with altitude and the pressure measurements are so good, you can also use it as an altimeter with ±1 meter accuracy.
The BMP280 is the next-generation of sensors from Bosch and is the upgrade to the BMP085/BMP180/BMP183 - with a low altitude noise of 0.25m and the same fast conversion time. It has the same specifications but can use either I2C or SPI. For simple easy wiring, go with I2C. If you want to connect a bunch of sensors without worrying about I2C address collisions, go with SPI.
#include <Arduino.h>
#include <SPI.h>
/*
BMP280 minimal SPI reader (no external libraries)
- Reads temperature (C) and pressure (hPa)
- Uses Bosch compensation formulas
- SPI Mode 0 confirmed working in your setup
Your pin mapping:
SCK = GPIO12 -> BMP280 SCL
MOSI = GPIO11 -> BMP280 SDA (SDI)
MISO = GPIO13 -> BMP280 SDD/SDO (SDO)
CS = GPIO17 -> BMP280 CSB
Power:
VCC = 3.3V
GND = GND
*/
static const int PIN_SCK = 12;
static const int PIN_MOSI = 11;
static const int PIN_MISO = 13;
static const int PIN_CS = 17;
static const uint32_t SPI_HZ = 100000; // start conservative; you can try 1 MHz later
// Calibration data
static uint16_t dig_T1;
static int16_t dig_T2, dig_T3;
static uint16_t dig_P1;
static int16_t dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;
static int32_t t_fine = 0;
static void cs_low() { digitalWrite(PIN_CS, LOW); }
static void cs_high() { digitalWrite(PIN_CS, HIGH); }
static uint8_t spi_read_u8(uint8_t reg) {
// BMP280 SPI: set bit7 to 1 for reads
uint8_t v;
SPI.beginTransaction(SPISettings(SPI_HZ, MSBFIRST, SPI_MODE0));
cs_low();
SPI.transfer(reg | 0x80);
v = SPI.transfer(0x00);
cs_high();
SPI.endTransaction();
return v;
}
static void spi_read_buf(uint8_t reg, uint8_t *buf, size_t len) {
SPI.beginTransaction(SPISettings(SPI_HZ, MSBFIRST, SPI_MODE0));
cs_low();
SPI.transfer(reg | 0x80);
for (size_t i = 0; i < len; i++) {
buf[i] = SPI.transfer(0x00);
}
cs_high();
SPI.endTransaction();
}
static void spi_write_u8(uint8_t reg, uint8_t val) {
// BMP280 SPI: bit7 must be 0 for writes
SPI.beginTransaction(SPISettings(SPI_HZ, MSBFIRST, SPI_MODE0));
cs_low();
SPI.transfer(reg & 0x7F);
SPI.transfer(val);
cs_high();
SPI.endTransaction();
}
static uint16_t u16le(const uint8_t *b) { return (uint16_t)b[0] | ((uint16_t)b[1] << 8); }
static int16_t s16le(const uint8_t *b) { return (int16_t)u16le(b); }
static bool bmp280_read_calibration() {
uint8_t b[24];
spi_read_buf(0x88, b, sizeof(b));
dig_T1 = u16le(&b[0]);
dig_T2 = s16le(&b[2]);
dig_T3 = s16le(&b[4]);
dig_P1 = u16le(&b[6]);
dig_P2 = s16le(&b[8]);
dig_P3 = s16le(&b[10]);
dig_P4 = s16le(&b[12]);
dig_P5 = s16le(&b[14]);
dig_P6 = s16le(&b[16]);
dig_P7 = s16le(&b[18]);
dig_P8 = s16le(&b[20]);
dig_P9 = s16le(&b[22]);
// Basic sanity check
if (dig_T1 == 0 || dig_P1 == 0) return false;
return true;
}
static bool bmp280_read_raw(int32_t &adc_T, int32_t &adc_P) {
uint8_t b[6];
spi_read_buf(0xF7, b, sizeof(b));
adc_P = ((int32_t)b[0] << 12) | ((int32_t)b[1] << 4) | (b[2] >> 4);
adc_T = ((int32_t)b[3] << 12) | ((int32_t)b[4] << 4) | (b[5] >> 4);
// Raw values should not be all zeros in normal operation
if (adc_T == 0 || adc_P == 0) {
// Not a hard failure, but suspicious; caller can decide
}
return true;
}
static float bmp280_compensate_temperature_c(int32_t adc_T) {
int32_t var1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * (int32_t)dig_T2) >> 11;
int32_t var2 = (((((adc_T >> 4) - (int32_t)dig_T1) * ((adc_T >> 4) - (int32_t)dig_T1)) >> 12) * (int32_t)dig_T3) >> 14;
t_fine = var1 + var2;
int32_t T = (t_fine * 5 + 128) >> 8; // 0.01 C
return (float)T / 100.0f;
}
static float bmp280_compensate_pressure_pa(int32_t adc_P) {
int64_t var1 = (int64_t)t_fine - 128000;
int64_t var2 = var1 * var1 * (int64_t)dig_P6;
var2 = var2 + ((var1 * (int64_t)dig_P5) << 17);
var2 = var2 + (((int64_t)dig_P4) << 35);
var1 = ((var1 * var1 * (int64_t)dig_P3) >> 8) + ((var1 * (int64_t)dig_P2) << 12);
var1 = (((((int64_t)1) << 47) + var1) * (int64_t)dig_P1) >> 33;
if (var1 == 0) return 0.0f; // avoid exception
int64_t p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = ((int64_t)dig_P9 * (p >> 13) * (p >> 13)) >> 25;
var2 = ((int64_t)dig_P8 * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)dig_P7) << 4);
// p is in Q24.8 -> Pa
return (float)p / 256.0f;
}
static bool bmp280_init() {
// Confirm chip ID
uint8_t id = spi_read_u8(0xD0);
if (id != 0x58) return false;
// Soft reset
spi_write_u8(0xE0, 0xB6);
delay(5);
// Configure:
// ctrl_meas (0xF4): osrs_t=001 (x1), osrs_p=001 (x1), mode=11 (normal) -> 0x27
// config (0xF5): t_sb=100 (500ms), filter=000, spi3w_en=0 -> 0x80
spi_write_u8(0xF4, 0x27);
spi_write_u8(0xF5, 0x80);
return bmp280_read_calibration();
}
void setup() {
Serial.begin(115200);
delay(200);
pinMode(PIN_CS, OUTPUT);
cs_high();
SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);
Serial.println("BMP280 SPI (MODE0) minimal reader starting...");
if (!bmp280_init()) {
Serial.print("BMP280 init failed. Chip ID read was: 0x");
Serial.println(spi_read_u8(0xD0), HEX);
return;
} else
{
int32_t adc_T, adc_P;
bmp280_read_raw(adc_T, adc_P);
bmp280_compensate_temperature_c(adc_T);
bmp280_compensate_pressure_pa(adc_P);
delay(50);
}
Serial.println("BMP280 init OK.");
}
void loop() {
int32_t adc_T = 0, adc_P = 0;
bmp280_read_raw(adc_T, adc_P);
float tempC = bmp280_compensate_temperature_c(adc_T);
float pressPa = bmp280_compensate_pressure_pa(adc_P);
Serial.print("Temp: ");
Serial.print(tempC, 2);
Serial.print(" C, Pressure: ");
Serial.print(pressPa / 100.0f, 2);
Serial.println(" hPa");
delay(1000);
}