BME680  v1.0.12
Arduino Library for Bosch BME680 Temperature, Humidity, and Pressure
Zanshin_BME680.h
Go to the documentation of this file.
1 // clang-format off
103 // clang-format on
104 #include <SPI.h> // Standard SPI library
105 #include <Wire.h> // Standard I2C "Wire" library
106 
107 #include "Arduino.h" // Arduino data type definitions
108 
109 #ifndef BME680_h
110  #define BME680_h
111  #define CONCAT_BYTES(msb, lsb) \
112  (((uint16_t)msb << 8) | (uint16_t)lsb)
113  #ifndef _BV
114  #define _BV(bit) (1 << (bit))
115  #endif
116  /***************************************************************************************************
117  ** Declare publically visible constants used in the class **
118  ***************************************************************************************************/
119  #ifndef I2C_MODES // If the I2C_Modes haven't been declared yet
120  #define I2C_MODES
121 const uint32_t I2C_STANDARD_MODE{100000};
122 const uint32_t I2C_FAST_MODE{400000};
123 const uint32_t I2C_FAST_MODE_PLUS{1000000};
124 const uint32_t I2C_HIGH_SPEED_MODE{3400000};
125  #endif
126 const uint32_t SPI_HERZ{500000};
128 /***************************************************************************************************
129 ** Declare enumerated types used in the class **
130 ***************************************************************************************************/
132 enum sensorTypes { TemperatureSensor, HumiditySensor, PressureSensor, GasSensor, UnknownSensor };
134 enum oversamplingTypes {
135  SensorOff,
136  Oversample1,
137  Oversample2,
138  Oversample4,
139  Oversample8,
140  Oversample16,
141  UnknownOversample
142 };
144 enum iirFilterTypes { IIROff, IIR2, IIR4, IIR8, IIR16, IIR32, IIR64, IIR128, UnknownIIR };
146 class BME680_Class {
151  public:
152  BME680_Class(); // Class constructor (unused)
153  ~BME680_Class(); // Class destructor (unused)
154  bool begin(); // Start using I2C Communications
155  bool begin(const uint32_t i2cSpeed); // I2C with a non-default speed
156  bool begin(const uint8_t chipSelect); // Start using either I2C or HW-SPI
157  bool begin(const uint32_t i2cSpeed, const uint8_t i2cAddress); // Set speed and I2C Addr.
158  bool begin(const uint8_t chipSelect, const uint8_t mosi, // Start using software SPI
159  const uint8_t miso, const uint8_t sck);
160  uint8_t setOversampling(const uint8_t sensor, // Set enum sensorType Oversampling
161  const uint8_t sampling = UINT8_MAX) const; // and return current value
162  bool setGas(uint16_t GasTemp, uint16_t GasMillis) const; // Gas heating temperature and time
163  uint8_t setIIRFilter(const uint8_t iirFilterSetting = UINT8_MAX) const; // Set IIR Filter
164  uint8_t getSensorData(int32_t &temp, int32_t &hum, // get most recent readings
165  int32_t &press, int32_t &gas, //
166  const bool waitSwitch = true); //
167  uint8_t getI2CAddress() const; // Return the I2C Address of the BME680
168  void reset(); // Reset the BME680
169  bool measuring() const;
170  void triggerMeasurement() const;
171  private: //
172  bool commonInitialization();
173  uint8_t readByte(const uint8_t addr) const;
174  uint8_t readSensors(const bool waitSwitch);
175  void waitForReadings() const;
176  void getCalibration();
177  uint8_t _I2CAddress = 0;
178  uint16_t _I2CSpeed = 0;
179  uint8_t _cs, _sck, _mosi, _miso;
180  uint8_t _H6, _P10, _res_heat_range;
181  int8_t _H3, _H4, _H5, _H7, _G1, _G3, _T3, _P3, _P6, _P7, _res_heat,
182  _rng_sw_err;
183  uint16_t _H1, _H2, _T1, _P1;
184  int16_t _G2, _T2, _P2, _P4, _P5, _P8, _P9;
185  int32_t _tfine, _Temperature, _Pressure, _Humidity, _Gas;
186 
200  template <typename T>
201  uint8_t &getData(const uint8_t addr, T &value) const {
209  uint8_t * bytePtr = (uint8_t *)&value; // Pointer to structure beginning
210  static uint8_t structSize = sizeof(T); // Number of bytes in structure
211  if (_I2CAddress) // Using I2C if address is non-zero
212  { //
213  Wire.beginTransmission(_I2CAddress); // Address the I2C device
214  Wire.write(addr); // Send register address to read
215  Wire.endTransmission(); // Close transmission
216  Wire.requestFrom(_I2CAddress, sizeof(T)); // Request 1 byte of data
217  structSize = Wire.available(); // Use the actual number of bytes
218  for (uint8_t i = 0; i < structSize; i++)
219  *bytePtr++ = Wire.read(); // loop for each byte to be read
220  } //
221  else //
222  { //
223  if (_sck == 0) // if sck is zero then hardware SPI
224  { //
225  SPI.beginTransaction(
226  SPISettings(SPI_HERZ, MSBFIRST, SPI_MODE0)); // Start the SPI transaction
227  digitalWrite(_cs, LOW); // Tell BME680 to listen up
228  SPI.transfer(addr | 0x80); // bit 7 is high, so read a byte
229  for (uint8_t i = 0; i < structSize; i++)
230  *bytePtr++ = SPI.transfer(0); // loop for each byte to be read
231  digitalWrite(_cs, HIGH); // Tell BME680 to stop listening
232  SPI.endTransaction(); // End the transaction
233  } else { // otherwise we are using soft SPI
234  int8_t i, j; // Loop variables
235  uint8_t reply; // return byte for soft SPI transfer
236  digitalWrite(_cs, LOW); // Tell BME680 to listen up
237  for (j = 7; j >= 0; j--) // First send the address byte
238  {
239  digitalWrite(_sck, LOW); // set the clock signal
240  digitalWrite(_mosi, ((addr) | 0x80) & (1 << j)); // set the MOSI pin state
241  digitalWrite(_sck, HIGH); // reset the clock signal
242  } // of for-next each bit
243  for (i = 0; i < structSize; i++) // Loop for each byte to read
244  { //
245  reply = 0; // reset our return byte
246  for (j = 7; j >= 0; j--) // Now read the data at that byte
247  { //
248  reply <<= 1; // shift buffer one bit left
249  digitalWrite(_sck, LOW); // set and reset the clock signal
250  digitalWrite(_sck, HIGH); // pin to get the next MISO bit
251  if (digitalRead(_miso)) reply |= 1; // read the MISO bit, add to reply
252  } // of for-next each bit
253  *bytePtr++ = reply; // Add byte just read to return data
254  } // of for-next each byte to be read
255  digitalWrite(_cs, HIGH); // Tell BME680 to stop listening
256  } // of if-then-else we are using hardware SPI
257  } // of if-then-else we are using I2C
258  return (structSize);
259  } // of method getData()
260  template <typename T>
261  uint8_t &putData(const uint8_t addr, const T &value) const {
269  const uint8_t *bytePtr = (const uint8_t *)&value; // Pointer to structure beginning
270  static uint8_t structSize = sizeof(T); // Number of bytes in structure
271  if (_I2CAddress) // Using I2C if address is non-zero
272  { //
273  Wire.beginTransmission(_I2CAddress); // Address the I2C device
274  Wire.write(addr); // Send register address to write
275  for (uint8_t i = 0; i < sizeof(T); i++)
276  Wire.write(*bytePtr++); // loop for each byte to be written
277  Wire.endTransmission(); // Close transmission
278  } else {
279  if (_sck == 0) // if sck is zero then hardware SPI
280  {
281  SPI.beginTransaction(
282  SPISettings(SPI_HERZ, MSBFIRST, SPI_MODE0)); // start the SPI transaction
283  digitalWrite(_cs, LOW); // Tell BME680 to listen up
284  SPI.transfer(addr & ~0x80); // bit 7 is low, so write a byte
285  for (uint8_t i = 0; i < structSize; i++) {
286  SPI.transfer(*bytePtr++);
287  } // loop for each byte to be written
288  digitalWrite(_cs, HIGH); // Tell BME680 to stop listening
289  SPI.endTransaction(); // End the transaction
290  } else // Otherwise soft SPI is used
291  {
292  int8_t i, j; // Loop variables
293  uint8_t reply; // return byte for soft SPI transfer
294  for (i = 0; i < structSize; i++) // Loop for each byte to read
295  {
296  reply = 0; // reset our return byte
297  digitalWrite(_cs, LOW); // Tell BME680 to listen up
298  for (j = 7; j >= 0; j--) // First send the address byte
299  {
300  digitalWrite(_sck, LOW); // set the clock signal
301  digitalWrite(_mosi, (addr & ~0x80) & (1 << j)); // set the MOSI pin state
302  digitalWrite(_sck, HIGH); // reset the clock signal
303  } // of for-next each bit
304  for (j = 7; j >= 0; j--) // Now read the data at that byte
305  {
306  reply <<= 1; // shift buffer one bit left
307  digitalWrite(_sck, LOW); // set the clock signal
308  digitalWrite(_mosi, *bytePtr & (1 << j)); // set the MOSI pin state
309  digitalWrite(_sck, HIGH); // reset the clock signal
310  } // of for-next each bit
311  digitalWrite(_cs, HIGH); // Tell BME680 to stop listening
312  bytePtr++; // go to next byte to write
313  } // of for-next each byte to be read
314  } // of if-then-else we are using hardware SPI
315  } // of if-then-else we are using I2C
316  return (structSize);
317  } // of method putData()
318 }; // of BME680 class definition
319 #endif
bool begin()
Definition: Zanshin_BME680.cpp:97
iirFilterTypes
Enumerate the iir filter types.
Definition: Zanshin_BME680.h:145
uint8_t setIIRFilter(const uint8_t iirFilterSetting=UINT8_MAX) const
Definition: Zanshin_BME680.cpp:360
bool measuring() const
true if currently measuring
Definition: Zanshin_BME680.cpp:560
sensorTypes
Enumerate the sensor type.
Definition: Zanshin_BME680.h:133
uint8_t setOversampling(const uint8_t sensor, const uint8_t sampling=UINT8_MAX) const
Definition: Zanshin_BME680.cpp:298
uint8_t getI2CAddress() const
Definition: Zanshin_BME680.cpp:396
~BME680_Class()
Definition: Zanshin_BME680.cpp:88
void reset()
Definition: Zanshin_BME680.cpp:221
oversamplingTypes
Enumerate the Oversampling types.
Definition: Zanshin_BME680.h:135
void triggerMeasurement() const
trigger a measurement
Definition: Zanshin_BME680.cpp:571
int32_t gas
BME680 gas resistance value.
Definition: ESP32FeatherWiFiDemo.ino:115
BME680_Class()
Definition: Zanshin_BME680.cpp:82
Main BME680 class for the temperature / humidity / pressure sensor.
Definition: Zanshin_BME680.h:147
uint8_t getSensorData(int32_t &temp, int32_t &hum, int32_t &press, int32_t &gas, const bool waitSwitch=true)
Definition: Zanshin_BME680.cpp:379
const uint32_t SPI_HERZ
SPI speed in Hz.
Definition: Zanshin_BME680.h:127
bool setGas(uint16_t GasTemp, uint16_t GasMillis) const
Definition: Zanshin_BME680.cpp:512