diff --git a/.github/workflows/add_issue_to_project.yml b/.github/workflows/add_issue_to_project.yml new file mode 100644 index 0000000..6b60cc3 --- /dev/null +++ b/.github/workflows/add_issue_to_project.yml @@ -0,0 +1,18 @@ +name: Add new issue to our main project + +on: + issues: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@main + with: + # You can target a project in a different organization + # to the issue + project-url: https://github.com/orgs/sparkfun/projects/19 + github-token: ${{ secrets.DEFECT_ADD_TO_PROJECT }} diff --git a/README.md b/README.md index abb6523..3f3fc4b 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Some examples include a circular buffer class for averaging. Thanks to: * calvin1564 for [fixing a name collision](https://github.com/sparkfun/SparkFun_BME280_Arduino_Library/pull/34) * LukaHitH for adding [BMP280 support](https://github.com/sparkfun/SparkFun_BME280_Arduino_Library/pull/23) +* cdonate for adding [burst read](https://github.com/sparkfun/SparkFun_BME280_Arduino_Library/pull/50) +* jdavid for integrating [math.h](https://github.com/sparkfun/SparkFun_BME280_Arduino_Library/pull/49) Repository Contents ------------------- @@ -36,12 +38,16 @@ Documentation -------------- * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. -* **[Product Repository](https://github.com/sparkfun/BME280-Breakout-Board)** - Main repository (including hardware files) for the SparkFun BME280 Breakout. +* **Product Repositories:** (including hardware files) + * [SparkFun BME280 Breakout](https://github.com/sparkfun/BME280-Breakout-Board) - Original product repository + * [SparkFun Environmental Combo Breakout - CCS811/BME280 (Qwiic)](https://www.sparkfun.com/products/14348) + * [SparkFun Atmospheric Sensor Breakout - BME280 (Qwiic)](https://github.com/sparkfun/Qwiic_Atmospheric_Sensor_Breakout_BME280) * **[Hookup Guide](https://learn.sparkfun.com/tutorials/sparkfun-bme280-breakout-hookup-guide)** - Basic hookup guide for the SparkFun BME280 Breakout. Products that use this Library --------------------------------- +* [*SEN-15440*](https://www.sparkfun.com/products/15440) * [*SEN-14348*](https://www.sparkfun.com/products/14348) * [*SEN-13676*](https://www.sparkfun.com/products/13676) diff --git a/examples/Example10_DewPoint/Example10_DewPoint.ino b/examples/Example10_DewPoint/Example10_DewPoint.ino index 6c1b4b6..fa0781b 100644 --- a/examples/Example10_DewPoint/Example10_DewPoint.ino +++ b/examples/Example10_DewPoint/Example10_DewPoint.ino @@ -25,7 +25,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Example showing dewpoint calculation"); mySensor.setI2CAddress(0x76); //Connect to a second sensor diff --git a/examples/Example11_BurstRead/Example11_BurstRead.ino b/examples/Example11_BurstRead/Example11_BurstRead.ino new file mode 100644 index 0000000..6e94e7f --- /dev/null +++ b/examples/Example11_BurstRead/Example11_BurstRead.ino @@ -0,0 +1,68 @@ +/* + Get environmental readings as a burst from the BME280 + By: Claudio Donaté + Date: December 30th, 2020 + License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license). + + Feel like supporting our work? Buy a board from SparkFun! + https://www.sparkfun.com/products/14348 - Qwiic Combo Board + https://www.sparkfun.com/products/13676 - BME280 Breakout Board + + This example shows how to read humidity, pressure, and current temperature from the BME280 over I2C reading all registers at once. + Please check BME280 Datasheet, section 4, Data readout for detail explanations on why. + + Hardware connections: + BME280 -> Arduino + GND -> GND + 3.3 -> 3.3 + SDA -> A4 + SCL -> A5 +*/ + +#include + +#include "SparkFunBME280.h" + +#define CELSIUS_SCALE 0 //Default +#define FAHRENHEIT_SCALE 1 + +BME280 mySensor; +BME280_SensorMeasurements measurements; + +void setup() +{ + Serial.begin(115200); + Serial.println("Reading basic values from BME280 as a Burst"); + + Wire.begin(); + + if (mySensor.beginI2C() == false) //Begin communication over I2C + { + Serial.println("The sensor did not respond. Please check wiring."); + while(1); //Freeze + } +} + +void loop() +{ + while (mySensor.isMeasuring()) // Wait for sensor to finish measuring + { + Serial.print("."); + }; + + mySensor.readAllMeasurements(&measurements); // Return temperature in Celsius + // mySensor.readAllMeasurements(&measurements, FAHRENHEIT_SCALE); + + Serial.print("\nHumidity: "); + Serial.print(measurements.humidity, 0); + + Serial.print(" Pressure: "); + Serial.print(measurements.pressure, 0); + + Serial.print(" Temp: "); + Serial.print(measurements.temperature, 2); + + Serial.println(); + + delay(50); +} diff --git a/examples/Example1_BasicReadings/Example1_BasicReadings.ino b/examples/Example1_BasicReadings/Example1_BasicReadings.ino index a4078f8..3fe99c4 100644 --- a/examples/Example1_BasicReadings/Example1_BasicReadings.ino +++ b/examples/Example1_BasicReadings/Example1_BasicReadings.ino @@ -26,7 +26,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Reading basic values from BME280"); Wire.begin(); diff --git a/examples/Example2_I2CAddress/Example2_I2CAddress.ino b/examples/Example2_I2CAddress/Example2_I2CAddress.ino index d277347..7d97120 100644 --- a/examples/Example2_I2CAddress/Example2_I2CAddress.ino +++ b/examples/Example2_I2CAddress/Example2_I2CAddress.ino @@ -27,7 +27,7 @@ BME280 mySensorB; //Uses I2C address 0x76 (jumper closed) void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Example showing alternate I2C addresses"); Wire.begin(); diff --git a/examples/Example3_CSVOutput/Example3_CSVOutput.ino b/examples/Example3_CSVOutput/Example3_CSVOutput.ino index 03e9d43..cb34eff 100644 --- a/examples/Example3_CSVOutput/Example3_CSVOutput.ino +++ b/examples/Example3_CSVOutput/Example3_CSVOutput.ino @@ -21,7 +21,7 @@ unsigned long sampleNumber = 0; void setup() { - Serial.begin(9600); + Serial.begin(115200); Wire.begin(); diff --git a/examples/Example4_Settings/Example4_Settings.ino b/examples/Example4_Settings/Example4_Settings.ino index b9e61f9..f51b795 100644 --- a/examples/Example4_Settings/Example4_Settings.ino +++ b/examples/Example4_Settings/Example4_Settings.ino @@ -17,7 +17,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Example showing alternate I2C addresses"); Wire.begin(); diff --git a/examples/Example5_ReadAllRegisters/Example5_ReadAllRegisters.ino b/examples/Example5_ReadAllRegisters/Example5_ReadAllRegisters.ino index f15eda4..85acc6a 100644 --- a/examples/Example5_ReadAllRegisters/Example5_ReadAllRegisters.ino +++ b/examples/Example5_ReadAllRegisters/Example5_ReadAllRegisters.ino @@ -23,7 +23,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); while(!Serial); //Needed for printing correctly when using a Teensy Serial.println("Reading all registers from BME280"); diff --git a/examples/Example6_LowPower/Example6_LowPower.ino b/examples/Example6_LowPower/Example6_LowPower.ino index e2fd8a6..c42abe8 100644 --- a/examples/Example6_LowPower/Example6_LowPower.ino +++ b/examples/Example6_LowPower/Example6_LowPower.ino @@ -18,7 +18,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Example showing alternate I2C addresses"); Wire.begin(); diff --git a/examples/Example7_RelativeAltitudeChange/Example7_RelativeAltitudeChange.ino b/examples/Example7_RelativeAltitudeChange/Example7_RelativeAltitudeChange.ino index 7b3e136..586ed2d 100644 --- a/examples/Example7_RelativeAltitudeChange/Example7_RelativeAltitudeChange.ino +++ b/examples/Example7_RelativeAltitudeChange/Example7_RelativeAltitudeChange.ino @@ -41,7 +41,7 @@ float localAltitude = 0; void setup() { - Serial.begin(9600); + Serial.begin(115200); while(!Serial); //Wait for user to get terminal open Serial.println("Output a local changing altitude"); Serial.println("Press any key to zero local altitude"); diff --git a/examples/Example8_LocalPressure/Example8_LocalPressure.ino b/examples/Example8_LocalPressure/Example8_LocalPressure.ino index d1a4fcd..552be86 100644 --- a/examples/Example8_LocalPressure/Example8_LocalPressure.ino +++ b/examples/Example8_LocalPressure/Example8_LocalPressure.ino @@ -25,7 +25,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Example showing alternate I2C addresses"); Wire.begin(); diff --git a/examples/Example9_SoftwareI2C/Example9_SoftwareI2C.ino b/examples/Example9_SoftwareI2C/Example9_SoftwareI2C.ino index b5c3c6a..f47d0b1 100644 --- a/examples/Example9_SoftwareI2C/Example9_SoftwareI2C.ino +++ b/examples/Example9_SoftwareI2C/Example9_SoftwareI2C.ino @@ -31,7 +31,7 @@ BME280 mySensor; void setup() { - Serial.begin(9600); + Serial.begin(115200); Serial.println("Example showing alternate I2C addresses"); myWire.begin(); diff --git a/library.properties b/library.properties index 7fd0ba7..6f0f324 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=SparkFun BME280 -version=2.0.7 +version=2.0.11 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=A library to drive the Bosch BME280 Altimeter and Pressure sensor paragraph=The SparkFun CCS811/BME280 Environmental Combo Breakout takes care of all your atmospheric-quality sensing needs with the popular CCS811 and BME280 ICs. This unique breakout provides a variety of environmental data, including barometric pressure, humidity, temperature, TVOCs and equivalent CO2 (or eCO2) levels. category=Sensors url=https://github.com/sparkfun/SparkFun_BME280_Arduino_Library -architectures=* \ No newline at end of file +architectures=* diff --git a/src/SparkFunBME280.cpp b/src/SparkFunBME280.cpp index c312244..80e12c1 100644 --- a/src/SparkFunBME280.cpp +++ b/src/SparkFunBME280.cpp @@ -7,20 +7,21 @@ May 20, 2015 Resources: Uses Wire.h for i2c operation -Uses SPI.h for SPI operation +Uses _spiPort->h for SPI operation Development environment specifics: Arduino IDE 1.8.5 Teensy loader 1.23 This code is released under the [MIT License](http://opensource.org/licenses/MIT). -Please review the LICENSE.md file included with this example. If you have any questions +Please review the LICENSE.md file included with this example. If you have any questions or concerns with licensing, please contact techsupport@sparkfun.com. Distributed as-is; no warranty is given. ******************************************************************************/ -//See SparkFunBME280.h for additional topology notes. +// See SparkFunBME280.h for additional topology notes. #include "SparkFunBME280.h" +#include //****************************************************************************// // @@ -28,331 +29,367 @@ Distributed as-is; no warranty is given. // //****************************************************************************// -//Constructor -- Specifies default configuration -BME280::BME280( void ) +// Constructor -- Specifies default configuration +BME280::BME280(void) { - //Construct with these default settings + // Construct with these default settings - settings.commInterface = I2C_MODE; //Default to I2C + settings.commInterface = kSfeI2CMode; // Default to I2C - settings.I2CAddress = 0x77; //Default, jumper open is 0x77 - _hardPort = &Wire; //Default to Wire port + settings.I2CAddress = 0x77; // Default, jumper open is 0x77 + _hardPort = &Wire; // Default to Wire port - settings.chipSelectPin = 10; //Select CS pin for SPI - - //These are deprecated settings - settings.runMode = 3; //Normal/Run - settings.tStandby = 0; //0.5ms - settings.filter = 0; //Filter off - settings.tempOverSample = 1; - settings.pressOverSample = 1; - settings.humidOverSample = 1; - settings.tempCorrection = 0.0; // correction of temperature - added to the result -} + settings.chipSelectPin = 10; // Select CS pin for SPI + // These are deprecated settings + settings.runMode = 3; // Normal/Run + settings.tStandby = 0; // 0.5ms + settings.filter = 0; // Filter off + settings.tempOverSample = 1; + settings.pressOverSample = 1; + settings.humidOverSample = 1; + settings.tempCorrection = 0.f; // correction of temperature - added to the result +} //****************************************************************************// // // Configuration section // // This uses the stored BME280_SensorSettings to start the IMU -// Use statements such as "mySensor.settings.commInterface = SPI_MODE;" to +// Use statements such as "mySensor.settings.commInterface = SPI_MODE;" to // configure before calling .begin(); // //****************************************************************************// uint8_t BME280::begin() { - delay(2); //Make sure sensor had enough time to turn on. BME280 requires 2ms to start up. - - //Check the settings structure values to determine how to setup the device - switch (settings.commInterface) - { - - case I2C_MODE: - - switch(_wireType) - { - case(HARD_WIRE): - _hardPort->begin(); //The caller can begin their port and set the speed. We just confirm it here otherwise it can be hard to debug. - break; - case(SOFT_WIRE): - #ifdef SoftwareWire_h - _softPort->begin(); //The caller can begin their port and set the speed. We just confirm it here otherwise it can be hard to debug. - #endif - break; - } - break; - - case SPI_MODE: - // start the SPI library: - SPI.begin(); - // initialize the data ready and chip select pins: - pinMode(settings.chipSelectPin, OUTPUT); - digitalWrite(settings.chipSelectPin, HIGH); - break; - - default: - break; - } - - //Check communication with IC before anything else - uint8_t chipID = readRegister(BME280_CHIP_ID_REG); //Should return 0x60 or 0x58 - if(chipID != 0x58 && chipID != 0x60) // Is this BMP or BME? - return(chipID); //This is not BMP nor BME! - - //Reading all compensation data, range 0x88:A1, 0xE1:E7 - calibration.dig_T1 = ((uint16_t)((readRegister(BME280_DIG_T1_MSB_REG) << 8) + readRegister(BME280_DIG_T1_LSB_REG))); - calibration.dig_T2 = ((int16_t)((readRegister(BME280_DIG_T2_MSB_REG) << 8) + readRegister(BME280_DIG_T2_LSB_REG))); - calibration.dig_T3 = ((int16_t)((readRegister(BME280_DIG_T3_MSB_REG) << 8) + readRegister(BME280_DIG_T3_LSB_REG))); - - calibration.dig_P1 = ((uint16_t)((readRegister(BME280_DIG_P1_MSB_REG) << 8) + readRegister(BME280_DIG_P1_LSB_REG))); - calibration.dig_P2 = ((int16_t)((readRegister(BME280_DIG_P2_MSB_REG) << 8) + readRegister(BME280_DIG_P2_LSB_REG))); - calibration.dig_P3 = ((int16_t)((readRegister(BME280_DIG_P3_MSB_REG) << 8) + readRegister(BME280_DIG_P3_LSB_REG))); - calibration.dig_P4 = ((int16_t)((readRegister(BME280_DIG_P4_MSB_REG) << 8) + readRegister(BME280_DIG_P4_LSB_REG))); - calibration.dig_P5 = ((int16_t)((readRegister(BME280_DIG_P5_MSB_REG) << 8) + readRegister(BME280_DIG_P5_LSB_REG))); - calibration.dig_P6 = ((int16_t)((readRegister(BME280_DIG_P6_MSB_REG) << 8) + readRegister(BME280_DIG_P6_LSB_REG))); - calibration.dig_P7 = ((int16_t)((readRegister(BME280_DIG_P7_MSB_REG) << 8) + readRegister(BME280_DIG_P7_LSB_REG))); - calibration.dig_P8 = ((int16_t)((readRegister(BME280_DIG_P8_MSB_REG) << 8) + readRegister(BME280_DIG_P8_LSB_REG))); - calibration.dig_P9 = ((int16_t)((readRegister(BME280_DIG_P9_MSB_REG) << 8) + readRegister(BME280_DIG_P9_LSB_REG))); - - calibration.dig_H1 = ((uint8_t)(readRegister(BME280_DIG_H1_REG))); - calibration.dig_H2 = ((int16_t)((readRegister(BME280_DIG_H2_MSB_REG) << 8) + readRegister(BME280_DIG_H2_LSB_REG))); - calibration.dig_H3 = ((uint8_t)(readRegister(BME280_DIG_H3_REG))); - calibration.dig_H4 = ((int16_t)((readRegister(BME280_DIG_H4_MSB_REG) << 4) + (readRegister(BME280_DIG_H4_LSB_REG) & 0x0F))); - calibration.dig_H5 = ((int16_t)((readRegister(BME280_DIG_H5_MSB_REG) << 4) + ((readRegister(BME280_DIG_H4_LSB_REG) >> 4) & 0x0F))); - calibration.dig_H6 = ((int8_t)readRegister(BME280_DIG_H6_REG)); - - //Most of the time the sensor will be init with default values - //But in case user has old/deprecated code, use the settings.x values - setStandbyTime(settings.tStandby); - setFilter(settings.filter); - setPressureOverSample(settings.pressOverSample); //Default of 1x oversample - setHumidityOverSample(settings.humidOverSample); //Default of 1x oversample - setTempOverSample(settings.tempOverSample); //Default of 1x oversample - - setMode(MODE_NORMAL); //Go! - - return(readRegister(BME280_CHIP_ID_REG)); //Should return 0x60 -} - -//Begin comm with BME280 over SPI -bool BME280::beginSPI(uint8_t csPin) -{ - settings.chipSelectPin = csPin; - settings.commInterface = SPI_MODE; - - uint8_t chipID = begin(); - - if(chipID == 0x58) return(true); //Begin normal init with these settings. Should return chip ID of 0x58 for BMP - if(chipID == 0x60) return(true); //Begin normal init with these settings. Should return chip ID of 0x60 for BME - return(false); -} - -//Begin comm with BME280 over I2C + delay(2); // Make sure sensor had enough time to turn on. BME280 requires 2ms to start up. + + // Check the settings structure values to determine how to setup the device + switch (settings.commInterface) + { + + case kSfeI2CMode: + + // Removing port begin from library. This should be done by user otherwise this library will overwrite Wire + // settings such as clock speed. + // switch(_wireType) + // { + // case(HARD_WIRE): + // _hardPort->begin(); //The caller can begin their port and set the speed. We just confirm it here + // otherwise it can be hard to debug. break; case(SOFT_WIRE): #ifdef SoftwareWire_h + // _softPort->begin(); //The caller can begin their port and set the speed. We just confirm it here otherwise + // it can be hard to debug. #endif break; + // } + break; + + case kSfeSPIMode: + // start the SPI library: + _spiPort->begin(); + // initialize the data ready and chip select pins: + pinMode(settings.chipSelectPin, OUTPUT); + digitalWrite(settings.chipSelectPin, HIGH); + break; + + default: + break; + } + + // Check communication with IC before anything else + uint8_t chipID = readRegister(BME280_CHIP_ID_REG); // Should return 0x60 or 0x58 + if (chipID != 0x58 && chipID != 0x60) // Is this BMP or BME? + return (chipID); // This is not BMP nor BME! + + // Reading all compensation data, range 0x88:A1, 0xE1:E7 + calibration.dig_T1 = ((uint16_t)((readRegister(BME280_DIG_T1_MSB_REG) << 8) + readRegister(BME280_DIG_T1_LSB_REG))); + calibration.dig_T2 = ((int16_t)((readRegister(BME280_DIG_T2_MSB_REG) << 8) + readRegister(BME280_DIG_T2_LSB_REG))); + calibration.dig_T3 = ((int16_t)((readRegister(BME280_DIG_T3_MSB_REG) << 8) + readRegister(BME280_DIG_T3_LSB_REG))); + + calibration.dig_P1 = ((uint16_t)((readRegister(BME280_DIG_P1_MSB_REG) << 8) + readRegister(BME280_DIG_P1_LSB_REG))); + calibration.dig_P2 = ((int16_t)((readRegister(BME280_DIG_P2_MSB_REG) << 8) + readRegister(BME280_DIG_P2_LSB_REG))); + calibration.dig_P3 = ((int16_t)((readRegister(BME280_DIG_P3_MSB_REG) << 8) + readRegister(BME280_DIG_P3_LSB_REG))); + calibration.dig_P4 = ((int16_t)((readRegister(BME280_DIG_P4_MSB_REG) << 8) + readRegister(BME280_DIG_P4_LSB_REG))); + calibration.dig_P5 = ((int16_t)((readRegister(BME280_DIG_P5_MSB_REG) << 8) + readRegister(BME280_DIG_P5_LSB_REG))); + calibration.dig_P6 = ((int16_t)((readRegister(BME280_DIG_P6_MSB_REG) << 8) + readRegister(BME280_DIG_P6_LSB_REG))); + calibration.dig_P7 = ((int16_t)((readRegister(BME280_DIG_P7_MSB_REG) << 8) + readRegister(BME280_DIG_P7_LSB_REG))); + calibration.dig_P8 = ((int16_t)((readRegister(BME280_DIG_P8_MSB_REG) << 8) + readRegister(BME280_DIG_P8_LSB_REG))); + calibration.dig_P9 = ((int16_t)((readRegister(BME280_DIG_P9_MSB_REG) << 8) + readRegister(BME280_DIG_P9_LSB_REG))); + + calibration.dig_H1 = ((uint8_t)(readRegister(BME280_DIG_H1_REG))); + calibration.dig_H2 = ((int16_t)((readRegister(BME280_DIG_H2_MSB_REG) << 8) + readRegister(BME280_DIG_H2_LSB_REG))); + calibration.dig_H3 = ((uint8_t)(readRegister(BME280_DIG_H3_REG))); + calibration.dig_H4 = + ((int16_t)((readRegister(BME280_DIG_H4_MSB_REG) << 4) + (readRegister(BME280_DIG_H4_LSB_REG) & 0x0F))); + calibration.dig_H5 = + ((int16_t)((readRegister(BME280_DIG_H5_MSB_REG) << 4) + ((readRegister(BME280_DIG_H4_LSB_REG) >> 4) & 0x0F))); + calibration.dig_H6 = ((int8_t)readRegister(BME280_DIG_H6_REG)); + + // Most of the time the sensor will be init with default values + // But in case user has old/deprecated code, use the settings.x values + setStandbyTime(settings.tStandby); + setFilter(settings.filter); + setPressureOverSample(settings.pressOverSample); // Default of 1x oversample + setHumidityOverSample(settings.humidOverSample); // Default of 1x oversample + setTempOverSample(settings.tempOverSample); // Default of 1x oversample + + setMode(MODE_NORMAL); // Go! + + return (readRegister(BME280_CHIP_ID_REG)); // Should return 0x60 +} + +// Begin comm with BME280 over SPI +bool BME280::beginSPI(uint8_t csPin, SPIClass &spiPort) +{ + _spiPort = &spiPort; + settings.chipSelectPin = csPin; + settings.commInterface = kSfeSPIMode; + + uint8_t chipID = begin(); + + if (chipID == 0x58) + return (true); // Begin normal init with these settings. Should return chip ID of 0x58 for BMP + if (chipID == 0x60) + return (true); // Begin normal init with these settings. Should return chip ID of 0x60 for BME + return (false); +} + +// Begin comm with BME280 over I2C bool BME280::beginI2C(TwoWire &wirePort) { - _hardPort = &wirePort; - _wireType = HARD_WIRE; + _hardPort = &wirePort; + _wireType = HARD_WIRE; - settings.commInterface = I2C_MODE; - //settings.I2CAddress = 0x77; //We assume user has set the I2C address using setI2CAddress() + settings.commInterface = kSfeI2CMode; + // settings.I2CAddress = 0x77; //We assume user has set the I2C address using setI2CAddress() - uint8_t chipID = begin(); + uint8_t chipID = begin(); - if(chipID == 0x58) return(true); //Begin normal init with these settings. Should return chip ID of 0x58 for BMP - if(chipID == 0x60) return(true); //Begin normal init with these settings. Should return chip ID of 0x60 for BME - return(false); + if (chipID == 0x58) + return (true); // Begin normal init with these settings. Should return chip ID of 0x58 for BMP + if (chipID == 0x60) + return (true); // Begin normal init with these settings. Should return chip ID of 0x60 for BME + return (false); } -//Begin comm with BME280 over software I2C +// Begin comm with BME280 over software I2C #ifdef SoftwareWire_h -bool BME280::beginI2C(SoftwareWire& wirePort) +bool BME280::beginI2C(SoftwareWire &wirePort) { - _softPort = &wirePort; - _wireType = SOFT_WIRE; + _softPort = &wirePort; + _wireType = SOFT_WIRE; - settings.commInterface = I2C_MODE; - //settings.I2CAddress = 0x77; //We assume user has set the I2C address using setI2CAddress() + settings.commInterface = kSfeI2CMode; + // settings.I2CAddress = 0x77; //We assume user has set the I2C address using setI2CAddress() - uint8_t chipID = begin(); + uint8_t chipID = begin(); - if(chipID == 0x58) return(true); //Begin normal init with these settings. Should return chip ID of 0x58 for BMP - if(chipID == 0x60) return(true); //Begin normal init with these settings. Should return chip ID of 0x60 for BME - return(false); + if (chipID == 0x58) + return (true); // Begin normal init with these settings. Should return chip ID of 0x58 for BMP + if (chipID == 0x60) + return (true); // Begin normal init with these settings. Should return chip ID of 0x60 for BME + return (false); } #endif -//Set the mode bits in the ctrl_meas register -// Mode 00 = Sleep -// 01 and 10 = Forced -// 11 = Normal mode +// Set the mode bits in the ctrl_meas register +// Mode 00 = Sleep +// 01 and 10 = Forced +// 11 = Normal mode void BME280::setMode(uint8_t mode) { - if(mode > 0b11) mode = 0; //Error check. Default to sleep mode - - uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); - controlData &= ~( (1<<1) | (1<<0) ); //Clear the mode[1:0] bits - controlData |= mode; //Set - writeRegister(BME280_CTRL_MEAS_REG, controlData); + if (mode > 0b11) + mode = 0; // Error check. Default to sleep mode + + uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); + controlData &= ~((1 << 1) | (1 << 0)); // Clear the mode[1:0] bits + controlData |= mode; // Set + writeRegister(BME280_CTRL_MEAS_REG, controlData); } -//Gets the current mode bits in the ctrl_meas register -//Mode 00 = Sleep -// 01 and 10 = Forced -// 11 = Normal mode +// Gets the current mode bits in the ctrl_meas register +// Mode 00 = Sleep +// 01 and 10 = Forced +// 11 = Normal mode uint8_t BME280::getMode() { - uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); - return(controlData & 0b00000011); //Clear bits 7 through 2 + uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); + return (controlData & 0b00000011); // Clear bits 7 through 2 } -//Set the standby bits in the config register -//tStandby can be: -// 0, 0.5ms -// 1, 62.5ms -// 2, 125ms -// 3, 250ms -// 4, 500ms -// 5, 1000ms -// 6, 10ms -// 7, 20ms +// Set the standby bits in the config register +// tStandby can be: +// 0, 0.5ms +// 1, 62.5ms +// 2, 125ms +// 3, 250ms +// 4, 500ms +// 5, 1000ms +// 6, 10ms +// 7, 20ms void BME280::setStandbyTime(uint8_t timeSetting) { - if(timeSetting > 0b111) timeSetting = 0; //Error check. Default to 0.5ms - - uint8_t controlData = readRegister(BME280_CONFIG_REG); - controlData &= ~( (1<<7) | (1<<6) | (1<<5) ); //Clear the 7/6/5 bits - controlData |= (timeSetting << 5); //Align with bits 7/6/5 - writeRegister(BME280_CONFIG_REG, controlData); -} - -//Set the filter bits in the config register -//filter can be off or number of FIR coefficients to use: -// 0, filter off -// 1, coefficients = 2 -// 2, coefficients = 4 -// 3, coefficients = 8 -// 4, coefficients = 16 + if (timeSetting > 0b111) + timeSetting = 0; // Error check. Default to 0.5ms + + uint8_t controlData = readRegister(BME280_CONFIG_REG); + controlData &= ~((1 << 7) | (1 << 6) | (1 << 5)); // Clear the 7/6/5 bits + controlData |= (timeSetting << 5); // Align with bits 7/6/5 + writeRegister(BME280_CONFIG_REG, controlData); +} + +// Set the filter bits in the config register +// filter can be off or number of FIR coefficients to use: +// 0, filter off +// 1, coefficients = 2 +// 2, coefficients = 4 +// 3, coefficients = 8 +// 4, coefficients = 16 void BME280::setFilter(uint8_t filterSetting) { - if(filterSetting > 0b111) filterSetting = 0; //Error check. Default to filter off - - uint8_t controlData = readRegister(BME280_CONFIG_REG); - controlData &= ~( (1<<4) | (1<<3) | (1<<2) ); //Clear the 4/3/2 bits - controlData |= (filterSetting << 2); //Align with bits 4/3/2 - writeRegister(BME280_CONFIG_REG, controlData); + if (filterSetting > 0b111) + filterSetting = 0; // Error check. Default to filter off + + uint8_t controlData = readRegister(BME280_CONFIG_REG); + controlData &= ~((1 << 4) | (1 << 3) | (1 << 2)); // Clear the 4/3/2 bits + controlData |= (filterSetting << 2); // Align with bits 4/3/2 + writeRegister(BME280_CONFIG_REG, controlData); } -//Set the temperature oversample value -//0 turns off temp sensing -//1 to 16 are valid over sampling values +// Set the temperature oversample value +// 0 turns off temp sensing +// 1 to 16 are valid over sampling values void BME280::setTempOverSample(uint8_t overSampleAmount) { - overSampleAmount = checkSampleValue(overSampleAmount); //Error check - - uint8_t originalMode = getMode(); //Get the current mode so we can go back to it at the end - - setMode(MODE_SLEEP); //Config will only be writeable in sleep mode, so first go to sleep mode + overSampleAmount = checkSampleValue(overSampleAmount); // Error check + + uint8_t originalMode = getMode(); // Get the current mode so we can go back to it at the end - //Set the osrs_t bits (7, 6, 5) to overSampleAmount - uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); - controlData &= ~( (1<<7) | (1<<6) | (1<<5) ); //Clear bits 765 - controlData |= overSampleAmount << 5; //Align overSampleAmount to bits 7/6/5 - writeRegister(BME280_CTRL_MEAS_REG, controlData); - - setMode(originalMode); //Return to the original user's choice + setMode(MODE_SLEEP); // Config will only be writeable in sleep mode, so first go to sleep mode + + // Set the osrs_t bits (7, 6, 5) to overSampleAmount + uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); + controlData &= ~((1 << 7) | (1 << 6) | (1 << 5)); // Clear bits 765 + controlData |= overSampleAmount << 5; // Align overSampleAmount to bits 7/6/5 + writeRegister(BME280_CTRL_MEAS_REG, controlData); + + setMode(originalMode); // Return to the original user's choice } -//Set the pressure oversample value -//0 turns off pressure sensing -//1 to 16 are valid over sampling values +// Set the pressure oversample value +// 0 turns off pressure sensing +// 1 to 16 are valid over sampling values void BME280::setPressureOverSample(uint8_t overSampleAmount) { - overSampleAmount = checkSampleValue(overSampleAmount); //Error check - - uint8_t originalMode = getMode(); //Get the current mode so we can go back to it at the end - - setMode(MODE_SLEEP); //Config will only be writeable in sleep mode, so first go to sleep mode + overSampleAmount = checkSampleValue(overSampleAmount); // Error check + + uint8_t originalMode = getMode(); // Get the current mode so we can go back to it at the end + + setMode(MODE_SLEEP); // Config will only be writeable in sleep mode, so first go to sleep mode + + // Set the osrs_p bits (4, 3, 2) to overSampleAmount + uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); + controlData &= ~((1 << 4) | (1 << 3) | (1 << 2)); // Clear bits 432 + controlData |= overSampleAmount << 2; // Align overSampleAmount to bits 4/3/2 + writeRegister(BME280_CTRL_MEAS_REG, controlData); - //Set the osrs_p bits (4, 3, 2) to overSampleAmount - uint8_t controlData = readRegister(BME280_CTRL_MEAS_REG); - controlData &= ~( (1<<4) | (1<<3) | (1<<2) ); //Clear bits 432 - controlData |= overSampleAmount << 2; //Align overSampleAmount to bits 4/3/2 - writeRegister(BME280_CTRL_MEAS_REG, controlData); - - setMode(originalMode); //Return to the original user's choice + setMode(originalMode); // Return to the original user's choice } -//Set the humidity oversample value -//0 turns off humidity sensing -//1 to 16 are valid over sampling values +// Set the humidity oversample value +// 0 turns off humidity sensing +// 1 to 16 are valid over sampling values void BME280::setHumidityOverSample(uint8_t overSampleAmount) { - overSampleAmount = checkSampleValue(overSampleAmount); //Error check - - uint8_t originalMode = getMode(); //Get the current mode so we can go back to it at the end - - setMode(MODE_SLEEP); //Config will only be writeable in sleep mode, so first go to sleep mode + overSampleAmount = checkSampleValue(overSampleAmount); // Error check - //Set the osrs_h bits (2, 1, 0) to overSampleAmount - uint8_t controlData = readRegister(BME280_CTRL_HUMIDITY_REG); - controlData &= ~( (1<<2) | (1<<1) | (1<<0) ); //Clear bits 2/1/0 - controlData |= overSampleAmount << 0; //Align overSampleAmount to bits 2/1/0 - writeRegister(BME280_CTRL_HUMIDITY_REG, controlData); + uint8_t originalMode = getMode(); // Get the current mode so we can go back to it at the end - setMode(originalMode); //Return to the original user's choice + setMode(MODE_SLEEP); // Config will only be writeable in sleep mode, so first go to sleep mode + + // Set the osrs_h bits (2, 1, 0) to overSampleAmount + uint8_t controlData = readRegister(BME280_CTRL_HUMIDITY_REG); + controlData &= ~((1 << 2) | (1 << 1) | (1 << 0)); // Clear bits 2/1/0 + controlData |= overSampleAmount << 0; // Align overSampleAmount to bits 2/1/0 + writeRegister(BME280_CTRL_HUMIDITY_REG, controlData); + + setMode(originalMode); // Return to the original user's choice } -//Validates an over sample value -//Allowed values are 0 to 16 -//These are used in the humidty, pressure, and temp oversample functions +// Validates an over sample value +// Allowed values are 0 to 16 +// These are used in the humidty, pressure, and temp oversample functions uint8_t BME280::checkSampleValue(uint8_t userValue) { - switch(userValue) - { - case(0): - return 0; - break; //Valid - case(1): - return 1; - break; //Valid - case(2): - return 2; - break; //Valid - case(4): - return 3; - break; //Valid - case(8): - return 4; - break; //Valid - case(16): - return 5; - break; //Valid - default: - return 1; //Default to 1x - break; //Good - } -} - -//Set the global setting for the I2C address we want to communicate with -//Default is 0x77 + switch (userValue) + { + case (0): + return 0; + break; // Valid + case (1): + return 1; + break; // Valid + case (2): + return 2; + break; // Valid + case (4): + return 3; + break; // Valid + case (8): + return 4; + break; // Valid + case (16): + return 5; + break; // Valid + default: + return 1; // Default to 1x + break; // Good + } +} + +// Set the global setting for the I2C address we want to communicate with +// Default is 0x77 void BME280::setI2CAddress(uint8_t address) { - settings.I2CAddress = address; //Set the I2C address for this device + settings.I2CAddress = address; // Set the I2C address for this device } -//Check the measuring bit and return true while device is taking measurement +// Check the measuring bit and return true while device is taking measurement bool BME280::isMeasuring(void) { - uint8_t stat = readRegister(BME280_STAT_REG); - return(stat & (1<<3)); //If the measuring bit (3) is set, return true + uint8_t stat = readRegister(BME280_STAT_REG); + return (stat & (1 << 3)); // If the measuring bit (3) is set, return true } -//Strictly resets. Run .begin() afterwards -void BME280::reset( void ) +// Strictly resets. Run .begin() afterwards +void BME280::reset(void) { - writeRegister(BME280_RST_REG, 0xB6); - + writeRegister(BME280_RST_REG, 0xB6); +} + +//****************************************************************************// +// +// Burst Measurement Section +// +//****************************************************************************// + +// Read all sensor registers as a burst. See BME280 Datasheet section 4. Data readout +// tempScale = 0 for Celsius scale (default setting) +// tempScale = 1 for Fahrenheit scale +void BME280::readAllMeasurements(BME280_SensorMeasurements *measurements, uint8_t tempScale) +{ + + uint8_t dataBurst[8]; + readRegisterRegion(dataBurst, BME280_MEASUREMENTS_REG, 8); + + if (tempScale == 0) + { + readTempCFromBurst(dataBurst, measurements); + } + else + { + readTempFFromBurst(dataBurst, measurements); + } + readFloatPressureFromBurst(dataBurst, measurements); + readFloatHumidityFromBurst(dataBurst, measurements); } //****************************************************************************// @@ -360,65 +397,106 @@ void BME280::reset( void ) // Pressure Section // //****************************************************************************// -float BME280::readFloatPressure( void ) +float BME280::readFloatPressure(void) { - // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits). - // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa + // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits). + // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa uint8_t buffer[3]; - readRegisterRegion(buffer, BME280_PRESSURE_MSB_REG, 3); + readRegisterRegion(buffer, BME280_PRESSURE_MSB_REG, 3); + int32_t adc_P = ((uint32_t)buffer[0] << 12) | ((uint32_t)buffer[1] << 4) | ((buffer[2] >> 4) & 0x0F); + + int64_t var1, var2, p_acc; + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)calibration.dig_P6; + var2 = var2 + ((var1 * (int64_t)calibration.dig_P5) << 17); + var2 = var2 + (((int64_t)calibration.dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)calibration.dig_P3) >> 8) + ((var1 * (int64_t)calibration.dig_P2) << 12); + var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)calibration.dig_P1) >> 33; + if (var1 == 0) + { + return 0; // avoid exception caused by division by zero + } + p_acc = 1048576 - adc_P; + p_acc = (((p_acc << 31) - var2) * 3125) / var1; + var1 = (((int64_t)calibration.dig_P9) * (p_acc >> 13) * (p_acc >> 13)) >> 25; + var2 = (((int64_t)calibration.dig_P8) * p_acc) >> 19; + p_acc = ((p_acc + var1 + var2) >> 8) + (((int64_t)calibration.dig_P7) << 4); + + return (float)p_acc / 256.0; +} + +void BME280::readFloatPressureFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements) +{ + + // Set pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits). + // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa + int32_t adc_P = ((uint32_t)buffer[0] << 12) | ((uint32_t)buffer[1] << 4) | ((buffer[2] >> 4) & 0x0F); - - int64_t var1, var2, p_acc; - var1 = ((int64_t)t_fine) - 128000; - var2 = var1 * var1 * (int64_t)calibration.dig_P6; - var2 = var2 + ((var1 * (int64_t)calibration.dig_P5)<<17); - var2 = var2 + (((int64_t)calibration.dig_P4)<<35); - var1 = ((var1 * var1 * (int64_t)calibration.dig_P3)>>8) + ((var1 * (int64_t)calibration.dig_P2)<<12); - var1 = (((((int64_t)1)<<47)+var1))*((int64_t)calibration.dig_P1)>>33; - if (var1 == 0) - { - return 0; // avoid exception caused by division by zero - } - p_acc = 1048576 - adc_P; - p_acc = (((p_acc<<31) - var2)*3125)/var1; - var1 = (((int64_t)calibration.dig_P9) * (p_acc>>13) * (p_acc>>13)) >> 25; - var2 = (((int64_t)calibration.dig_P8) * p_acc) >> 19; - p_acc = ((p_acc + var1 + var2) >> 8) + (((int64_t)calibration.dig_P7)<<4); - - return (float)p_acc / 256.0; - -} - -//Sets the internal variable _referencePressure so the + + int64_t var1, var2, p_acc; + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)calibration.dig_P6; + var2 = var2 + ((var1 * (int64_t)calibration.dig_P5) << 17); + var2 = var2 + (((int64_t)calibration.dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)calibration.dig_P3) >> 8) + ((var1 * (int64_t)calibration.dig_P2) << 12); + var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)calibration.dig_P1) >> 33; + if (var1 == 0) + { + measurements->pressure = 0; // avoid exception caused by division by zero + } + else + { + p_acc = 1048576 - adc_P; + p_acc = (((p_acc << 31) - var2) * 3125) / var1; + var1 = (((int64_t)calibration.dig_P9) * (p_acc >> 13) * (p_acc >> 13)) >> 25; + var2 = (((int64_t)calibration.dig_P8) * p_acc) >> 19; + p_acc = ((p_acc + var1 + var2) >> 8) + (((int64_t)calibration.dig_P7) << 4); + + measurements->pressure = (float)p_acc / 256.0; + } +} + +// Sets the internal variable _referencePressure so the altitude is calculated properly. +// This is also known as "sea level pressure" and is in Pascals. The value is probably +// within 10% of 101325. This varies based on the weather: +// https://en.wikipedia.org/wiki/Atmospheric_pressure#Mean_sea-level_pressure +// +// if you are concerned about accuracy or precision, make sure to pull the +// "sea level pressure"value from a trusted source like NOAA. void BME280::setReferencePressure(float refPressure) { - _referencePressure = refPressure; + _referencePressure = refPressure; } -//Return the local reference pressure +// Return the local reference pressure float BME280::getReferencePressure() { - return(_referencePressure); + return (_referencePressure); } -float BME280::readFloatAltitudeMeters( void ) +float BME280::readFloatAltitudeMeters(void) { - float heightOutput = 0; - - //heightOutput = ((float)-45846.2)*(pow(((float)readFloatPressure()/(float)_referencePressure), 0.190263) - (float)1); - heightOutput = ((float)-44330.77)*(pow(((float)readFloatPressure()/(float)_referencePressure), 0.190263) - (float)1); //Corrected, see issue 30 - return heightOutput; - + float heightOutput = 0; + + // Getting height from a pressure reading is called the "international barometric height formula". + // The magic value of 44330.77 was adjusted in issue #30. + // There's also some discussion of it here: https://www.sparkfun.com/tutorials/253 + // This calculation is NOT designed to work on non-Earthlike planets such as Mars or Venus; + // see NRLMSISE-00. That's why it is the "international" formula, not "interplanetary". + // Sparkfun is not liable for incorrect altitude calculations from this + // code on those planets. Interplanetary selfies are welcome, however. + heightOutput = ((float)-44330.77) * (pow(((float)readFloatPressure() / (float)_referencePressure), 0.190263) - + (float)1); // Corrected, see issue 30 + return heightOutput; } -float BME280::readFloatAltitudeFeet( void ) +float BME280::readFloatAltitudeFeet(void) { - float heightOutput = 0; - - heightOutput = readFloatAltitudeMeters() * 3.28084; - return heightOutput; - + float heightOutput = 0; + + heightOutput = readFloatAltitudeMeters() * 3.28084; + return heightOutput; } //****************************************************************************// @@ -426,25 +504,58 @@ float BME280::readFloatAltitudeFeet( void ) // Humidity Section // //****************************************************************************// -float BME280::readFloatHumidity( void ) +float BME280::readFloatHumidity(void) { - - // Returns humidity in %RH as unsigned 32 bit integer in Q22. 10 format (22 integer and 10 fractional bits). - // Output value of “47445” represents 47445/1024 = 46. 333 %RH + + // Returns humidity in %RH as unsigned 32 bit integer in Q22. 10 format (22 integer and 10 fractional bits). + // Output value of “47445” represents 47445/1024 = 46. 333 %RH uint8_t buffer[2]; - readRegisterRegion(buffer, BME280_HUMIDITY_MSB_REG, 2); + readRegisterRegion(buffer, BME280_HUMIDITY_MSB_REG, 2); int32_t adc_H = ((uint32_t)buffer[0] << 8) | ((uint32_t)buffer[1]); - - int32_t var1; - var1 = (t_fine - ((int32_t)76800)); - var1 = (((((adc_H << 14) - (((int32_t)calibration.dig_H4) << 20) - (((int32_t)calibration.dig_H5) * var1)) + - ((int32_t)16384)) >> 15) * (((((((var1 * ((int32_t)calibration.dig_H6)) >> 10) * (((var1 * ((int32_t)calibration.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * - ((int32_t)calibration.dig_H2) + 8192) >> 14)); - var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32_t)calibration.dig_H1)) >> 4)); - var1 = (var1 < 0 ? 0 : var1); - var1 = (var1 > 419430400 ? 419430400 : var1); - return (float)(var1>>12) / 1024.0; + int32_t var1; + var1 = (t_fine - ((int32_t)76800)); + var1 = (((((adc_H << 14) - (((int32_t)calibration.dig_H4) << 20) - (((int32_t)calibration.dig_H5) * var1)) + + ((int32_t)16384)) >> + 15) * + (((((((var1 * ((int32_t)calibration.dig_H6)) >> 10) * + (((var1 * ((int32_t)calibration.dig_H3)) >> 11) + ((int32_t)32768))) >> + 10) + + ((int32_t)2097152)) * + ((int32_t)calibration.dig_H2) + + 8192) >> + 14)); + var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32_t)calibration.dig_H1)) >> 4)); + var1 = (var1 < 0 ? 0 : var1); + var1 = (var1 > 419430400 ? 419430400 : var1); + + return (float)(var1 >> 12) / 1024.0; +} + +void BME280::readFloatHumidityFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements) +{ + + // Set humidity in %RH as unsigned 32 bit integer in Q22. 10 format (22 integer and 10 fractional bits). + // Output value of “47445” represents 47445/1024 = 46. 333 %RH + int32_t adc_H = ((uint32_t)buffer[6] << 8) | ((uint32_t)buffer[7]); + + int32_t var1; + var1 = (t_fine - ((int32_t)76800)); + var1 = (((((adc_H << 14) - (((int32_t)calibration.dig_H4) << 20) - (((int32_t)calibration.dig_H5) * var1)) + + ((int32_t)16384)) >> + 15) * + (((((((var1 * ((int32_t)calibration.dig_H6)) >> 10) * + (((var1 * ((int32_t)calibration.dig_H3)) >> 11) + ((int32_t)32768))) >> + 10) + + ((int32_t)2097152)) * + ((int32_t)calibration.dig_H2) + + 8192) >> + 14)); + var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32_t)calibration.dig_H1)) >> 4)); + var1 = (var1 < 0 ? 0 : var1); + var1 = (var1 > 419430400 ? 419430400 : var1); + + measurements->humidity = (float)(var1 >> 12) / 1024.0; } //****************************************************************************// @@ -453,36 +564,74 @@ float BME280::readFloatHumidity( void ) // //****************************************************************************// -float BME280::readTempC( void ) +void BME280::setTemperatureCorrection(float corr) { - // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC. - // t_fine carries fine temperature as global value + settings.tempCorrection = corr; +} - //get the reading (adc_T); +float BME280::readTempC(void) +{ + // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC. + // t_fine carries fine temperature as global value + + // get the reading (adc_T); uint8_t buffer[3]; - readRegisterRegion(buffer, BME280_TEMPERATURE_MSB_REG, 3); + readRegisterRegion(buffer, BME280_TEMPERATURE_MSB_REG, 3); int32_t adc_T = ((uint32_t)buffer[0] << 12) | ((uint32_t)buffer[1] << 4) | ((buffer[2] >> 4) & 0x0F); - //By datasheet, calibrate - int64_t var1, var2; + // By datasheet, calibrate + int64_t var1, var2; + + var1 = ((((adc_T >> 3) - ((int32_t)calibration.dig_T1 << 1))) * ((int32_t)calibration.dig_T2)) >> 11; + var2 = (((((adc_T >> 4) - ((int32_t)calibration.dig_T1)) * ((adc_T >> 4) - ((int32_t)calibration.dig_T1))) >> 12) * + ((int32_t)calibration.dig_T3)) >> + 14; + t_fine = var1 + var2; + float output = (t_fine * 5 + 128) >> 8; + + output = output / 100 + settings.tempCorrection; + + return output; +} + +float BME280::readTempFromBurst(uint8_t buffer[]) +{ + int32_t adc_T = ((uint32_t)buffer[3] << 12) | ((uint32_t)buffer[4] << 4) | ((buffer[5] >> 4) & 0x0F); + + // By datasheet, calibrate + int64_t var1, var2; + + var1 = ((((adc_T >> 3) - ((int32_t)calibration.dig_T1 << 1))) * ((int32_t)calibration.dig_T2)) >> 11; + var2 = (((((adc_T >> 4) - ((int32_t)calibration.dig_T1)) * ((adc_T >> 4) - ((int32_t)calibration.dig_T1))) >> 12) * + ((int32_t)calibration.dig_T3)) >> + 14; + t_fine = var1 + var2; + float output = (t_fine * 5 + 128) >> 8; + + output = output / 100 + settings.tempCorrection; - var1 = ((((adc_T>>3) - ((int32_t)calibration.dig_T1<<1))) * ((int32_t)calibration.dig_T2)) >> 11; - var2 = (((((adc_T>>4) - ((int32_t)calibration.dig_T1)) * ((adc_T>>4) - ((int32_t)calibration.dig_T1))) >> 12) * - ((int32_t)calibration.dig_T3)) >> 14; - t_fine = var1 + var2; - float output = (t_fine * 5 + 128) >> 8; + return output; +} + +void BME280::readTempCFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements) +{ + measurements->temperature = readTempFromBurst(buffer); +} + +float BME280::readTempF(void) +{ + float output = readTempC(); + output = (output * 9) / 5 + 32; - output = output / 100 + settings.tempCorrection; - - return output; + return output; } -float BME280::readTempF( void ) +void BME280::readTempFFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements) { - float output = readTempC(); - output = (output * 9) / 5 + 32; + float output = readTempFromBurst(buffer); + output = (output * 9) / 5 + 32; - return output; + measurements->temperature = output; } //****************************************************************************// @@ -493,26 +642,26 @@ float BME280::readTempF( void ) // Returns Dew point in DegC double BME280::dewPointC(void) { - double celsius = readTempC(); - double humidity = readFloatHumidity(); - // (1) Saturation Vapor Pressure = ESGG(T) - double RATIO = 373.15 / (273.15 + celsius); - double RHS = -7.90298 * (RATIO - 1); - RHS += 5.02808 * log10(RATIO); - RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ; - RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ; - RHS += log10(1013.246); - // factor -3 is to adjust units - Vapor Pressure SVP * humidity - double VP = pow(10, RHS - 3) * humidity; - // (2) DEWPOINT = F(Vapor Pressure) - double T = log(VP/0.61078); // temp var - return (241.88 * T) / (17.558 - T); + double celsius = readTempC(); + double humidity = readFloatHumidity(); + // (1) Saturation Vapor Pressure = ESGG(T) + double RATIO = 373.15 / (273.15 + celsius); + double RHS = -7.90298 * (RATIO - 1); + RHS += 5.02808 * log10(RATIO); + RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / RATIO))) - 1); + RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1); + RHS += log10(1013.246); + // factor -3 is to adjust units - Vapor Pressure SVP * humidity + double VP = pow(10, RHS - 3) * humidity; + // (2) DEWPOINT = F(Vapor Pressure) + double T = log(VP / 0.61078); // temp var + return (241.88 * T) / (17.558 - T); } // Returns Dew point in DegF double BME280::dewPointF(void) { - return(dewPointC() * 1.8 + 32); //Convert C to F + return (dewPointC() * 1.8 + 32); // Convert C to F } //****************************************************************************// @@ -520,176 +669,177 @@ double BME280::dewPointF(void) // Utility // //****************************************************************************// -void BME280::readRegisterRegion(uint8_t *outputPointer , uint8_t offset, uint8_t length) -{ - //define pointer that will point to the external space - uint8_t i = 0; - char c = 0; - - switch (settings.commInterface) - { - - case I2C_MODE: - switch(_wireType) - { - case(HARD_WIRE): - _hardPort->beginTransmission(settings.I2CAddress); - _hardPort->write(offset); - _hardPort->endTransmission(); - - // request bytes from slave device - _hardPort->requestFrom(settings.I2CAddress, length); - while ( (_hardPort->available()) && (i < length)) // slave may send less than requested - { - c = _hardPort->read(); // receive a byte as character - *outputPointer = c; - outputPointer++; - i++; - } - break; - case(SOFT_WIRE): - #ifdef SoftwareWire_h - _softPort->beginTransmission(settings.I2CAddress); - _softPort->write(offset); - _softPort->endTransmission(); - - // request bytes from slave device - _softPort->requestFrom(settings.I2CAddress, length); - while ( (_softPort->available()) && (i < length)) // slave may send less than requested - { - c = _softPort->read(); // receive a byte as character - *outputPointer = c; - outputPointer++; - i++; - } - #endif - break; - } - break; - - case SPI_MODE: - SPI.beginTransaction(settings.spiSettings); - // take the chip select low to select the device: - digitalWrite(settings.chipSelectPin, LOW); - // send the device the register you want to read: - SPI.transfer(offset | 0x80); //Ored with "read request" bit - while ( i < length ) // slave may send less than requested - { - c = SPI.transfer(0x00); // receive a byte as character - *outputPointer = c; - outputPointer++; - i++; - } - // take the chip select high to de-select: - digitalWrite(settings.chipSelectPin, HIGH); - SPI.endTransaction(); - break; - - default: - break; - } - +void BME280::readRegisterRegion(uint8_t *outputPointer, uint8_t offset, uint8_t length) +{ + // define pointer that will point to the external space + uint8_t i = 0; + char c = 0; + + switch (settings.commInterface) + { + + case kSfeI2CMode: + switch (_wireType) + { + case (HARD_WIRE): + _hardPort->beginTransmission(settings.I2CAddress); + _hardPort->write(offset); + _hardPort->endTransmission(); + + // request bytes from slave device + _hardPort->requestFrom(settings.I2CAddress, length); + while ((_hardPort->available()) && (i < length)) // slave may send less than requested + { + c = _hardPort->read(); // receive a byte as character + *outputPointer = c; + outputPointer++; + i++; + } + break; + case (SOFT_WIRE): +#ifdef SoftwareWire_h + _softPort->beginTransmission(settings.I2CAddress); + _softPort->write(offset); + _softPort->endTransmission(); + + // request bytes from slave device + _softPort->requestFrom(settings.I2CAddress, length); + while ((_softPort->available()) && (i < length)) // slave may send less than requested + { + c = _softPort->read(); // receive a byte as character + *outputPointer = c; + outputPointer++; + i++; + } +#endif + break; + } + break; + + case kSfeSPIMode: + _spiPort->beginTransaction(settings.spiSettings); + // take the chip select low to select the device: + digitalWrite(settings.chipSelectPin, LOW); + // send the device the register you want to read: + _spiPort->transfer(offset | 0x80); // Ored with "read request" bit + while (i < length) // slave may send less than requested + { + c = _spiPort->transfer(0x00); // receive a byte as character + *outputPointer = c; + outputPointer++; + i++; + } + // take the chip select high to de-select: + digitalWrite(settings.chipSelectPin, HIGH); + _spiPort->endTransaction(); + break; + + default: + break; + } } uint8_t BME280::readRegister(uint8_t offset) { - //Return value - uint8_t result = 0; - uint8_t numBytes = 1; - switch (settings.commInterface) { - - case I2C_MODE: - switch(_wireType) - { - case(HARD_WIRE): - _hardPort->beginTransmission(settings.I2CAddress); - _hardPort->write(offset); - _hardPort->endTransmission(); - - _hardPort->requestFrom(settings.I2CAddress, numBytes); - while ( _hardPort->available() ) // slave may send less than requested - { - result = _hardPort->read(); // receive a byte as a proper uint8_t - } - break; - - case(SOFT_WIRE): - #ifdef SoftwareWire_h - _softPort->beginTransmission(settings.I2CAddress); - _softPort->write(offset); - _softPort->endTransmission(); - - _softPort->requestFrom(settings.I2CAddress, numBytes); - while ( _softPort->available() ) // slave may send less than requested - { - result = _softPort->read(); // receive a byte as a proper uint8_t - } - #endif - break; - } - - break; - - case SPI_MODE: - readRegisterRegion(&result, offset, 1); - break; - - default: - break; - } - return result; -} - -int16_t BME280::readRegisterInt16( uint8_t offset ) -{ - uint8_t myBuffer[2]; - readRegisterRegion(myBuffer, offset, 2); //Does memory transfer - int16_t output = (int16_t)myBuffer[0] | int16_t(myBuffer[1] << 8); - - return output; + // Return value + uint8_t result = 0; + uint8_t numBytes = 1; + uint8_t bytesAvailable; + switch (settings.commInterface) + { + + case kSfeI2CMode: + switch (_wireType) + { + case (HARD_WIRE): + _hardPort->beginTransmission(settings.I2CAddress); + _hardPort->write(offset); + _hardPort->endTransmission(); + + bytesAvailable = _hardPort->requestFrom(settings.I2CAddress, numBytes); + if (bytesAvailable == numBytes) + { + result = _hardPort->read(); + } + break; + + case (SOFT_WIRE): +#ifdef SoftwareWire_h + _softPort->beginTransmission(settings.I2CAddress); + _softPort->write(offset); + _softPort->endTransmission(); + + bytesAvailable = _softPort->requestFrom(settings.I2CAddress, numBytes); + if (bytesAvailable == numBytes) + { + result = _softPort->read(); + } +#endif + break; + } + + break; + + case kSfeSPIMode: + readRegisterRegion(&result, offset, 1); + break; + + default: + break; + } + return result; +} + +int16_t BME280::readRegisterInt16(uint8_t offset) +{ + uint8_t myBuffer[2]; + readRegisterRegion(myBuffer, offset, 2); // Does memory transfer + int16_t output = (int16_t)myBuffer[0] | int16_t(myBuffer[1] << 8); + + return output; } void BME280::writeRegister(uint8_t offset, uint8_t dataToWrite) { - switch (settings.commInterface) - { - case I2C_MODE: - //Write the byte - - switch(_wireType) - { - case(HARD_WIRE): - _hardPort->beginTransmission(settings.I2CAddress); - _hardPort->write(offset); - _hardPort->write(dataToWrite); - _hardPort->endTransmission(); - break; - case(SOFT_WIRE): - #ifdef SoftwareWire_h - _softPort->beginTransmission(settings.I2CAddress); - _softPort->write(offset); - _softPort->write(dataToWrite); - _softPort->endTransmission(); - #endif - break; - } - break; - - case SPI_MODE: - SPI.beginTransaction(settings.spiSettings); - // take the chip select low to select the device: - digitalWrite(settings.chipSelectPin, LOW); - // send the device the register you want to read: - SPI.transfer(offset & 0x7F); - // send a value of 0 to read the first byte returned: - SPI.transfer(dataToWrite); - // decrement the number of bytes left to read: - // take the chip select high to de-select: - digitalWrite(settings.chipSelectPin, HIGH); - SPI.endTransaction(); - break; - - default: - break; - } + switch (settings.commInterface) + { + case kSfeI2CMode: + // Write the byte + + switch (_wireType) + { + case (HARD_WIRE): + _hardPort->beginTransmission(settings.I2CAddress); + _hardPort->write(offset); + _hardPort->write(dataToWrite); + _hardPort->endTransmission(); + break; + case (SOFT_WIRE): +#ifdef SoftwareWire_h + _softPort->beginTransmission(settings.I2CAddress); + _softPort->write(offset); + _softPort->write(dataToWrite); + _softPort->endTransmission(); +#endif + break; + } + break; + + case kSfeSPIMode: + _spiPort->beginTransaction(settings.spiSettings); + // take the chip select low to select the device: + digitalWrite(settings.chipSelectPin, LOW); + // send the device the register you want to read: + _spiPort->transfer(offset & 0x7F); + // send a value of 0 to read the first byte returned: + _spiPort->transfer(dataToWrite); + // decrement the number of bytes left to read: + // take the chip select high to de-select: + digitalWrite(settings.chipSelectPin, HIGH); + _spiPort->endTransaction(); + break; + + default: + break; + } } diff --git a/src/SparkFunBME280.h b/src/SparkFunBME280.h index 0b7b766..89debc2 100644 --- a/src/SparkFunBME280.h +++ b/src/SparkFunBME280.h @@ -14,14 +14,14 @@ Arduino IDE 1.6.4 Teensy loader 1.23 This code is released under the [MIT License](http://opensource.org/licenses/MIT). -Please review the LICENSE.md file included with this example. If you have any questions +Please review the LICENSE.md file included with this example. If you have any questions or concerns with licensing, please contact techsupport@sparkfun.com. Distributed as-is; no warranty is given. TODO: - roll library ver to 2.0 - remove hard wire. - write escalating examples + roll library ver to 2.0 + remove hard wire. + write escalating examples ******************************************************************************/ @@ -36,15 +36,15 @@ Distributed as-is; no warranty is given. #include "WProgram.h" #endif -#include #include +#include -//Uncomment the following line to enable software I2C -//You will need to have the SoftwareWire library installed -//#include //SoftwareWire by Testato. Installed from library manager. +// Uncomment the following line to enable software I2C +// You will need to have the SoftwareWire library installed +// #include //SoftwareWire by Testato. Installed from library manager. -#define I2C_MODE 0 -#define SPI_MODE 1 +#define kSfeI2CMode 0 +#define kSfeSPIMode 1 #ifndef BME280_SPI_CLOCK #ifdef ARDUINO_ARCH_ESP32 @@ -66,196 +66,212 @@ Distributed as-is; no warranty is given. #define MODE_FORCED 0b01 #define MODE_NORMAL 0b11 -//Register names: -#define BME280_DIG_T1_LSB_REG 0x88 -#define BME280_DIG_T1_MSB_REG 0x89 -#define BME280_DIG_T2_LSB_REG 0x8A -#define BME280_DIG_T2_MSB_REG 0x8B -#define BME280_DIG_T3_LSB_REG 0x8C -#define BME280_DIG_T3_MSB_REG 0x8D -#define BME280_DIG_P1_LSB_REG 0x8E -#define BME280_DIG_P1_MSB_REG 0x8F -#define BME280_DIG_P2_LSB_REG 0x90 -#define BME280_DIG_P2_MSB_REG 0x91 -#define BME280_DIG_P3_LSB_REG 0x92 -#define BME280_DIG_P3_MSB_REG 0x93 -#define BME280_DIG_P4_LSB_REG 0x94 -#define BME280_DIG_P4_MSB_REG 0x95 -#define BME280_DIG_P5_LSB_REG 0x96 -#define BME280_DIG_P5_MSB_REG 0x97 -#define BME280_DIG_P6_LSB_REG 0x98 -#define BME280_DIG_P6_MSB_REG 0x99 -#define BME280_DIG_P7_LSB_REG 0x9A -#define BME280_DIG_P7_MSB_REG 0x9B -#define BME280_DIG_P8_LSB_REG 0x9C -#define BME280_DIG_P8_MSB_REG 0x9D -#define BME280_DIG_P9_LSB_REG 0x9E -#define BME280_DIG_P9_MSB_REG 0x9F -#define BME280_DIG_H1_REG 0xA1 -#define BME280_CHIP_ID_REG 0xD0 //Chip ID -#define BME280_RST_REG 0xE0 //Softreset Reg -#define BME280_DIG_H2_LSB_REG 0xE1 -#define BME280_DIG_H2_MSB_REG 0xE2 -#define BME280_DIG_H3_REG 0xE3 -#define BME280_DIG_H4_MSB_REG 0xE4 -#define BME280_DIG_H4_LSB_REG 0xE5 -#define BME280_DIG_H5_MSB_REG 0xE6 -#define BME280_DIG_H6_REG 0xE7 -#define BME280_CTRL_HUMIDITY_REG 0xF2 //Ctrl Humidity Reg -#define BME280_STAT_REG 0xF3 //Status Reg -#define BME280_CTRL_MEAS_REG 0xF4 //Ctrl Measure Reg -#define BME280_CONFIG_REG 0xF5 //Configuration Reg -#define BME280_PRESSURE_MSB_REG 0xF7 //Pressure MSB -#define BME280_PRESSURE_LSB_REG 0xF8 //Pressure LSB -#define BME280_PRESSURE_XLSB_REG 0xF9 //Pressure XLSB -#define BME280_TEMPERATURE_MSB_REG 0xFA //Temperature MSB -#define BME280_TEMPERATURE_LSB_REG 0xFB //Temperature LSB -#define BME280_TEMPERATURE_XLSB_REG 0xFC //Temperature XLSB -#define BME280_HUMIDITY_MSB_REG 0xFD //Humidity MSB -#define BME280_HUMIDITY_LSB_REG 0xFE //Humidity LSB - -//Class BME280_SensorSettings. This object is used to hold settings data. The application -//uses this classes' data directly. The settings are adopted and sent to the sensor -//at special times, such as .begin. Some are used for doing math. +// Register names: +#define BME280_DIG_T1_LSB_REG 0x88 +#define BME280_DIG_T1_MSB_REG 0x89 +#define BME280_DIG_T2_LSB_REG 0x8A +#define BME280_DIG_T2_MSB_REG 0x8B +#define BME280_DIG_T3_LSB_REG 0x8C +#define BME280_DIG_T3_MSB_REG 0x8D +#define BME280_DIG_P1_LSB_REG 0x8E +#define BME280_DIG_P1_MSB_REG 0x8F +#define BME280_DIG_P2_LSB_REG 0x90 +#define BME280_DIG_P2_MSB_REG 0x91 +#define BME280_DIG_P3_LSB_REG 0x92 +#define BME280_DIG_P3_MSB_REG 0x93 +#define BME280_DIG_P4_LSB_REG 0x94 +#define BME280_DIG_P4_MSB_REG 0x95 +#define BME280_DIG_P5_LSB_REG 0x96 +#define BME280_DIG_P5_MSB_REG 0x97 +#define BME280_DIG_P6_LSB_REG 0x98 +#define BME280_DIG_P6_MSB_REG 0x99 +#define BME280_DIG_P7_LSB_REG 0x9A +#define BME280_DIG_P7_MSB_REG 0x9B +#define BME280_DIG_P8_LSB_REG 0x9C +#define BME280_DIG_P8_MSB_REG 0x9D +#define BME280_DIG_P9_LSB_REG 0x9E +#define BME280_DIG_P9_MSB_REG 0x9F +#define BME280_DIG_H1_REG 0xA1 +#define BME280_CHIP_ID_REG 0xD0 // Chip ID +#define BME280_RST_REG 0xE0 // Softreset Reg +#define BME280_DIG_H2_LSB_REG 0xE1 +#define BME280_DIG_H2_MSB_REG 0xE2 +#define BME280_DIG_H3_REG 0xE3 +#define BME280_DIG_H4_MSB_REG 0xE4 +#define BME280_DIG_H4_LSB_REG 0xE5 +#define BME280_DIG_H5_MSB_REG 0xE6 +#define BME280_DIG_H6_REG 0xE7 +#define BME280_CTRL_HUMIDITY_REG 0xF2 // Ctrl Humidity Reg +#define BME280_STAT_REG 0xF3 // Status Reg +#define BME280_CTRL_MEAS_REG 0xF4 // Ctrl Measure Reg +#define BME280_CONFIG_REG 0xF5 // Configuration Reg +#define BME280_MEASUREMENTS_REG 0xF7 // Measurements register start +#define BME280_PRESSURE_MSB_REG 0xF7 // Pressure MSB +#define BME280_PRESSURE_LSB_REG 0xF8 // Pressure LSB +#define BME280_PRESSURE_XLSB_REG 0xF9 // Pressure XLSB +#define BME280_TEMPERATURE_MSB_REG 0xFA // Temperature MSB +#define BME280_TEMPERATURE_LSB_REG 0xFB // Temperature LSB +#define BME280_TEMPERATURE_XLSB_REG 0xFC // Temperature XLSB +#define BME280_HUMIDITY_MSB_REG 0xFD // Humidity MSB +#define BME280_HUMIDITY_LSB_REG 0xFE // Humidity LSB + +// Class BME280_SensorSettings. This object is used to hold settings data. The application +// uses this classes' data directly. The settings are adopted and sent to the sensor +// at special times, such as .begin. Some are used for doing math. // -//This is a kind of bloated way to do this. The trade-off is that the user doesn't -//need to deal with #defines or enums with bizarre names. +// This is a kind of bloated way to do this. The trade-off is that the user doesn't +// need to deal with #defines or enums with bizarre names. // -//A power user would strip out BME280_SensorSettings entirely, and send specific read and -//write command directly to the IC. (ST #defines below) +// A power user would strip out BME280_SensorSettings entirely, and send specific read and +// write command directly to the IC. (ST #defines below) // struct BME280_SensorSettings { public: - - //Main Interface and mode settings + // Main Interface and mode settings uint8_t commInterface; uint8_t I2CAddress; uint8_t chipSelectPin; - SPISettings spiSettings{BME280_SPI_CLOCK, MSBFIRST, BME280_SPI_MODE}; - - //Deprecated settings - uint8_t runMode; - uint8_t tStandby; - uint8_t filter; - uint8_t tempOverSample; - uint8_t pressOverSample; - uint8_t humidOverSample; + SPISettings spiSettings{BME280_SPI_CLOCK, MSBFIRST, BME280_SPI_MODE}; + + // Deprecated settings + uint8_t runMode; + uint8_t tStandby; + uint8_t filter; + uint8_t tempOverSample; + uint8_t pressOverSample; + uint8_t humidOverSample; float tempCorrection; // correction of temperature - added to the result }; -//Used to hold the calibration constants. These are used -//by the driver as measurements are being taking +// Used to hold the calibration constants. These are used +// by the driver as measurements are being taking struct SensorCalibration { public: - 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; - - uint8_t dig_H1; - int16_t dig_H2; - uint8_t dig_H3; - int16_t dig_H4; - int16_t dig_H5; - int8_t dig_H6; - + 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; + + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; }; -//This is the main operational class of the driver. +struct BME280_SensorMeasurements +{ + public: + float temperature; + float pressure; + float humidity; +}; + +// This is the main operational class of the driver. class BME280 { public: - //settings + // settings BME280_SensorSettings settings; - SensorCalibration calibration; - int32_t t_fine; - - //Constructor generates default BME280_SensorSettings. - //(over-ride after construction if desired) - BME280( void ); + SensorCalibration calibration; + int32_t t_fine; + + // Constructor generates default BME280_SensorSettings. + //(over-ride after construction if desired) + BME280(void); //~BME280() = default; - - //Call to apply BME280_SensorSettings. - //This also gets the SensorCalibration constants - uint8_t begin( void ); - bool beginSPI(uint8_t csPin); //Communicate using SPI - bool beginI2C(TwoWire &wirePort = Wire); //Called when user provides Wire port - - #ifdef SoftwareWire_h - bool beginI2C(SoftwareWire &wirePort); //Called when user provides a softwareWire port - #endif - - uint8_t getMode(void); //Get the current mode: sleep, forced, or normal - void setMode(uint8_t mode); //Set the current mode - - void setTempOverSample(uint8_t overSampleAmount); //Set the temperature sample mode - void setPressureOverSample(uint8_t overSampleAmount); //Set the pressure sample mode - void setHumidityOverSample(uint8_t overSampleAmount); //Set the humidity sample mode - void setStandbyTime(uint8_t timeSetting); //Set the standby time between measurements - void setFilter(uint8_t filterSetting); //Set the filter - - void setI2CAddress(uint8_t i2caddress); //Set the address the library should use to communicate. Use if address jumper is closed (0x76). - - void setReferencePressure(float refPressure); //Allows user to set local sea level reference pressure - float getReferencePressure(); - - bool isMeasuring(void); //Returns true while the device is taking measurement - - //Software reset routine - void reset( void ); - - //Returns the values as floats. - float readFloatPressure( void ); - float readFloatAltitudeMeters( void ); - float readFloatAltitudeFeet( void ); - - float readFloatHumidity( void ); - - //Temperature related methods - float readTempC( void ); - float readTempF( void ); - - //Dewpoint related methods - //From Pavel-Sayekat: https://github.com/sparkfun/SparkFun_BME280_Breakout_Board/pull/6/files + + // Call to apply BME280_SensorSettings. + // This also gets the SensorCalibration constants + uint8_t begin(void); + bool beginSPI(uint8_t csPin, SPIClass &spiPort = SPI); // Communicate using SPI + bool beginI2C(TwoWire &wirePort = Wire); // Called when user provides Wire port + +#ifdef SoftwareWire_h + bool beginI2C(SoftwareWire &wirePort); // Called when user provides a softwareWire port +#endif + + uint8_t getMode(void); // Get the current mode: sleep, forced, or normal + void setMode(uint8_t mode); // Set the current mode + + void setTempOverSample(uint8_t overSampleAmount); // Set the temperature sample mode + void setPressureOverSample(uint8_t overSampleAmount); // Set the pressure sample mode + void setHumidityOverSample(uint8_t overSampleAmount); // Set the humidity sample mode + void setStandbyTime(uint8_t timeSetting); // Set the standby time between measurements + void setFilter(uint8_t filterSetting); // Set the filter + + void setI2CAddress(uint8_t i2caddress); // Set the address the library should use to communicate. Use if address + // jumper is closed (0x76). + + void setReferencePressure(float refPressure); // Allows user to set local sea level reference pressure + float getReferencePressure(); + + bool isMeasuring(void); // Returns true while the device is taking measurement + + // Software reset routine + void reset(void); + void readAllMeasurements(BME280_SensorMeasurements *measurements, uint8_t tempScale = 0); + + // Returns the values as floats. + float readFloatPressure(void); + float readFloatAltitudeMeters(void); + float readFloatAltitudeFeet(void); + void readFloatPressureFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements); + + float readFloatHumidity(void); + void readFloatHumidityFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements); + + // Temperature related methods + void setTemperatureCorrection(float corr); + float readTempC(void); + float readTempF(void); + float readTempFromBurst(uint8_t buffer[]); + + // Dewpoint related methods + // From Pavel-Sayekat: https://github.com/sparkfun/SparkFun_BME280_Breakout_Board/pull/6/files double dewPointC(void); double dewPointF(void); - - //The following utilities read and write - //ReadRegisterRegion takes a uint8 array address as input and reads - //a chunk of memory into that array. - void readRegisterRegion(uint8_t*, uint8_t, uint8_t ); - //readRegister reads one register + // The following utilities read and write + + // ReadRegisterRegion takes a uint8 array address as input and reads + // a chunk of memory into that array. + void readRegisterRegion(uint8_t *, uint8_t, uint8_t); + // readRegister reads one register uint8_t readRegister(uint8_t); - //Reads two regs, LSByte then MSByte order, and concatenates them - //Used for two-byte reads - int16_t readRegisterInt16( uint8_t offset ); - //Writes a byte; + // Reads two regs, LSByte then MSByte order, and concatenates them + // Used for two-byte reads + int16_t readRegisterInt16(uint8_t offset); + // Writes a byte; void writeRegister(uint8_t, uint8_t); -private: - uint8_t checkSampleValue(uint8_t userValue); //Checks for valid over sample values - - uint8_t _wireType = HARD_WIRE; //Default to Wire.h - TwoWire *_hardPort = NO_WIRE; //The generic connection to user's chosen I2C hardware - - #ifdef SoftwareWire_h - SoftwareWire *_softPort = NO_WIRE; //Or, the generic connection to software wire port - #endif - - float _referencePressure = 101325.0; //Default but is changeable + private: + uint8_t checkSampleValue(uint8_t userValue); // Checks for valid over sample values + void readTempCFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements); + void readTempFFromBurst(uint8_t buffer[], BME280_SensorMeasurements *measurements); + + uint8_t _wireType = HARD_WIRE; // Default to Wire.h + TwoWire *_hardPort = NO_WIRE; // The generic connection to user's chosen I2C hardware + SPIClass *_spiPort = &SPI; // The generic connection to user's chosen SPI hardware + +#ifdef SoftwareWire_h + SoftwareWire *_softPort = NO_WIRE; // Or, the generic connection to software wire port +#endif + + float _referencePressure = 101325.0; // Default but is changeable }; -#endif // End of __BME280_H__ definition check \ No newline at end of file +#endif // End of __BME280_H__ definition check