From 9e676f1d641978dbf8710191e2fbf4488f44b812 Mon Sep 17 00:00:00 2001 From: mozzbozz Date: Thu, 18 Aug 2016 23:24:14 +0200 Subject: [PATCH] Implemented sensor modes and settings among other improvements --- Adafruit_BME280.cpp | 504 +++++++++++++++++------------ Adafruit_BME280.h | 285 +++++++++++----- examples/bme280test/bme280test.ino | 123 ++++++- 3 files changed, 621 insertions(+), 291 deletions(-) diff --git a/Adafruit_BME280.cpp b/Adafruit_BME280.cpp index e3b97cd..a9f9847 100644 --- a/Adafruit_BME280.cpp +++ b/Adafruit_BME280.cpp @@ -19,180 +19,238 @@ #include #include "Adafruit_BME280.h" - /*************************************************************************** PRIVATE FUNCTIONS ***************************************************************************/ - - Adafruit_BME280::Adafruit_BME280() - : _cs(-1), _mosi(-1), _miso(-1), _sck(-1) + : _cs(-1), _mosi(-1), _miso(-1), _sck(-1) { } Adafruit_BME280::Adafruit_BME280(int8_t cspin) - : _cs(cspin), _mosi(-1), _miso(-1), _sck(-1) + : _cs(cspin), _mosi(-1), _miso(-1), _sck(-1) { } Adafruit_BME280::Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin) - : _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin) + : _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin) { } -bool Adafruit_BME280::begin(uint8_t a) { - _i2caddr = a; +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings +*/ +/**************************************************************************/ +bool Adafruit_BME280::begin(uint8_t addr, + sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration + ) +{ + _i2caddr = addr; - if (_cs == -1) { - // i2c - Wire.begin(); - } else { - digitalWrite(_cs, HIGH); - pinMode(_cs, OUTPUT); - - if (_sck == -1) { - // hardware SPI - SPI.begin(); + // init I2C or SPI sensor interface + if (_cs == -1) { + // I2C + Wire.begin(); } else { - // software SPI - pinMode(_sck, OUTPUT); - pinMode(_mosi, OUTPUT); - pinMode(_miso, INPUT); + digitalWrite(_cs, HIGH); + pinMode(_cs, OUTPUT); + if (_sck == -1) { + // hardware SPI + SPI.begin(); + } else { + // software SPI + pinMode(_sck, OUTPUT); + pinMode(_mosi, OUTPUT); + pinMode(_miso, INPUT); + } } - } - if (read8(BME280_REGISTER_CHIPID) != 0x60) - return false; + // check if sensor, i.e. the chip ID is correct + if (read8(BME280_REGISTER_CHIPID) != 0x60) + return false; - readCoefficients(); + readCoefficients(); // read trimming parameters, see DS 4.2.2 + + _measReg.mode = mode; + _measReg.osrs_t = tempSampling; + _measReg.osrs_p = pressSampling; + + + _humReg.osrs_h = humSampling; + _configReg.filter = filter; + _configReg.t_sb = duration; - //Set before CONTROL_meas (DS 5.4.3) - write8(BME280_REGISTER_CONTROLHUMID, 0x05); //16x oversampling + + // you must make sure to also set REGISTER_CONTROL after setting the + // CONTROLHUMID register, otherwise the values won't be applied (see DS 5.4.3) + write8(BME280_REGISTER_CONTROLHUMID, _humReg.get()); + write8(BME280_REGISTER_CONFIG, _configReg.get()); + write8(BME280_REGISTER_CONTROL, _measReg.get()); - write8(BME280_REGISTER_CONTROL, 0xB7); // 16x ovesampling, normal mode - return true; + return true; } + +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings + + This is simply a overload to the normal begin()-function, so SPI users + don't get confused about the library requiring an address. +*/ +/**************************************************************************/ +bool Adafruit_BME280::begin(sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration + ) +{ + return begin(BME280_ADDRESS, mode, tempSampling, pressSampling, humSampling, filter, duration); +} + + +/**************************************************************************/ +/*! + @brief Encapsulate hardware and software SPI transfer into one function +*/ +/**************************************************************************/ uint8_t Adafruit_BME280::spixfer(uint8_t x) { - if (_sck == -1) - return SPI.transfer(x); + // hardware SPI + if (_sck == -1) + return SPI.transfer(x); - // software spi - //Serial.println("Software SPI"); - uint8_t reply = 0; - for (int i=7; i>=0; i--) { - reply <<= 1; - digitalWrite(_sck, LOW); - digitalWrite(_mosi, x & (1<=0; i--) { + reply <<= 1; + digitalWrite(_sck, LOW); + digitalWrite(_mosi, x & (1<> 8) | (temp << 8); - -} /**************************************************************************/ /*! - @brief Reads a signed 16 bit value over I2C + +*/ +/**************************************************************************/ +uint16_t Adafruit_BME280::read16_LE(byte reg) { + uint16_t temp = read16(reg); + return (temp >> 8) | (temp << 8); +} + + +/**************************************************************************/ +/*! + @brief Reads a signed 16 bit value over I2C or SPI */ /**************************************************************************/ int16_t Adafruit_BME280::readS16(byte reg) { - return (int16_t)read16(reg); - + return (int16_t)read16(reg); } + +/**************************************************************************/ +/*! + +*/ +/**************************************************************************/ int16_t Adafruit_BME280::readS16_LE(byte reg) { - return (int16_t)read16_LE(reg); - + return (int16_t)read16_LE(reg); } @@ -201,41 +259,60 @@ int16_t Adafruit_BME280::readS16_LE(byte reg) @brief Reads a 24 bit value over I2C */ /**************************************************************************/ - uint32_t Adafruit_BME280::read24(byte reg) { - uint32_t value; + uint32_t value; - if (_cs == -1) { - Wire.beginTransmission((uint8_t)_i2caddr); - Wire.write((uint8_t)reg); - Wire.endTransmission(); - Wire.requestFrom((uint8_t)_i2caddr, (byte)3); - - value = Wire.read(); - value <<= 8; - value |= Wire.read(); - value <<= 8; - value |= Wire.read(); + if (_cs == -1) { + Wire.beginTransmission((uint8_t)_i2caddr); + Wire.write((uint8_t)reg); + Wire.endTransmission(); + Wire.requestFrom((uint8_t)_i2caddr, (byte)3); - } else { - if (_sck == -1) - SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); - digitalWrite(_cs, LOW); - spixfer(reg | 0x80); // read, bit 7 high - - value = spixfer(0); - value <<= 8; - value |= spixfer(0); - value <<= 8; - value |= spixfer(0); + value = Wire.read(); + value <<= 8; + value |= Wire.read(); + value <<= 8; + value |= Wire.read(); + } else { + if (_sck == -1) + SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high - digitalWrite(_cs, HIGH); - if (_sck == -1) - SPI.endTransaction(); // release the SPI bus - } + value = spixfer(0); + value <<= 8; + value |= spixfer(0); + value <<= 8; + value |= spixfer(0); - return value; + digitalWrite(_cs, HIGH); + if (_sck == -1) + SPI.endTransaction(); // release the SPI bus + } + + return value; +} + + +/**************************************************************************/ +/*! + @brief Take a new measurement (only possible in forced mode) +*/ +/**************************************************************************/ +void Adafruit_BME280::takeForcedMeasurement() +{ + // If we are in forced mode, the BME sensor goes back to sleep after each + // measurement and we need to set it to forced mode once at this point, so + // it will take the next measurement and then return to sleep again. + // In normal mode simply does new measurements periodically. + if (_measReg.mode == MODE_FORCED) { + // set to forced mode, i.e. "take next measurement" + write8(BME280_REGISTER_CONTROL, _measReg.get()); + // wait until measurement has been completed, otherwise we would read + // the values from the last measurement + while (read8(BME280_REGISTER_STATUS) & 0x08); + } } @@ -268,95 +345,103 @@ void Adafruit_BME280::readCoefficients(void) _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); } + /**************************************************************************/ /*! - + @brief Returns the temperature from the sensor */ /**************************************************************************/ float Adafruit_BME280::readTemperature(void) { - int32_t var1, var2; + int32_t var1, var2; - int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); - adc_T >>= 4; + int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); + if (adc_T == 0x800000) // value in case temp measurement was disabled + return NAN; + adc_T >>= 4; - var1 = ((((adc_T>>3) - ((int32_t)_bme280_calib.dig_T1 <<1))) * - ((int32_t)_bme280_calib.dig_T2)) >> 11; + var1 = ((((adc_T>>3) - ((int32_t)_bme280_calib.dig_T1 <<1))) * + ((int32_t)_bme280_calib.dig_T2)) >> 11; + + var2 = (((((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1)) * + ((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) * + ((int32_t)_bme280_calib.dig_T3)) >> 14; - var2 = (((((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1)) * - ((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) * - ((int32_t)_bme280_calib.dig_T3)) >> 14; + t_fine = var1 + var2; - t_fine = var1 + var2; - - float T = (t_fine * 5 + 128) >> 8; - return T/100; + float T = (t_fine * 5 + 128) >> 8; + return T/100; } + /**************************************************************************/ /*! - + @brief Returns the temperature from the sensor */ /**************************************************************************/ float Adafruit_BME280::readPressure(void) { - int64_t var1, var2, p; + int64_t var1, var2, p; - readTemperature(); // must be done first to get t_fine + readTemperature(); // must be done first to get t_fine - int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); - adc_P >>= 4; + int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); + if (adc_P == 0x800000) // value in case pressure measurement was disabled + return NAN; + adc_P >>= 4; - var1 = ((int64_t)t_fine) - 128000; - var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; - var2 = var2 + ((var1*(int64_t)_bme280_calib.dig_P5)<<17); - var2 = var2 + (((int64_t)_bme280_calib.dig_P4)<<35); - var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3)>>8) + - ((var1 * (int64_t)_bme280_calib.dig_P2)<<12); - var1 = (((((int64_t)1)<<47)+var1))*((int64_t)_bme280_calib.dig_P1)>>33; + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; + var2 = var2 + ((var1*(int64_t)_bme280_calib.dig_P5)<<17); + var2 = var2 + (((int64_t)_bme280_calib.dig_P4)<<35); + var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3)>>8) + + ((var1 * (int64_t)_bme280_calib.dig_P2)<<12); + var1 = (((((int64_t)1)<<47)+var1))*((int64_t)_bme280_calib.dig_P1)>>33; - if (var1 == 0) { - return 0; // avoid exception caused by division by zero - } - p = 1048576 - adc_P; - p = (((p<<31) - var2)*3125) / var1; - var1 = (((int64_t)_bme280_calib.dig_P9) * (p>>13) * (p>>13)) >> 25; - var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19; + if (var1 == 0) { + return 0; // avoid exception caused by division by zero + } + p = 1048576 - adc_P; + p = (((p<<31) - var2)*3125) / var1; + var1 = (((int64_t)_bme280_calib.dig_P9) * (p>>13) * (p>>13)) >> 25; + var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7)<<4); - return (float)p/256; + p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7)<<4); + return (float)p/256; } /**************************************************************************/ /*! - + @brief Returns the humidity from the sensor */ /**************************************************************************/ float Adafruit_BME280::readHumidity(void) { + readTemperature(); // must be done first to get t_fine - readTemperature(); // must be done first to get t_fine + int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); + if (adc_H == 0x8000) // value in case humidity measurement was disabled + return NAN; + + int32_t v_x1_u32r; - int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); + v_x1_u32r = (t_fine - ((int32_t)76800)); - int32_t v_x1_u32r; + v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) - + (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * + (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + + ((int32_t)2097152)) * ((int32_t)_bme280_calib.dig_H2) + 8192) >> 14)); - v_x1_u32r = (t_fine - ((int32_t)76800)); + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)_bme280_calib.dig_H1)) >> 4)); - v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) - - (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * - (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) * - (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + - ((int32_t)2097152)) * ((int32_t)_bme280_calib.dig_H2) + 8192) >> 14)); - - v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * - ((int32_t)_bme280_calib.dig_H1)) >> 4)); - - v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; - v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; - float h = (v_x1_u32r>>12); - return h / 1024.0; + v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; + v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; + float h = (v_x1_u32r>>12); + return h / 1024.0; } + /**************************************************************************/ /*! Calculates the altitude (in meters) from the specified atmospheric @@ -368,17 +453,18 @@ float Adafruit_BME280::readHumidity(void) { /**************************************************************************/ float Adafruit_BME280::readAltitude(float seaLevel) { - // Equation taken from BMP180 datasheet (page 16): - // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + // Equation taken from BMP180 datasheet (page 16): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf - // Note that using the equation from wikipedia can give bad results - // at high altitude. See this thread for more information: - // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 - float atmospheric = readPressure() / 100.0F; - return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); + float atmospheric = readPressure() / 100.0F; + return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); } + /**************************************************************************/ /*! Calculates the pressure at sea level (in hPa) from the specified altitude @@ -389,12 +475,12 @@ float Adafruit_BME280::readAltitude(float seaLevel) /**************************************************************************/ float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) { - // Equation taken from BMP180 datasheet (page 17): - // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + // Equation taken from BMP180 datasheet (page 17): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf - // Note that using the equation from wikipedia can give bad results - // at high altitude. See this thread for more information: - // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 - - return atmospheric / pow(1.0 - (altitude/44330.0), 5.255); + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + return atmospheric / pow(1.0 - (altitude/44330.0), 5.255); } diff --git a/Adafruit_BME280.h b/Adafruit_BME280.h index 4136579..ed45c7f 100644 --- a/Adafruit_BME280.h +++ b/Adafruit_BME280.h @@ -37,39 +37,40 @@ -----------------------------------------------------------------------*/ enum { - BME280_REGISTER_DIG_T1 = 0x88, - BME280_REGISTER_DIG_T2 = 0x8A, - BME280_REGISTER_DIG_T3 = 0x8C, + BME280_REGISTER_DIG_T1 = 0x88, + BME280_REGISTER_DIG_T2 = 0x8A, + BME280_REGISTER_DIG_T3 = 0x8C, - BME280_REGISTER_DIG_P1 = 0x8E, - BME280_REGISTER_DIG_P2 = 0x90, - BME280_REGISTER_DIG_P3 = 0x92, - BME280_REGISTER_DIG_P4 = 0x94, - BME280_REGISTER_DIG_P5 = 0x96, - BME280_REGISTER_DIG_P6 = 0x98, - BME280_REGISTER_DIG_P7 = 0x9A, - BME280_REGISTER_DIG_P8 = 0x9C, - BME280_REGISTER_DIG_P9 = 0x9E, + BME280_REGISTER_DIG_P1 = 0x8E, + BME280_REGISTER_DIG_P2 = 0x90, + BME280_REGISTER_DIG_P3 = 0x92, + BME280_REGISTER_DIG_P4 = 0x94, + BME280_REGISTER_DIG_P5 = 0x96, + BME280_REGISTER_DIG_P6 = 0x98, + BME280_REGISTER_DIG_P7 = 0x9A, + BME280_REGISTER_DIG_P8 = 0x9C, + BME280_REGISTER_DIG_P9 = 0x9E, - BME280_REGISTER_DIG_H1 = 0xA1, - BME280_REGISTER_DIG_H2 = 0xE1, - BME280_REGISTER_DIG_H3 = 0xE3, - BME280_REGISTER_DIG_H4 = 0xE4, - BME280_REGISTER_DIG_H5 = 0xE5, - BME280_REGISTER_DIG_H6 = 0xE7, + BME280_REGISTER_DIG_H1 = 0xA1, + BME280_REGISTER_DIG_H2 = 0xE1, + BME280_REGISTER_DIG_H3 = 0xE3, + BME280_REGISTER_DIG_H4 = 0xE4, + BME280_REGISTER_DIG_H5 = 0xE5, + BME280_REGISTER_DIG_H6 = 0xE7, - BME280_REGISTER_CHIPID = 0xD0, - BME280_REGISTER_VERSION = 0xD1, - BME280_REGISTER_SOFTRESET = 0xE0, + BME280_REGISTER_CHIPID = 0xD0, + BME280_REGISTER_VERSION = 0xD1, + BME280_REGISTER_SOFTRESET = 0xE0, - BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 + BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 - BME280_REGISTER_CONTROLHUMID = 0xF2, - BME280_REGISTER_CONTROL = 0xF4, - BME280_REGISTER_CONFIG = 0xF5, - BME280_REGISTER_PRESSUREDATA = 0xF7, - BME280_REGISTER_TEMPDATA = 0xFA, - BME280_REGISTER_HUMIDDATA = 0xFD, + BME280_REGISTER_CONTROLHUMID = 0xF2, + BME280_REGISTER_STATUS = 0XF3, + BME280_REGISTER_CONTROL = 0xF4, + BME280_REGISTER_CONFIG = 0xF5, + BME280_REGISTER_PRESSUREDATA = 0xF7, + BME280_REGISTER_TEMPDATA = 0xFA, + BME280_REGISTER_HUMIDDATA = 0xFD }; /*=========================================================================*/ @@ -79,26 +80,26 @@ -----------------------------------------------------------------------*/ typedef struct { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; - uint8_t dig_H1; - int16_t dig_H2; - uint8_t dig_H3; - int16_t dig_H4; - int16_t dig_H5; - int8_t dig_H6; + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; } bme280_calib_data; /*=========================================================================*/ @@ -123,41 +124,179 @@ class Adafruit_BME280_Unified : public Adafruit_Sensor */ -class Adafruit_BME280 -{ - public: - Adafruit_BME280(void); - Adafruit_BME280(int8_t cspin); - Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin); +class Adafruit_BME280 { + public: + enum sensor_sampling { + SAMPLING_NONE = 0b000, + SAMPLING_X1 = 0b001, + SAMPLING_X2 = 0b010, + SAMPLING_X4 = 0b011, + SAMPLING_X8 = 0b100, + SAMPLING_X16 = 0b101 + }; - bool begin(uint8_t addr = BME280_ADDRESS); - float readTemperature(void); - float readPressure(void); - float readHumidity(void); - float readAltitude(float seaLevel); - float seaLevelForAltitude(float altitude, float atmospheric); + enum sensor_mode { + MODE_SLEEP = 0b00, + MODE_FORCED = 0b01, + MODE_NORMAL = 0b11 + }; - private: + enum sensor_filter { + FILTER_OFF = 0b000, + FILTER_X2 = 0b001, + FILTER_X4 = 0b010, + FILTER_X8 = 0b011, + FILTER_X16 = 0b100 + }; - void readCoefficients(void); - uint8_t spixfer(uint8_t x); + // standby durations in ms + enum standby_duration { + STANDBY_MS_0_5 = 0b000, + STANDBY_MS_10 = 0b110, + STANDBY_MS_20 = 0b111, + STANDBY_MS_62_5 = 0b001, + STANDBY_MS_125 = 0b010, + STANDBY_MS_250 = 0b011, + STANDBY_MS_500 = 0b100, + STANDBY_MS_1000 = 0b101 + }; + + // constructors + Adafruit_BME280(void); + Adafruit_BME280(int8_t cspin); + Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin); + + bool begin(uint8_t addr = BME280_ADDRESS, + sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_sampling humSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_0_5 + ); + + // overload function without address (-> for SPI users) + bool begin(sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_sampling humSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_0_5 + ); + + void takeForcedMeasurement(); + float readTemperature(void); + float readPressure(void); + float readHumidity(void); + + float readAltitude(float seaLevel); + float seaLevelForAltitude(float altitude, float pressure); - void write8(byte reg, byte value); - uint8_t read8(byte reg); - uint16_t read16(byte reg); - uint32_t read24(byte reg); - int16_t readS16(byte reg); - uint16_t read16_LE(byte reg); // little endian - int16_t readS16_LE(byte reg); // little endian + + private: + void readCoefficients(void); + uint8_t spixfer(uint8_t x); - uint8_t _i2caddr; - int32_t _sensorID; - int32_t t_fine; + void write8(byte reg, byte value); + uint8_t read8(byte reg); + uint16_t read16(byte reg); + uint32_t read24(byte reg); + int16_t readS16(byte reg); + uint16_t read16_LE(byte reg); // little endian + int16_t readS16_LE(byte reg); // little endian - int8_t _cs, _mosi, _miso, _sck; + uint8_t _i2caddr; + int32_t _sensorID; + int32_t t_fine; - bme280_calib_data _bme280_calib; + int8_t _cs, _mosi, _miso, _sck; + bme280_calib_data _bme280_calib; + + // The config register + struct config { + // inactive duration (standby time) in normal mode + // 000 = 0.5 ms + // 001 = 62.5 ms + // 010 = 125 ms + // 011 = 250 ms + // 100 = 500 ms + // 101 = 1000 ms + // 110 = 10 ms + // 111 = 20 ms + unsigned int t_sb : 3; + + // filter settings + // 000 = filter off + // 001 = 2x filter + // 010 = 4x filter + // 011 = 8x filter + // 100 and above = 16x filter + unsigned int filter : 3; + + // unused - don't set + unsigned int none : 1; + unsigned int spi3w_en : 1; + + unsigned int get() { + return (t_sb << 5) | (filter << 3) | spi3w_en; + } + }; + config _configReg; + + + // The ctrl_meas register + struct ctrl_meas { + // temperature oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_t : 3; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_p : 3; + + // device mode + // 00 = sleep + // 01 or 10 = forced + // 11 = normal + unsigned int mode : 2; + + unsigned int get() { + return (osrs_t << 5) | (osrs_p << 3) | mode; + } + }; + ctrl_meas _measReg; + + + // The ctrl_hum register + struct ctrl_hum { + // unused - don't set + unsigned int none : 5; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_h : 3; + + unsigned int get() { + return (osrs_h); + } + }; + ctrl_hum _humReg; }; #endif diff --git a/examples/bme280test/bme280test.ino b/examples/bme280test/bme280test.ino index 2c321b6..45b7c7c 100644 --- a/examples/bme280test/bme280test.ino +++ b/examples/bme280test/bme280test.ino @@ -5,7 +5,7 @@ ----> http://www.adafruit.com/products/2650 These sensors use I2C or SPI to communicate, 2 or 4 pins are required - to interface. + to interface. The device's I2C address is either 0x76 or 0x77. Adafruit invests time and resources providing this open source code, please support Adafruit andopen-source hardware by purchasing products @@ -29,19 +29,125 @@ Adafruit_BME280 bme; // I2C //Adafruit_BME280 bme(BME_CS); // hardware SPI -//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); +//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI + +unsigned long delayTime; void setup() { - Serial.begin(9600); - Serial.println(F("BME280 test")); + Serial.begin(9600); + Serial.println(F("BME280 test")); - if (!bme.begin()) { - Serial.println("Could not find a valid BME280 sensor, check wiring!"); - while (1); - } + bool status; + + // default settings + status = bme.begin(); + Serial.println("-- Default Test --"); + Serial.println("normal mode, 16x oversampling for all, filter off,"); + Serial.println("0.5ms standby period"); + delayTime = 5000; + + + // For more details on the following scenarious, see chapter + // 3.5 "Recommended modes of operation" in the datasheet + + /* + // weather monitoring + Serial.println("-- Weather Station Scenario --"); + Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,"); + Serial.println("filter off"); + status = bme.begin(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_X1, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_OFF + ); + + // suggested rate is 1/60Hz (1m) + delayTime = 60e3; + */ + + + /* + // humidity sensing + Serial.println("-- Humidity Sensing Scenario --"); + Serial.println("forced mode, 1x temperature / 1x humidity / 0x pressure oversampling"); + Serial.println("= pressure off, filter off"); + status = bme.begin(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_NONE, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_OFF + ); + + // suggested rate is 1Hz (1s) + delayTime = 1e3; + */ + + + /* + // indoor navigation + Serial.println("-- Indoor Navigation Scenario --"); + Serial.println("normal mode, 16x pressure / 2x temperature / 1x humidity oversampling,"); + Serial.println("0.5ms standby period, filter 16x"); + status = bme.begin(Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X2, // temperature + Adafruit_BME280::SAMPLING_X16, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_X16, + Adafruit_BME280::STANDBY_MS_0_5 + ); + + // suggested rate is 25Hz + // 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + (2 * H_ovs + 0.5) + // T_ovs = 2 + // P_ovs = 16 + // H_ovs = 1 + // = 40ms (25Hz) + // with standby time that should really be 24.16913... Hz + delayTime = 41; + */ + + + /* + // gaming + Serial.println("-- Gaming Scenario --"); + Serial.println("normal mode, 4x pressure / 1x temperature / 0x humidity oversampling,"); + Serial.println("= humidity off, 0.5ms standby period, filter 16x"); + status = bme.begin(Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_X4, // pressure + Adafruit_BME280::SAMPLING_NONE, // humidity + Adafruit_BME280::FILTER_X16, + Adafruit_BME280::STANDBY_MS_0_5 + ); + + // Suggested rate is 83Hz + // 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + // T_ovs = 1 + // P_ovs = 4 + // = 11.5ms + 0.5ms standby + delayTime = 12; + */ + + Serial.println(); + + if (!status) { + Serial.println("Could not find a valid BME280 sensor, check wiring!"); + while (1); + } } + void loop() { + // Only needed in forced mode! In normal mode, you can remove the next line. + bme.takeForcedMeasurement(); // has no effect in normal mode + + printValues(); + delay(delayTime); +} + + +void printValues() { Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C"); @@ -60,5 +166,4 @@ void loop() { Serial.println(" %"); Serial.println(); - delay(2000); }