BMP180.cpp
1 /***************************************************************************************************/ 2 /* 3 This is an Arduino basic library for Bosch BMP180 & BMP085 barometric pressure & 4 temperature sensor 5 6 Power supply voltage: 1.8v - 3.6v 7 Range: 30,000Pa..110,000Pa at -40°C..+85°C 8 Typ. resolution: 1Pa / 0.1°C 9 Typ. accuracy: ±100Pa* / ±1.0°C* at 0°C..+65°C 10 Typ. relative accuracy: ±12Pa / xx°C 11 Duty cycle: 10% active & 90% inactive, to prevent self heating 12 13 *sensor is sensitive to direct light, which can affect 14 the accuracy of the measurement 15 16 written by : enjoyneering79 17 sourse code: https://github.com/enjoyneering/ 18 19 20 This chip uses I2C bus to communicate, specials pins are required to interface 21 Board: SDA SCL Level 22 Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v 23 Mega2560................................. 20 21 5v 24 Due, SAM3X8E............................. 20 21 3.3v 25 Leonardo, Micro, ATmega32U4.............. 2 3 5v 26 Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v 27 Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v 28 ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v 29 NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v 30 ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v 31 32 NOTE: 33 - EOC pin is not used, shows the end of conversion 34 - XCLR pin is not used, reset pin 35 36 Frameworks & Libraries: 37 ATtiny Core - https://github.com/SpenceKonde/ATTinyCore 38 ESP32 Core - https://github.com/espressif/arduino-esp32 39 ESP8266 Core - https://github.com/esp8266/Arduino 40 STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32 41 42 GNU GPL license, all text above must be included in any redistribution, 43 see link for details - https://www.gnu.org/licenses/licenses.html 44 */ 45 /***************************************************************************************************/ 46 47 #include "BMP180.h" 48 49 50 /**************************************************************************/ 51 /* 52 Constructor 53 54 NOTE: 55 - BMP180_ULTRALOWPOWER, pressure oversampled 1 time & consumption 3μA 56 - BMP180_STANDARD, pressure oversampled 2 times & consumption 5μA 57 - BMP180_HIGHRES, pressure oversampled 4 times & consumption 7μA 58 - BMP180_ULTRAHIGHRES, pressure oversampled 8 times & consumption 12μA 59 */ 60 /**************************************************************************/ 61 BMP180::BMP180(BMP180_RESOLUTION res_mode) 62 { 63 _resolution = res_mode; 64 } 65 66 67 /**************************************************************************/ 68 /* 69 getPressure() 70 71 Calculates compensated pressure, in Pa 72 73 NOTE: 74 - resolutin 1Pa with accuracy ±150Pa at range 30,000Pa..110,000Pa 75 */ 76 /**************************************************************************/ 77 int32_t BMP180::getPressure(void) 78 { 79 int32_t UT = 0; 80 int32_t UP = 0; 81 int32_t B3 = 0; 82 int32_t B5 = 0; 83 int32_t B6 = 0; 84 int32_t X1 = 0; 85 int32_t X2 = 0; 86 int32_t X3 = 0; 87 int32_t pressure = 0; 88 uint32_t B4 = 0; 89 uint32_t B7 = 0; 90 91 UT = readRawTemperature(); //read uncompensated temperature, 16-bit 92 if (UT == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus 93 94 UP = readRawPressure(); //read uncompensated pressure, 19-bit 95 if (UP == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus 96 97 B5 = computeB5(UT); 98 99 /* pressure calculation */ 100 B6 = B5 - 4000; 101 X1 = ((int32_t)_calCoeff.bmpB2 * ((B6 * B6) >> 12)) >> 11; 102 X2 = ((int32_t)_calCoeff.bmpAC2 * B6) >> 11; 103 X3 = X1 + X2; 104 B3 = ((((int32_t)_calCoeff.bmpAC1 * 4 + X3) << _resolution) + 2) / 4; 105 106 X1 = ((int32_t)_calCoeff.bmpAC3 * B6) >> 13; 107 X2 = ((int32_t)_calCoeff.bmpB1 * ((B6 * B6) >> 12)) >> 16; 108 X3 = ((X1 + X2) + 2) >> 2; 109 B4 = ((uint32_t)_calCoeff.bmpAC4 * (X3 + 32768L)) >> 15; 110 B7 = (UP - B3) * (50000UL >> _resolution); 111 112 if (B4 == 0) return BMP180_ERROR; //safety check, avoiding division by zero 113 114 if (B7 < 0x80000000) pressure = (B7 * 2) / B4; 115 else pressure = (B7 / B4) * 2; 116 117 X1 = pow((pressure >> 8), 2); 118 X1 = (X1 * 3038L) >> 16; 119 X2 = (-7357L * pressure) >> 16; 120 121 return pressure = pressure + ((X1 + X2 + 3791L) >> 4); 122 } 123 124 /**************************************************************************/ 125 /* 126 getTemperature() 127 128 Calculates compensated temperature, in °C 129 130 NOTE: 131 - resolution 0.1°C with accuracy ±1.0°C at range 0°C..+65°C 132 */ 133 /**************************************************************************/ 134 float BMP180::getTemperature(void) 135 { 136 int16_t rawTemperature = readRawTemperature(); 137 138 if (rawTemperature == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus 139 return (float)((computeB5(rawTemperature) + 8) >> 4) / 10; 140 } 141 142 /**************************************************************************/ 143 /* 144 getSeaLevelPressure() 145 146 Converts current pressure to sea level pressure at specific true 147 altitude, in Pa 148 149 NOTE: 150 - true altitude is the actual elevation above sea level, to find out 151 your current true altitude do search with google earth or gps 152 - see level pressure is commonly used in weather reports & forecasts 153 to compensate current true altitude 154 - for example, we know that a sunny day happens if the current sea 155 level pressure is 250Pa above the average sea level pressure of 156 101325 Pa, so by converting the current pressure to sea level & 157 comparing it with an average sea level pressure we can instantly 158 predict the weather conditions 159 */ 160 /**************************************************************************/ 161 int32_t BMP180::getSeaLevelPressure(int16_t trueAltitude) 162 { 163 int32_t pressure = getPressure(); 164 165 if (pressure == BMP180_ERROR) return BMP180_ERROR; 166 return (pressure / pow(1.0 - (float)trueAltitude / 44330, 5.255)); 167 } 168 169 /**************************************************************************/ 170 /* 171 softReset() 172 173 Soft reset 174 175 NOTE: 176 - performs the same sequence as power on reset 177 */ 178 /**************************************************************************/ 179 void BMP180::softReset(void) 180 { 181 write8(BMP180_SOFT_RESET_REG, BMP180_SOFT_RESET_CTRL); 182 } 183 184 /**************************************************************************/ 185 /* 186 readFirmwareVersion() 187 188 Reads ML & AL Version 189 190 NOTE: 191 - ML version is LSB, 4-bit..0-bit 192 - AL version is MSB, 7-bit..5-bit 193 */ 194 /**************************************************************************/ 195 uint8_t BMP180::readFirmwareVersion(void) 196 { 197 return read8(BMP180_GET_VERSION_REG); 198 } 199 200 /**************************************************************************/ 201 /* 202 readDeviceID() 203 204 Reads chip ID 205 */ 206 /**************************************************************************/ 207 uint8_t BMP180::readDeviceID(void) 208 { 209 if (read8(BMP180_GET_ID_REG) == BMP180_CHIP_ID) return 180; 210 return false; 211 } 212 213 /**************************************************************************/ 214 /* 215 readCalibrationCoefficients() 216 217 Reads factory calibration coefficients from E2PROM 218 219 NOTE: 220 - every sensor module has individual calibration coefficients 221 - before first temperature & pressure calculation master have to read 222 calibration coefficients from 176-bit E2PROM 223 */ 224 /**************************************************************************/ 225 bool BMP180::readCalibrationCoefficients() 226 { 227 int32_t value = 0; 228 229 for (uint8_t reg = BMP180_CAL_AC1_REG; reg <= BMP180_CAL_MD_REG; reg++) 230 { 231 value = read16(reg); 232 233 if (value == BMP180_ERROR) return false; //error handler, collision on i2c bus 234 235 switch (reg) 236 { 237 case BMP180_CAL_AC1_REG: //used for pressure computation 238 _calCoeff.bmpAC1 = value; 239 break; 240 241 case BMP180_CAL_AC2_REG: //used for pressure computation 242 _calCoeff.bmpAC2 = value; 243 break; 244 245 case BMP180_CAL_AC3_REG: //used for pressure computation 246 _calCoeff.bmpAC3 = value; 247 break; 248 249 case BMP180_CAL_AC4_REG: //used for pressure computation 250 _calCoeff.bmpAC4 = value; 251 break; 252 253 case BMP180_CAL_AC5_REG: //used for temperature computation 254 _calCoeff.bmpAC5 = value; 255 break; 256 257 case BMP180_CAL_AC6_REG: //used for temperature computation 258 _calCoeff.bmpAC6 = value; 259 break; 260 261 case BMP180_CAL_B1_REG: //used for pressure computation 262 _calCoeff.bmpB1 = value; 263 break; 264 265 case BMP180_CAL_B2_REG: //used for pressure computation 266 _calCoeff.bmpB2 = value; 267 break; 268 269 case BMP180_CAL_MB_REG: //??? 270 _calCoeff.bmpMB = value; 271 break; 272 273 case BMP180_CAL_MC_REG: //used for temperature computation 274 _calCoeff.bmpMC = value; 275 break; 276 277 case BMP180_CAL_MD_REG: //used for temperature computation 278 _calCoeff.bmpMD = value; 279 break; 280 } 281 } 282 283 return true; 284 } 285 286 /**************************************************************************/ 287 /* 288 readRawTemperature() 289 290 Reads raw/uncompensated temperature value, 16-bit 291 */ 292 /**************************************************************************/ 293 uint16_t BMP180::readRawTemperature(void) 294 { 295 /* send temperature measurement command */ 296 if (write8(BMP180_START_MEASURMENT_REG, BMP180_GET_TEMPERATURE_CTRL) != true) return BMP180_ERROR; //error handler, collision on i2c bus 297 298 /* set measurement delay */ 299 HAL_Delay(5); 300 301 /* read result */ 302 return read16(BMP180_READ_ADC_MSB_REG); //reads msb + lsb 303 } 304 305 /**************************************************************************/ 306 /* 307 readRawPressure() 308 309 Reads raw/uncompensated pressure value, 19-bits 310 */ 311 /**************************************************************************/ 312 uint32_t BMP180::readRawPressure(void) 313 { 314 uint8_t regControl = 0; 315 uint32_t rawPressure = 0; 316 317 /* convert resolution to register control */ 318 switch (_resolution) 319 { 320 case BMP180_ULTRALOWPOWER: //oss0 321 regControl = BMP180_GET_PRESSURE_OSS0_CTRL; 322 break; 323 324 case BMP180_STANDARD: //oss1 325 regControl = BMP180_GET_PRESSURE_OSS1_CTRL; 326 break; 327 328 case BMP180_HIGHRES: //oss2 329 regControl = BMP180_GET_PRESSURE_OSS2_CTRL; 330 break; 331 332 case BMP180_ULTRAHIGHRES: //oss3 333 regControl = BMP180_GET_PRESSURE_OSS3_CTRL; 334 break; 335 } 336 337 /* send pressure measurement command */ 338 if (write8(BMP180_START_MEASURMENT_REG, regControl) != true) return BMP180_ERROR; //error handler, collision on i2c bus 339 340 /* set measurement delay */ 341 switch (_resolution) 342 { 343 case BMP180_ULTRALOWPOWER: 344 HAL_Delay(5); 345 break; 346 347 case BMP180_STANDARD: 348 HAL_Delay(8); 349 break; 350 351 case BMP180_HIGHRES: 352 HAL_Delay(14); 353 break; 354 355 case BMP180_ULTRAHIGHRES: 356 HAL_Delay(26); 357 break; 358 } 359 360 /* read result msb + lsb */ 361 rawPressure = read16(BMP180_READ_ADC_MSB_REG); //16-bits 362 if (rawPressure == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus 363 364 /* read result xlsb */ 365 rawPressure <<= 8; 366 rawPressure |= read8(BMP180_READ_ADC_XLSB_REG); //19-bits 367 368 rawPressure >>= (8 - _resolution); 369 370 return rawPressure; 371 } 372 373 /**************************************************************************/ 374 /* 375 computeB5() 376 377 Computes B5 value 378 379 NOTE: 380 - to compensate raw/uncompensated temperature 381 - also used for compensated pressure calculation 382 */ 383 /**************************************************************************/ 384 int32_t BMP180::computeB5(int32_t UT) 385 { 386 int32_t X1 = ((UT - (int32_t)_calCoeff.bmpAC6) * (int32_t)_calCoeff.bmpAC5) >> 15; 387 int32_t X2 = ((int32_t)_calCoeff.bmpMC << 11) / (X1 + (int32_t)_calCoeff.bmpMD); 388 389 return X1 + X2; 390 } 391 392 /**************************************************************************/ 393 /* 394 read8() 395 396 Reads 8-bit value over I2C 397 */ 398 /**************************************************************************/ 399 uint8_t BMP180::read8(uint8_t reg) 400 { 401 uint8_t data = 0; 402 HAL_StatusTypeDef status; 403 404 // Write register address 405 status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, ®, 1, I2C_TIMEOUT); 406 if (status != HAL_OK) return BMP180_ERROR; 407 408 // Read data from register 409 status = HAL_I2C_Master_Receive(&hi2c3, BMP180_ADDRESS, &data, 1, I2C_TIMEOUT); 410 if (status != HAL_OK) return BMP180_ERROR; 411 412 return data; 413 } 414 415 /**************************************************************************/ 416 /* 417 read16() 418 419 Reads 16-bits value over I2C 420 */ 421 /**************************************************************************/ 422 423 uint16_t BMP180::read16(uint8_t reg) 424 { 425 uint8_t data[2] = {0, 0}; 426 uint16_t value = 0; 427 HAL_StatusTypeDef status; 428 429 // Write register address 430 status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, ®, 1, I2C_TIMEOUT); 431 if (status != HAL_OK) return BMP180_ERROR; 432 433 // Read 2 bytes from register 434 status = HAL_I2C_Master_Receive(&hi2c3, BMP180_ADDRESS, data, 2, I2C_TIMEOUT); 435 if (status != HAL_OK) return BMP180_ERROR; 436 437 // Combine bytes (MSB first) 438 value = (data[0] << 8) | data[1]; 439 440 return value; 441 } 442 443 444 /**************************************************************************/ 445 /* 446 write8() 447 448 Writes 8-bits value over I2C 449 */ 450 /**************************************************************************/ 451 452 bool BMP180::write8(uint8_t reg, uint8_t control) 453 { 454 uint8_t data[2] = {reg, control}; 455 HAL_StatusTypeDef status; 456 457 // Write register address and data 458 status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, data, 2, I2C_TIMEOUT); 459 460 return (status == HAL_OK); 461 } 462