Clemens Valens
/
bme280
Driver for Bosch Sensortec BME280 combined humidity and pressure sensor
Embed:
(wiki syntax)
Show/hide line numbers
bme280.cpp
00001 /* 00002 bme280.cpp - driver for Bosch Sensortec BME280 combined humidity and pressure sensor. 00003 00004 Copyright (c) 2015 Elektor 00005 00006 26/11/2015 - CPV, Initial release. 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Lesser General Public 00010 License as published by the Free Software Foundation; either 00011 version 2.1 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Lesser General Public License for more details. 00017 00018 You should have received a copy of the GNU Lesser General 00019 Public License along with this library; if not, write to the 00020 Free Software Foundation, Inc., 59 Temple Place, Suite 330, 00021 Boston, MA 02111-1307 USA 00022 00023 */ 00024 00025 #include "bme280.h" 00026 00027 00028 BME280::BME280(void) 00029 { 00030 _i2c_address = 0; 00031 _t_fine = 0; 00032 _temperature = 0; 00033 _pressure = 0; 00034 _humidity = 0; 00035 clearCalibrationData(); 00036 } 00037 00038 00039 void BME280::clearCalibrationData(void) 00040 { 00041 _dig_T1 = 0; 00042 _dig_T2 = 0; 00043 _dig_T3 = 0; 00044 _dig_P1 = 0; 00045 _dig_P2 = 0; 00046 _dig_P3 = 0; 00047 _dig_P4 = 0; 00048 _dig_P5 = 0; 00049 _dig_P6 = 0; 00050 _dig_P7 = 0; 00051 _dig_P8 = 0; 00052 _dig_P9 = 0; 00053 _dig_H1 = 0; 00054 _dig_H2 = 0; 00055 _dig_H3 = 0; 00056 _dig_H4 = 0; 00057 _dig_H5 = 0; 00058 _dig_H6 = 0; 00059 } 00060 00061 00062 uint8_t BME280::begin(uint8_t i2cAddress) 00063 { 00064 _i2c_address = i2cAddress; 00065 if (readId()==BME280_ID) 00066 { 00067 clearCalibrationData(); 00068 readCalibrationData(); 00069 return 0; 00070 } 00071 return (uint8_t)-1; 00072 } 00073 00074 00075 void BME280::busWrite(uint8_t *p_data, uint8_t data_size, uint8_t repeated_start) 00076 { 00077 if (_i2c_address==BME280_I2C_ADDRESS1 || _i2c_address==BME280_I2C_ADDRESS2) 00078 { 00079 // Assume I2C bus. 00080 i2cWrite(_i2c_address,p_data,data_size,repeated_start); 00081 } 00082 else 00083 { 00084 // Assume SPI bus. 00085 // First byte is supposed to be the address of the register to write to, set R/~W bit to 0. 00086 p_data[0] &= 0x7f; 00087 spiWrite(p_data,data_size); 00088 } 00089 } 00090 00091 00092 void BME280::busRead(uint8_t *p_data, uint8_t data_size) 00093 { 00094 if (_i2c_address==BME280_I2C_ADDRESS1 || _i2c_address==BME280_I2C_ADDRESS2) 00095 { 00096 // Assume I2C bus. 00097 i2cRead(_i2c_address,p_data,data_size); 00098 } 00099 else 00100 { 00101 // Assume SPI bus. 00102 // First byte is supposed to be the address of the register to write to, set R/~W bit to 1. 00103 p_data[0] |= 0x80; 00104 spiRead(p_data,data_size); 00105 } 00106 } 00107 00108 00109 uint8_t BME280::readUint8(uint8_t reg) 00110 { 00111 uint8_t data; 00112 busWrite(®,1,1); // Use repeated start. 00113 busRead(&data,1); // Read one byte. 00114 return data; 00115 } 00116 00117 00118 uint16_t BME280::readUint16(uint8_t reg) 00119 { 00120 uint8_t data[2]; 00121 uint16_t value; 00122 busWrite(®,1,1); // Use repeated start. 00123 busRead(data,2); // Read two bytes. 00124 // Process as little endian, which is the case for calibration data. 00125 value = data[1]; 00126 value = (value<<8) | data[0]; 00127 return value; 00128 } 00129 00130 00131 void BME280::readCalibrationData(void) 00132 { 00133 _dig_T1 = readUint16(BME280_CAL_T1); 00134 _dig_T2 = (int16_t) readUint16(BME280_CAL_T2); 00135 _dig_T3 = (int16_t) readUint16(BME280_CAL_T3); 00136 _dig_P1 = readUint16(BME280_CAL_P1); 00137 _dig_P2 = (int16_t) readUint16(BME280_CAL_P2); 00138 _dig_P3 = (int16_t) readUint16(BME280_CAL_P3); 00139 _dig_P4 = (int16_t) readUint16(BME280_CAL_P4); 00140 _dig_P5 = (int16_t) readUint16(BME280_CAL_P5); 00141 _dig_P6 = (int16_t) readUint16(BME280_CAL_P6); 00142 _dig_P7 = (int16_t) readUint16(BME280_CAL_P7); 00143 _dig_P8 = (int16_t) readUint16(BME280_CAL_P8); 00144 _dig_P9 = (int16_t) readUint16(BME280_CAL_P9); 00145 _dig_H1 = readUint8(BME280_CAL_H1); 00146 _dig_H2 = (int16_t) readUint16(BME280_CAL_H2); 00147 _dig_H3 = readUint8(BME280_CAL_H3); 00148 // H4 & H5 share a byte. 00149 uint8_t temp1 = readUint8(BME280_CAL_H4); 00150 uint8_t temp2 = readUint8(BME280_CAL_H45); 00151 uint8_t temp3 = readUint8(BME280_CAL_H5); 00152 _dig_H4 = (temp1<<4) | (temp2&0x0f); 00153 _dig_H5 = (temp3<<4) | (temp2>>4); 00154 _dig_H6 = (int8_t) readUint8(BME280_CAL_H6); 00155 } 00156 00157 00158 uint8_t BME280::readFrom(uint8_t reg, uint8_t data_size, uint8_t *p_data) 00159 { 00160 // Set start address to read from. 00161 busWrite(®,1,1); // Use repeated start. 00162 // Now read the requested number of bytes. 00163 busRead(p_data,data_size); 00164 return data_size; 00165 } 00166 00167 00168 void BME280::read(void) 00169 { 00170 // Get all the measurements in one burst (recommended). 00171 uint8_t data[BME280_MEASUREMENT_SIZE]; 00172 readFrom(BME280_MEASUREMENT_REGISTER,BME280_MEASUREMENT_SIZE,data); 00173 // We assume Normal mode, so it is not necessary to reissue a Forced mode command here. 00174 00175 // Process data. 00176 int32_t p = assembleRawValue(&data[0],1); 00177 int32_t t = assembleRawValue(&data[3],1); 00178 int32_t h = assembleRawValue(&data[6],0); 00179 00180 _temperature = compensateTemperature(t); // First call this before calling the other compensate functions. 00181 _pressure = compensatePressure(p); // Uses value calculated by compensateTemperature. 00182 _humidity = compensateHumidity(h); // Uses value calculated by compensateTemperature. 00183 } 00184 00185 00186 int32_t BME280::assembleRawValue(uint8_t *p_data, uint8_t has_xlsb) 00187 { 00188 // Needed to decode sensor data. 00189 uint32_t value = p_data[0]; 00190 value <<= 8; 00191 value |= p_data[1]; 00192 if (has_xlsb!=0) 00193 { 00194 value <<= 4; 00195 value |= (p_data[2]>>4); 00196 } 00197 return (int32_t) value; 00198 } 00199 00200 00201 void BME280::writeControlRegisters(uint8_t osrs_t, uint8_t osrs_p, uint8_t osrs_h, uint8_t mode) 00202 { 00203 uint8_t data[2]; 00204 data[0] = BME280_CTRL_HUM_REGISTER; 00205 data[1] = (osrs_h&0x07); 00206 busWrite(data,2,0); 00207 // Writing CTRL_MEAS validates previous write to CTRL_HUM. 00208 data[0] = BME280_CTRL_MEAS_REGISTER; 00209 data[1] = ((osrs_t&0x07)<<5) | ((osrs_p&0x07)<<2) | (mode&0x03); 00210 busWrite(data,2,0); 00211 } 00212 00213 00214 void BME280::writeConfigRegister(uint8_t t_sb, uint8_t filter, uint8_t spi) 00215 { 00216 uint8_t data[2]; 00217 data[0] = BME280_CONFIG_REGISTER; 00218 data[1] = ((t_sb&0x07)<<5) | ((filter&0x07)<<2) | (spi&0x01); 00219 busWrite(data,2,0); 00220 } 00221 00222 00223 void BME280::reset(void) 00224 { 00225 uint8_t data[2] = { BME280_RESET_REGISTER, BME280_RESET }; 00226 busWrite(data,2,0); 00227 } 00228 00229 00230 uint8_t BME280::readId(void) 00231 { 00232 return readUint8(BME280_ID_REGISTER); 00233 } 00234 00235 00236 #if BME280_ALLOW_FLOAT!=0 00237 00238 // From the driver by Bosch Sensortec 00239 00240 //! 00241 // @brief Reads actual temperature from uncompensated temperature 00242 // @note returns the value in Degree centigrade 00243 // @note Output value of "51.23" equals 51.23 DegC. 00244 // 00245 // @param adc_T : value of uncompensated temperature 00246 // 00247 // @return Return the actual temperature in floating point 00248 // 00249 temperature_t BME280::compensateTemperature(int32_t adc_T) 00250 { 00251 double v_x1_u32; 00252 double v_x2_u32; 00253 double temperature; 00254 00255 v_x1_u32 = (((double)adc_T) / 16384.0 - ((double)_dig_T1) / 1024.0) * ((double)_dig_T2); 00256 v_x2_u32 = ((((double)adc_T) / 131072.0 - ((double)_dig_T1) / 8192.0) * (((double)adc_T) / 131072.0 - ((double)_dig_T1) / 8192.0)) * ((double)_dig_T3); 00257 _t_fine = (int32_t)(v_x1_u32 + v_x2_u32); 00258 temperature = (v_x1_u32 + v_x2_u32) / 5120.0; 00259 return temperature; 00260 } 00261 00262 00263 //! 00264 // @brief Reads actual pressure from uncompensated pressure 00265 // @note Returns pressure in Pa as double. 00266 // @note Output value of "96386.2" 00267 // equals 96386.2 Pa = 963.862 hPa. 00268 // 00269 // @param adc_P : value of uncompensated pressure 00270 // 00271 // @return Return the actual pressure in floating point 00272 // 00273 pressure_t BME280::compensatePressure(int32_t adc_P) 00274 { 00275 double v_x1_u32; 00276 double v_x2_u32; 00277 double pressure; 00278 00279 v_x1_u32 = ((double)_t_fine / 2.0) - 64000.0; 00280 v_x2_u32 = v_x1_u32 * v_x1_u32 * ((double)_dig_P6) / 32768.0; 00281 v_x2_u32 = v_x2_u32 + v_x1_u32 * ((double)_dig_P5) * 2.0; 00282 v_x2_u32 = (v_x2_u32 / 4.0) + (((double)_dig_P4) * 65536.0); 00283 v_x1_u32 = (((double)_dig_P3) * v_x1_u32 * v_x1_u32 / 524288.0 + ((double)_dig_P2) * v_x1_u32) / 524288.0; 00284 v_x1_u32 = (1.0 + v_x1_u32 / 32768.0) * ((double)_dig_P1); 00285 pressure = 1048576.0 - (double)adc_P; 00286 // Avoid exception caused by division by zero. 00287 if (v_x1_u32 != 0) pressure = (pressure - (v_x2_u32 / 4096.0)) * 6250.0 / v_x1_u32; 00288 else return 0; 00289 v_x1_u32 = ((double)_dig_P9) * pressure * pressure / 2147483648.0; 00290 v_x2_u32 = pressure * ((double)_dig_P8) / 32768.0; 00291 pressure = pressure + (v_x1_u32 + v_x2_u32 + ((double)_dig_P7)) / 16.0; 00292 00293 return pressure; 00294 } 00295 00296 00297 //! 00298 // @brief Reads actual humidity from uncompensated humidity 00299 // @note returns the value in relative humidity (%rH) 00300 // @note Output value of "42.12" equals 42.12 %rH 00301 // 00302 // @param adc_H : value of uncompensated humidity 00303 // 00304 // @return Return the actual humidity in floating point 00305 // 00306 humidity_t BME280::compensateHumidity(int32_t adc_H) 00307 { 00308 double var_h; 00309 00310 var_h = (((double)_t_fine) - 76800.0); 00311 if (var_h != 0) 00312 { 00313 var_h = (adc_H - (((double)_dig_H4) * 64.0 + ((double)_dig_H5) / 16384.0 * var_h)) * 00314 (((double)_dig_H2) / 65536.0 * (1.0 + ((double) _dig_H6) / 67108864.0 * 00315 var_h * (1.0 + ((double)_dig_H3) / 67108864.0 * var_h))); 00316 } 00317 else return 0; 00318 var_h = var_h * (1.0 - ((double)_dig_H1)*var_h / 524288.0); 00319 if (var_h > 100.0) var_h = 100.0; 00320 else if (var_h < 0.0) var_h = 0.0; 00321 return var_h; 00322 } 00323 00324 #else /* BME280_ALLOW_FLOAT */ 00325 00326 // From the datasheet. 00327 // Returns temperature in DegC, resolution is 0.01 DegC. Output value of 5123 equals 51.23 DegC. 00328 // _t_fine carries fine temperature as "global" value. 00329 temperature_t BME280::compensateTemperature(int32_t adc_T) 00330 { 00331 int32_t var1, var2, T; 00332 var1 = ((((adc_T>>3) - ((int32_t)_dig_T1<<1))) * ((int32_t)_dig_T2)) >> 11; 00333 var2 = (((((adc_T>>4) - ((int32_t)_dig_T1)) * ((adc_T>>4) - ((int32_t)_dig_T1))) >> 12) * ((int32_t)_dig_T3)) >> 14; 00334 _t_fine = var1 + var2; 00335 T = (_t_fine * 5 + 128) >> 8; 00336 return T; 00337 } 00338 00339 00340 // From the datasheet. 00341 // Returns pressure in Pa as unsigned 32 bit integer. Output value of 96386 equals 96386 Pa = 963.86 hPa 00342 pressure_t BME280::compensatePressure(int32_t adc_P) 00343 { 00344 int32_t var1, var2; 00345 uint32_t p; 00346 var1 = (((int32_t)_t_fine)>>1) - (int32_t)64000; 00347 var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((int32_t)_dig_P6); 00348 var2 = var2 + ((var1*((int32_t)_dig_P5))<<1); 00349 var2 = (var2>>2)+(((int32_t)_dig_P4)<<16); 00350 var1 = (((_dig_P3 * (((var1>>2) * (var1>>2)) >> 13 )) >> 3) + ((((int32_t)_dig_P2) * var1)>>1))>>18; 00351 var1 =((((32768+var1))*((int32_t)_dig_P1))>>15); 00352 if (var1 == 0) 00353 { 00354 return 0; // avoid exception caused by division by zero 00355 } 00356 p = (((uint32_t)(((int32_t)1048576)-adc_P)-(var2>>12)))*3125; 00357 if (p < 0x80000000) 00358 { 00359 p = (p << 1) / ((uint32_t)var1); 00360 } 00361 else 00362 { 00363 p = (p / (uint32_t)var1) * 2; 00364 } 00365 var1 = (((int32_t)_dig_P9) * ((int32_t)(((p>>3) * (p>>3))>>13)))>>12; 00366 var2 = (((int32_t)(p>>2)) * ((int32_t)_dig_P8))>>13; 00367 p = (uint32_t)((int32_t)p + ((var1 + var2 + _dig_P7) >> 4)); 00368 return p; 00369 } 00370 00371 00372 // From the datasheet. 00373 // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits). 00374 // Output value of 47445 represents 47445/1024 = 46.333 %RH 00375 humidity_t BME280::compensateHumidity(int32_t adc_H) 00376 { 00377 int32_t v_x1_u32r; 00378 v_x1_u32r = (_t_fine - ((int32_t)76800)); 00379 v_x1_u32r = (((((adc_H << 14) - (((int32_t)_dig_H4) << 20) - (((int32_t)_dig_H5) * v_x1_u32r)) + 00380 ((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)_dig_H6)) >> 10) * (((v_x1_u32r * 00381 ((int32_t)_dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * 00382 ((int32_t)_dig_H2) + 8192) >> 14)); 00383 v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)_dig_H1)) >> 4)); 00384 v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); 00385 v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); 00386 return (uint32_t)(v_x1_u32r>>12); 00387 } 00388 00389 #endif /* BME280_ALLOW_FLOAT */
Generated on Tue Jul 12 2022 18:38:32 by 1.7.2