├── README.md └── BME680_t3.ino /README.md: -------------------------------------------------------------------------------- 1 | # BME680 2 | 3 | Simple Teensy 3.X sketch that configures and initializes the sensors, reads the sensor data, and spews to the serial monitor scaled temperature, pressure, and humidity from Bosch's latest BME680 environmental sensor. I am getting resistance from the gas sensor in forced mode and so far everything is working as expected. I haven't got the gas sensor to work in sequential mode yet, and I have yet to interpret the measured resistance in terms of gas concentration. Still working on it... 4 | 5 | ![BME680](https://cloud.githubusercontent.com/assets/6698410/17267381/0170571a-55bc-11e6-982f-62df273703f8.jpg) 6 | 7 | -------------------------------------------------------------------------------- /BME680_t3.ino: -------------------------------------------------------------------------------- 1 | /* BME680 Basic Example Code 2 | by: Kris Winer 3 | date: June 20, 2016 4 | license: Beerware - Use this code however you'd like. If you 5 | find it useful you can buy me a beer some time. 6 | 7 | This sketch uses SDA/SCL on pins 16/17, respectively, and it uses the ESP8285. 8 | The BME680 is a simple but high resolution pressure/humidity/temperature sensor, which can be used in its high resolution 9 | mode but with power consumption of 20 microAmp, or in a lower resolution mode with power consumption of 10 | only 1 microAmp. The choice will depend on the application. 11 | 12 | SDA and SCL should have 4K7 pull-up resistors (to 3.3V). 13 | 14 | Hardware setup: 15 | SDA ----------------------- 17 16 | SCL ----------------------- 16 17 | 18 | */ 19 | #include "i2c_t3.h" 20 | 21 | // BME680 registers 22 | #define BME680_CALIB_DATA00 0x00 // eight bytes of device-specific calibration data 0x00 - 0x07 23 | #define BME680_FIELD_0_MEAS_STATUS_0 0x1D 24 | #define BME680_FIELD_0_MEAS_STATUS_1 0x1E 25 | #define BME680_FIELD_0_PRESS_MSB 0x1F 26 | #define BME680_FIELD_0_PRESS_LSB 0x20 27 | #define BME680_FIELD_0_PRESS_XLSB 0x21 28 | #define BME680_FIELD_0_TEMP_MSB 0x22 29 | #define BME680_FIELD_0_TEMP_LSB 0x23 30 | #define BME680_FIELD_0_TEMP_XLSB 0x24 31 | #define BME680_FIELD_0_HUM_MSB 0x25 32 | #define BME680_FIELD_0_HUM_LSB 0x26 33 | 34 | #define BME680_FIELD_0_GAS_RL_MSB 0x2A 35 | #define BME680_FIELD_0_GAS_RL_LSB 0x2B 36 | 37 | #define BME680_FIELD_1_MEAS_STATUS_0 0x2E 38 | #define BME680_FIELD_1_MEAS_STATUS_1 0x2F 39 | #define BME680_FIELD_1_PRESS_MSB 0x30 40 | #define BME680_FIELD_1_PRESS_LSB 0x31 41 | #define BME680_FIELD_1_PRESS_XLSB 0x32 42 | #define BME680_FIELD_1_TEMP_MSB 0x33 43 | #define BME680_FIELD_1_TEMP_LSB 0x34 44 | #define BME680_FIELD_1_TEMP_XLSB 0x35 45 | #define BME680_FIELD_1_HUM_MSB 0x36 46 | #define BME680_FIELD_1_HUM_LSB 0x37 47 | 48 | #define BME680_FIELD_2_GAS_RL_MSB 0x3B 49 | #define BME680_FIELD_2_GAS_RL_LSB 0x3C 50 | 51 | #define BME680_FIELD_2_MEAS_STATUS_0 0x3F 52 | #define BME680_FIELD_2_MEAS_STATUS_1 0x40 53 | #define BME680_FIELD_2_PRESS_MSB 0x41 54 | #define BME680_FIELD_2_PRESS_LSB 0x42 55 | #define BME680_FIELD_2_PRESS_XLSB 0x43 56 | #define BME680_FIELD_2_TEMP_MSB 0x44 57 | #define BME680_FIELD_2_TEMP_LSB 0x45 58 | #define BME680_FIELD_2_TEMP_XLSB 0x46 59 | #define BME680_FIELD_2_HUM_MSB 0x47 60 | #define BME680_FIELD_2_HUM_LSB 0x48 61 | 62 | #define BME680_FIELD_2_GAS_RL_MSB 0x4C 63 | #define BME680_FIELD_2_GAS_RL_LSB 0x4D 64 | 65 | #define BME680_IDAC_HEAT_X 0x50 // 10 IDAC byte values 0x50 - 0x59 66 | #define BME680_RES_HEAT_X 0x5A // 10 RES byte values 0x5A - 0x63 67 | #define BME680_GAS_WAIT_X 0x64 // 10 WAIT byte values 0x64 - 0x6D 68 | #define BME680_GAS_WAIT_SHARED 0x6E 69 | #define BME680_RES_HEAT_CTRL 0x6F 70 | #define BME680_CTRL_GAS_0 0x70 71 | #define BME680_CTRL_GAS_1 0x71 72 | #define BME680_CTRL_HUM 0x72 73 | #define BME680_STATUS 0x73 74 | #define BME680_CTRL_MEAS 0x74 75 | #define BME680_CONFIG 0x75 76 | #define BME680_CTRL_PROG 0x76 77 | 78 | #define BME680_CALIB_DATA_80 0x80 // more calibration data 0x80 - 0xA1 79 | 80 | #define BME680_ID 0xD0 //should return 0x61 81 | #define BME680_RESET 0xE0 82 | 83 | #define BME680_CALIB_DATA_E1 0xE1 // more calibration data 0xE1 - 0xF0 84 | 85 | #define BME680_CTRL_HUM 0xF2 86 | #define BME680_SPI_MEM_PAGE 0xF3 87 | 88 | #define BME680_CALIB_ADDR_1 0x89 // 25 bytes of calibration data for I2C 89 | #define BME680_CALIB_ADDR_2 0xE1 // 16 bytes of calibration data for I2C 90 | 91 | #define BME680_ADDRESS 0x76 // Address of BME680 altimeter when ADO = 0 (default) 92 | 93 | 94 | #define SerialDebug true // set to true to get Serial output for debugging 95 | #define myLed 13 96 | 97 | enum Posr { 98 | P_OSR_00 = 0, // no op 99 | P_OSR_01, 100 | P_OSR_02, 101 | P_OSR_04, 102 | P_OSR_08, 103 | P_OSR_16 104 | }; 105 | 106 | enum Hosr { 107 | H_OSR_00 = 0, // no op 108 | H_OSR_01, 109 | H_OSR_02, 110 | H_OSR_04, 111 | H_OSR_08, 112 | H_OSR_16 113 | }; 114 | 115 | enum Tosr { 116 | T_OSR_00 = 0, // no op 117 | T_OSR_01, 118 | T_OSR_02, 119 | T_OSR_04, 120 | T_OSR_08, 121 | T_OSR_16 122 | }; 123 | 124 | enum IIRFilter { 125 | full = 0, // bandwidth at full sample rate 126 | BW0_223ODR, 127 | BW0_092ODR, 128 | BW0_042ODR, 129 | BW0_021ODR // bandwidth at 0.021 x sample rate 130 | }; 131 | 132 | enum Mode { 133 | BME680Sleep = 0, 134 | Forced, 135 | Parallel, 136 | Sequential 137 | }; 138 | 139 | enum SBy { 140 | t_00_6ms = 0, 141 | t_62_5ms, 142 | t_125ms, 143 | t_250ms, 144 | t_500ms, 145 | t_1000ms, 146 | t_10ms, 147 | t_20ms, 148 | }; 149 | 150 | enum GWaitMult { 151 | gw_1xmult = 0, 152 | gw_4xmult, 153 | gw_16xmult, 154 | gw_64xmult 155 | }; 156 | 157 | // Specify BME680 configuration 158 | uint8_t Posr = P_OSR_16, Hosr = H_OSR_01, Tosr = T_OSR_02, Mode = Forced, IIRFilter = BW0_042ODR, SBy = t_10ms; // set pressure amd temperature output data rate 159 | // Gas sensor configuration 160 | uint8_t GWaitMult = gw_1xmult; // choose gas sensor wait time multiplier 161 | uint8_t numHeatPts = 0x01; // one heat set point 162 | // choose gas wait time in milliseconds x gas wait multiplier 0x00 | 0x59 == 100 ms gas wait time 163 | uint8_t gasWait[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // must choose at least one non-zero wait time 164 | uint8_t resHeat[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // must choose at least one non-zero wait time 165 | 166 | // Data arrays for conversion of raw gas measurements into resistance 167 | float const_array1[16] = {1, 1, 1, 1, 1, 0.99, 1, 0.992, 1, 1, 0.998, 0.995, 1, 0.99, 1, 1}; 168 | double const_array2[16] = {8000000.0, 4000000.0, 2000000.0, 1000000.0, 499500.4995, 248262.1648, 125000.0, 169 | 63004.03226, 31281.28128, 15625.0, 7812.5, 3906.25, 1953.125, 976.5625, 488.28125, 244.140625}; 170 | 171 | // t_fine carries fine temperature as global value for BME680 172 | int32_t t_fine; 173 | 174 | float Temperature, Pressure, Humidity; // stores BME680 pressures sensor pressure and temperature 175 | uint32_t rawPress, rawTemp; // pressure and temperature raw count output for BME680 176 | uint16_t rawHumidity, rawGasResistance; // variables to hold raw BME680 humidity and gas resistance values 177 | 178 | // BME680 compensation parameters 179 | uint8_t dig_P10, dig_H6; 180 | uint16_t dig_T1, dig_P1, dig_H1, dig_H2; 181 | int16_t dig_T2, dig_P2, dig_P4, dig_P5, dig_P8, dig_P9, dig_GH2; 182 | int8_t dig_T3, dig_P3, dig_P6, dig_P7, dig_H3, dig_H4, dig_H5, dig_H7, dig_GH1, dig_GH3; 183 | float temperature_C, temperature_F, pressure, humidity, altitude, resistance; // Scaled output of the BME680 184 | 185 | uint32_t delt_t = 0, count = 0, sumCount = 0, slpcnt = 0; // used to control display output rate 186 | 187 | uint8_t status0, status1, status2; 188 | 189 | void setup() 190 | { 191 | 192 | Serial.begin(115200); 193 | Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_400); 194 | delay(4000); 195 | 196 | pinMode(myLed, OUTPUT); 197 | 198 | I2Cscan(); // should detect BME680 at 0x76 199 | 200 | // Read the WHO_AM_I register of the BME680 this is a good test of communication 201 | byte f = readByte(BME680_ADDRESS, BME680_ID); // Read WHO_AM_I register for BME680 202 | Serial.print("BME680 "); 203 | Serial.print("I AM "); 204 | Serial.print(f, HEX); 205 | Serial.print(" I should be "); 206 | Serial.println(0x61, HEX); 207 | Serial.println(" "); 208 | 209 | delay(1000); 210 | 211 | if(f == 0x61) { 212 | 213 | writeByte(BME680_ADDRESS, BME680_RESET, 0xB6); // reset BME680 before initialization 214 | delay(100); 215 | 216 | BME680TPHInit(); // Initialize BME680 Temperature, Pressure, Humidity sensors 217 | Serial.println("Calibration coeficients:"); 218 | Serial.print("dig_T1 ="); 219 | Serial.println(dig_T1); 220 | Serial.print("dig_T2 ="); 221 | Serial.println(dig_T2); 222 | Serial.print("dig_T3 ="); 223 | Serial.println(dig_T3); 224 | Serial.print("dig_P1 ="); 225 | Serial.println(dig_P1); 226 | Serial.print("dig_P2 ="); 227 | Serial.println(dig_P2); 228 | Serial.print("dig_P3 ="); 229 | Serial.println(dig_P3); 230 | Serial.print("dig_P4 ="); 231 | Serial.println(dig_P4); 232 | Serial.print("dig_P5 ="); 233 | Serial.println(dig_P5); 234 | Serial.print("dig_P6 ="); 235 | Serial.println(dig_P6); 236 | Serial.print("dig_P7 ="); 237 | Serial.println(dig_P7); 238 | Serial.print("dig_P8 ="); 239 | Serial.println(dig_P8); 240 | Serial.print("dig_P9 ="); 241 | Serial.println(dig_P9); 242 | Serial.print("dig_P10 ="); 243 | Serial.println(dig_P10); 244 | Serial.print("dig_H1 ="); 245 | Serial.println(dig_H1); 246 | Serial.print("dig_H2 ="); 247 | Serial.println(dig_H2); 248 | Serial.print("dig_H3 ="); 249 | Serial.println(dig_H3); 250 | Serial.print("dig_H4 ="); 251 | Serial.println(dig_H4); 252 | Serial.print("dig_H5 ="); 253 | Serial.println(dig_H5); 254 | Serial.print("dig_H6 ="); 255 | Serial.println(dig_H6); 256 | Serial.print("dig_H7 ="); 257 | Serial.println(dig_H7); 258 | Serial.print("dig_GH1 ="); 259 | Serial.println(dig_GH1); 260 | Serial.print("dig_GH2 ="); 261 | Serial.println(dig_GH2); 262 | Serial.print("dig_GH3 ="); 263 | Serial.println(dig_GH3); 264 | 265 | // Configure the gas sensor 266 | gasWait[0] = GWaitMult | 0x59; // define gas wait time for heat set point 0x59 == 100 ms 267 | Serial.print("gas wait time = 0x"); Serial.println(gasWait[0], HEX); 268 | resHeat[0] = BME680_TT(200); // define temperature set point in degrees Celsius for resistance set point 0 269 | Serial.print("resistance Heat = "); Serial.println(resHeat[0]); 270 | BME680GasInit(); 271 | 272 | } 273 | else Serial.println(" BME680 not functioning!"); 274 | 275 | delay(1000); 276 | } 277 | 278 | 279 | void loop() 280 | { 281 | // Serial print and/or display at 0.5 s rate independent of data rates 282 | delt_t = millis() - count; 283 | if (delt_t > 1000) { // update LCD once per second independent of read rate 284 | 285 | // Check status registers 286 | status0 = readByte(BME680_ADDRESS, BME680_FIELD_0_MEAS_STATUS_0); 287 | if(status0 & 0x80) Serial.println("New data in field 0!"); 288 | if(status0 & 0x40) Serial.println("Measuring field 0 gas data!"); 289 | if(status0 & 0x20) Serial.println("Conversion in progress!"); 290 | Serial.print("Gas measurement Index = "); Serial.println(status0 & 0x0F); 291 | 292 | writeByte(BME680_ADDRESS, BME680_CTRL_MEAS, Tosr << 5 | Posr << 2 | Mode); 293 | rawTemp = readBME680Temperature(); 294 | temperature_C = (float) BME680_compensate_T(rawTemp)/100.; 295 | rawPress = readBME680Pressure(); 296 | pressure = (float) BME680_compensate_P(rawPress)/100.; // Pressure in mbar 297 | rawHumidity = readBME680Humidity(); 298 | humidity = (float) BME680_compensate_H(rawHumidity)/1024.; 299 | rawGasResistance = readBME680GasResistance(); 300 | resistance = (float) BME680_compensate_Gas(rawGasResistance); 301 | 302 | Serial.println("BME680:"); 303 | Serial.print("Altimeter temperature = "); 304 | Serial.print( temperature_C, 2); 305 | Serial.println(" C"); // temperature in degrees Celsius 306 | Serial.print("Altimeter temperature = "); 307 | Serial.print(9.*temperature_C/5. + 32., 2); 308 | Serial.println(" F"); // temperature in degrees Fahrenheit 309 | Serial.print("Altimeter pressure = "); 310 | Serial.print(pressure, 2); 311 | Serial.println(" mbar");// pressure in millibar 312 | altitude = 145366.45f*(1.0f - powf((pressure/1013.25f), 0.190284f)); 313 | Serial.print("Altitude = "); 314 | Serial.print(altitude, 2); 315 | Serial.println(" feet"); 316 | Serial.print("Altimeter humidity = "); 317 | Serial.print(humidity, 1); 318 | Serial.println(" %rH");// relative humidity 319 | Serial.print("Gas Sensor raw resistance = "); 320 | Serial.print(rawGasResistance); 321 | Serial.println(" "); 322 | Serial.print("Gas Sensor resistance = "); 323 | Serial.print(resistance, 1); 324 | Serial.println(" Ohm");// gas sensor resistance in Ohm 325 | Serial.println(" "); 326 | 327 | digitalWrite(myLed, !digitalRead(myLed)); 328 | count = millis(); 329 | } 330 | 331 | } 332 | 333 | //=================================================================================================================== 334 | //====== Set of useful function to access acceleration. gyroscope, magnetometer, and temperature data 335 | //=================================================================================================================== 336 | 337 | uint32_t readBME680Temperature() 338 | { 339 | uint8_t rawData[3]; // 20-bit pressure register data stored here 340 | readBytes(BME680_ADDRESS, BME680_FIELD_0_TEMP_MSB, 3, &rawData[0]); 341 | return (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4); 342 | } 343 | 344 | uint32_t readBME680Pressure() 345 | { 346 | uint8_t rawData[3]; // 20-bit pressure register data stored here 347 | readBytes(BME680_ADDRESS, BME680_FIELD_0_PRESS_MSB, 3, &rawData[0]); 348 | return (uint32_t) (((uint32_t) rawData[0] << 16 | (uint32_t) rawData[1] << 8 | rawData[2]) >> 4); 349 | } 350 | 351 | uint16_t readBME680Humidity() 352 | { 353 | uint8_t rawData[3]; // 20-bit pressure register data stored here 354 | readBytes(BME680_ADDRESS, BME680_FIELD_0_HUM_MSB, 2, &rawData[0]); 355 | return (uint16_t) (((uint16_t) rawData[0] << 8 | rawData[1]) ); 356 | } 357 | 358 | uint16_t readBME680GasResistance() 359 | { 360 | uint8_t rawData[2]; // 10-bit gas resistance register data stored here 361 | readBytes(BME680_ADDRESS, BME680_FIELD_0_GAS_RL_MSB, 2, &rawData[0]); 362 | if(rawData[1] & 0x20) Serial.println("Field 0 gas data valid"); 363 | return (uint16_t) (((uint16_t) rawData[0] << 2 | (0xC0 & rawData[1]) >> 6) ); 364 | 365 | } 366 | 367 | 368 | void BME680TPHInit() 369 | { 370 | // Configure the BME680 Temperature, Pressure, Humidity sensors 371 | // Set H oversampling rate 372 | writeByte(BME680_ADDRESS, BME680_CTRL_HUM, 0x07 & Hosr); 373 | // Set T and P oversampling rates and sensor mode 374 | writeByte(BME680_ADDRESS, BME680_CTRL_MEAS, Tosr << 5 | Posr << 2 | Mode); 375 | // Set standby time interval in normal mode and bandwidth 376 | writeByte(BME680_ADDRESS, BME680_CONFIG, SBy << 5 | IIRFilter << 2); 377 | 378 | // Read and store calibration data 379 | uint8_t calib[41] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 380 | readBytes(BME680_ADDRESS, BME680_CALIB_ADDR_1, 25, &calib[0]); 381 | readBytes(BME680_ADDRESS, BME680_CALIB_ADDR_2, 16, &calib[25]); 382 | // temperature compensation parameters 383 | dig_T1 = (uint16_t)(((uint16_t) calib[34] << 8) | calib[33]); 384 | dig_T2 = ( int16_t)((( int16_t) calib[2] << 8) | calib[1]); 385 | dig_T3 = ( int8_t) (calib[3]); 386 | // pressure compensation parameters 387 | dig_P1 = (uint16_t)(((uint16_t) calib[6] << 8) | calib[5]); 388 | dig_P2 = ( int16_t)((( int16_t) calib[8] << 8) | calib[7]); 389 | dig_P3 = ( int8_t) (calib[9]); 390 | dig_P4 = ( int16_t)((( int16_t) calib[12] << 8) | calib[11]); 391 | dig_P5 = ( int16_t)((( int16_t) calib[14] << 8) | calib[13]); 392 | dig_P6 = ( int8_t) (calib[16]); 393 | dig_P7 = ( int8_t) (calib[15]); 394 | dig_P8 = ( int16_t)((( int16_t) calib[20] << 8) | calib[19]); 395 | dig_P9 = ( int16_t)((( int16_t) calib[22] << 8) | calib[21]); 396 | dig_P10 = (uint8_t) (calib[23]); 397 | // humidity compensation parameters 398 | dig_H1 = (uint16_t)(((uint16_t) calib[27] << 4) | (calib[26] & 0x0F)); 399 | dig_H2 = (uint16_t)(((uint16_t) calib[25] << 4) | (calib[26] >> 4)); 400 | dig_H3 = (int8_t) calib[28]; 401 | dig_H4 = (int8_t) calib[29]; 402 | dig_H5 = (int8_t) calib[30]; 403 | dig_H6 = (uint8_t) calib[31]; 404 | dig_H7 = (int8_t) calib[32]; 405 | // gas sensor compensation parameters 406 | dig_GH1 = (int8_t) calib[37]; 407 | dig_GH2 = ( int16_t)((( int16_t) calib[36] << 8) | calib[35]); 408 | dig_GH3 = (int8_t) calib[38]; 409 | } 410 | 411 | void BME680GasInit() // Initialize BME680 gas sensor 412 | { 413 | // Configure the BME680 Gas Sensor 414 | writeByte(BME680_ADDRESS, BME680_CTRL_GAS_1, 0x10 | numHeatPts - 1); // write number of heater set points 415 | // Set gas sampling wait time and target heater resistance 416 | for(uint8_t ii = 0; ii < numHeatPts; ii++) 417 | { 418 | writeByte(BME680_ADDRESS, (BME680_GAS_WAIT_X + ii), gasWait[ii]); 419 | writeByte(BME680_ADDRESS, (BME680_RES_HEAT_X + ii), resHeat[ii]); 420 | } 421 | Serial.print("CTRL_GAS_1 = 0x"); Serial.println(readByte(BME680_ADDRESS, BME680_CTRL_GAS_1), HEX); 422 | Serial.print("gas wait = 0x"); Serial.println(readByte(BME680_ADDRESS, BME680_GAS_WAIT_X), HEX); 423 | Serial.print("res heat = 0x"); Serial.println(readByte(BME680_ADDRESS, BME680_RES_HEAT_X)); 424 | } 425 | 426 | // Returns register code to be written to register BME680_RES_HEAT_CTRL for a user specified target temperature TT 427 | // where TT is the target temperature in degrees Celsius 428 | uint8_t BME680_TT(uint16_t TT) // TT is between 200 and 400 429 | { 430 | uint8_t res_heat_x = 0; 431 | double var1 = 0.0, var2 = 0.0, var3 = 0.0, var4 = 0.0, var5 = 0.0; 432 | uint16_t par_g1 = ((uint16_t) readByte(BME680_ADDRESS, 0xEC) << 8) | readByte(BME680_ADDRESS, 0xEB); 433 | uint8_t par_g2 = readByte(BME680_ADDRESS, 0xED); 434 | uint8_t par_g3 = readByte(BME680_ADDRESS, 0xEE); 435 | uint8_t res_heat_range = (readByte(BME680_ADDRESS, 0x02) & 0x30) >> 4; 436 | uint8_t res_heat_val = readByte(BME680_ADDRESS, 0x00); 437 | var1 = ((double) par_g1/ 16.0) + 49.0; 438 | var2 = (((double)par_g2 / 32768.0) * 0.0005) + 0.00235; 439 | var3 = (double)par_g3 / 1024.0; 440 | var4 = var1 * (1.0 + (var2 * (double)TT)); 441 | var5 = var4 + (var3 * 25.0); // use 25 C as ambient temperature 442 | res_heat_x = (uint8_t)(((var5 * (4.0/(4.0 * (double)res_heat_range))) - 25.0) * 3.4 / ((res_heat_val * 0.002) + 1)); 443 | return res_heat_x; 444 | } 445 | 446 | 447 | // Compensate Raw Gas ADC values to obtain resistance 448 | float BME680_compensate_Gas(uint16_t gas_adc) 449 | { 450 | uint8_t gasRange = readByte(BME680_ADDRESS, BME680_FIELD_0_GAS_RL_LSB) & 0x0F; 451 | Serial.print("gas range = "); Serial.println(gasRange); 452 | double var1 = 0, gas_switch_error = 1.0; 453 | var1 = (1340.0 + 5.0 * gas_switch_error) * const_array1[gasRange]; 454 | float gas_res = var1 * const_array2[gasRange] / (gas_adc - 512.0 + var1); 455 | return gas_res; 456 | } 457 | 458 | // Returns temperature in DegC, resolution is 0.01 DegC. Output value of 459 | // “5123” equals 51.23 DegC. 460 | int32_t BME680_compensate_T(uint32_t adc_T) 461 | { 462 | int32_t var1 = 0, var2 = 0, var3 = 0, T = 0; 463 | var1 = ((int32_t) adc_T >> 3) - ((int32_t)dig_T1 << 1); 464 | var2 = (var1 * (int32_t)dig_T2) >> 11; 465 | var3 = ((((var1 >> 1) * (var1 >> 1)) >> 12) * ((int32_t) dig_T3 << 4)) >> 14; 466 | t_fine = var2 + var3; 467 | T = (t_fine * 5 + 128) >> 8; 468 | return T; 469 | } 470 | 471 | // Returns the value in Pascal(Pa) 472 | // Output value of "96386" equals 96386 Pa = 473 | // 963.86 hPa = 963.86 millibar 474 | int32_t BME680_compensate_P(uint32_t adc_P) 475 | { 476 | int32_t var1 = 0, var2 = 0, var3 = 0, var4 = 0, P = 0; 477 | var1 = (((int32_t) t_fine) >> 1) - 64000; 478 | var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * (int32_t) dig_P6) >> 2; 479 | var2 = var2 + ((var1 * (int32_t)dig_P5) << 1); 480 | var2 = (var2 >> 2) + ((int32_t) dig_P4 << 16); 481 | var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * ((int32_t) dig_P3 << 5)) >> 3) + (((int32_t) dig_P2 * var1) >> 1); 482 | var1 = var1 >> 18; 483 | var1 = ((32768 + var1) * (int32_t) dig_P1) >> 15; 484 | P = 1048576 - adc_P; 485 | P = (int32_t)((P - (var2 >> 12)) * ((uint32_t)3125)); 486 | var4 = (1 << 31); 487 | 488 | if(P >= var4) 489 | P = (( P / (uint32_t) var1) << 1); 490 | else 491 | P = ((P << 1) / (uint32_t) var1); 492 | 493 | var1 = ((int32_t) dig_P9 * (int32_t) (((P >> 3) * (P >> 3)) >> 13)) >> 12; 494 | var2 = ((int32_t)(P >> 2) * (int32_t) dig_P8) >> 13; 495 | var3 = ((int32_t)(P >> 8) * (int32_t)(P >> 8) * (int32_t)(P >> 8) * (int32_t)dig_P10) >> 17; 496 | P = (int32_t)(P) + ((var1 + var2 + var3 + ((int32_t)dig_P7 << 7)) >> 4); 497 | 498 | return P; 499 | } 500 | 501 | // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22integer and 10fractional bits). 502 | // Output value of “47445”represents 47445/1024 = 46.333%RH 503 | int32_t BME680_compensate_H(uint32_t adc_H) 504 | { 505 | int32_t var1 = 0, var2 = 0, var3 = 0, var4 = 0, var5 = 0, var6 = 0, H = 0, T = 0; 506 | 507 | T = (((int32_t) t_fine * 5) + 128) >> 8; 508 | var1 = (int32_t) adc_H - ((int32_t) ((int32_t)dig_H1 << 4)) - (((T * (int32_t) dig_H3) / ((int32_t)100)) >> 1); 509 | var2 = ((int32_t)dig_H2 * (((T * (int32_t)dig_H4) / 510 | ((int32_t)100)) + (((T * ((T * (int32_t)dig_H5) / 511 | ((int32_t)100))) >> 6) / ((int32_t)100)) + (int32_t)(1 << 14))) >> 10; 512 | var3 = var1 * var2; 513 | var4 = ((((int32_t)dig_H6) << 7) + ((T * (int32_t) dig_H7) / ((int32_t)100))) >> 4; 514 | var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; 515 | var6 = (var4 * var5) >> 1; 516 | 517 | H = (var3 + var6) >> 12; 518 | 519 | if (H > 102400) H = 102400; // check for over- and under-flow 520 | else if(H < 0) H = 0; 521 | 522 | return H; 523 | } 524 | 525 | // simple function to scan for I2C devices on the bus 526 | void I2Cscan() 527 | { 528 | // scan for i2c devices 529 | byte error, address; 530 | int nDevices; 531 | 532 | Serial.println("Scanning..."); 533 | 534 | nDevices = 0; 535 | for(address = 1; address < 127; address++ ) 536 | { 537 | // The i2c_scanner uses the return value of 538 | // the Write.endTransmisstion to see if 539 | // a device did acknowledge to the address. 540 | Wire.beginTransmission(address); 541 | error = Wire.endTransmission(); 542 | 543 | if (error == 0) 544 | { 545 | Serial.print("I2C device found at address 0x"); 546 | if (address<16) 547 | Serial.print("0"); 548 | Serial.print(address,HEX); 549 | Serial.println(" !"); 550 | 551 | nDevices++; 552 | } 553 | else if (error==4) 554 | { 555 | Serial.print("Unknown error at address 0x"); 556 | if (address<16) 557 | Serial.print("0"); 558 | Serial.println(address,HEX); 559 | } 560 | } 561 | if (nDevices == 0) 562 | Serial.println("No I2C devices found\n"); 563 | else 564 | Serial.println("done\n"); 565 | } 566 | 567 | 568 | // I2C read/write functions for the BMP280 sensors 569 | 570 | void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) 571 | { 572 | Wire.beginTransmission(address); // Initialize the Tx buffer 573 | Wire.write(subAddress); // Put slave register address in Tx buffer 574 | Wire.write(data); // Put data in Tx buffer 575 | Wire.endTransmission(); // Send the Tx buffer 576 | } 577 | 578 | uint8_t readByte(uint8_t address, uint8_t subAddress) 579 | { 580 | uint8_t data; // `data` will store the register data 581 | Wire.beginTransmission(address); // Initialize the Tx buffer 582 | Wire.write(subAddress); // Put slave register address in Tx buffer 583 | Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive 584 | // Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive 585 | Wire.requestFrom(address, 1); // Read one byte from slave register address 586 | // Wire.requestFrom(address, (size_t) 1); // Read one byte from slave register address 587 | data = Wire.read(); // Fill Rx buffer with result 588 | return data; // Return data read from slave register 589 | } 590 | 591 | void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) 592 | { 593 | Wire.beginTransmission(address); // Initialize the Tx buffer 594 | Wire.write(subAddress); // Put slave register address in Tx buffer 595 | Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive 596 | // Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive 597 | uint8_t i = 0; 598 | // Wire.requestFrom(address, count); // Read bytes from slave register address 599 | Wire.requestFrom(address, (size_t) count); // Read bytes from slave register address 600 | while (Wire.available()) { 601 | dest[i++] = Wire.read(); } // Put read results in the Rx buffer 602 | } 603 | --------------------------------------------------------------------------------