libraries / Adafruit_BMP085_Unified-master / Adafruit_BMP085_U.cppon commit Added readme code notes (00df5ca)
   1/***************************************************************************
   2  This is a library for the BMP085 pressure sensor
   3
   4  Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout 
   5  ----> http://www.adafruit.com/products/391
   6  ----> http://www.adafruit.com/products/1603
   7 
   8  These displays use I2C to communicate, 2 pins are required to interface.
   9
  10  Adafruit invests time and resources providing this open source code,
  11  please support Adafruit andopen-source hardware by purchasing products
  12  from Adafruit!
  13
  14  Written by Kevin Townsend for Adafruit Industries.  
  15  BSD license, all text above must be included in any redistribution
  16 ***************************************************************************/
  17#if ARDUINO >= 100
  18 #include "Arduino.h"
  19#else
  20 #include "WProgram.h"
  21#endif
  22
  23#ifdef __AVR_ATtiny85__
  24 #include "TinyWireM.h"
  25 #define Wire TinyWireM
  26#else
  27 #include <Wire.h>
  28#endif
  29
  30#include <math.h>
  31#include <limits.h>
  32
  33#include "Adafruit_BMP085_U.h"
  34
  35static bmp085_calib_data _bmp085_coeffs;   // Last read accelerometer data will be available here
  36static uint8_t           _bmp085Mode;
  37
  38#define BMP085_USE_DATASHEET_VALS (0) /* Set to 1 for sanity check */
  39
  40/***************************************************************************
  41 PRIVATE FUNCTIONS
  42 ***************************************************************************/
  43
  44/**************************************************************************/
  45/*!
  46    @brief  Writes an 8 bit value over I2C
  47*/
  48/**************************************************************************/
  49static void writeCommand(byte reg, byte value)
  50{
  51  Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
  52  #if ARDUINO >= 100
  53    Wire.write((uint8_t)reg);
  54    Wire.write((uint8_t)value);
  55  #else
  56    Wire.send(reg);
  57    Wire.send(value);
  58  #endif
  59  Wire.endTransmission();
  60}
  61
  62/**************************************************************************/
  63/*!
  64    @brief  Reads an 8 bit value over I2C
  65*/
  66/**************************************************************************/
  67static void read8(byte reg, uint8_t *value)
  68{
  69  Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
  70  #if ARDUINO >= 100
  71    Wire.write((uint8_t)reg);
  72  #else
  73    Wire.send(reg);
  74  #endif
  75  Wire.endTransmission();
  76  Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)1);
  77  #if ARDUINO >= 100
  78    *value = Wire.read();
  79  #else
  80    *value = Wire.receive();
  81  #endif  
  82  Wire.endTransmission();
  83}
  84
  85/**************************************************************************/
  86/*!
  87    @brief  Reads a 16 bit value over I2C
  88*/
  89/**************************************************************************/
  90static void read16(byte reg, uint16_t *value)
  91{
  92  Wire.beginTransmission((uint8_t)BMP085_ADDRESS);
  93  #if ARDUINO >= 100
  94    Wire.write((uint8_t)reg);
  95  #else
  96    Wire.send(reg);
  97  #endif
  98  Wire.endTransmission();
  99  Wire.requestFrom((uint8_t)BMP085_ADDRESS, (byte)2);
 100  #if ARDUINO >= 100
 101    *value = (Wire.read() << 8) | Wire.read();
 102  #else
 103    *value = (Wire.receive() << 8) | Wire.receive();
 104  #endif  
 105  Wire.endTransmission();
 106}
 107
 108/**************************************************************************/
 109/*!
 110    @brief  Reads a signed 16 bit value over I2C
 111*/
 112/**************************************************************************/
 113static void readS16(byte reg, int16_t *value)
 114{
 115  uint16_t i;
 116  read16(reg, &i);
 117  *value = (int16_t)i;
 118}
 119
 120/**************************************************************************/
 121/*!
 122    @brief  Reads the factory-set coefficients
 123*/
 124/**************************************************************************/
 125static void readCoefficients(void)
 126{
 127  #if BMP085_USE_DATASHEET_VALS
 128    _bmp085_coeffs.ac1 = 408;
 129    _bmp085_coeffs.ac2 = -72;
 130    _bmp085_coeffs.ac3 = -14383;
 131    _bmp085_coeffs.ac4 = 32741;
 132    _bmp085_coeffs.ac5 = 32757;
 133    _bmp085_coeffs.ac6 = 23153;
 134    _bmp085_coeffs.b1  = 6190;
 135    _bmp085_coeffs.b2  = 4;
 136    _bmp085_coeffs.mb  = -32768;
 137    _bmp085_coeffs.mc  = -8711;
 138    _bmp085_coeffs.md  = 2868;
 139    _bmp085Mode        = 0;
 140  #else
 141    readS16(BMP085_REGISTER_CAL_AC1, &_bmp085_coeffs.ac1);
 142    readS16(BMP085_REGISTER_CAL_AC2, &_bmp085_coeffs.ac2);
 143    readS16(BMP085_REGISTER_CAL_AC3, &_bmp085_coeffs.ac3);
 144    read16(BMP085_REGISTER_CAL_AC4, &_bmp085_coeffs.ac4);
 145    read16(BMP085_REGISTER_CAL_AC5, &_bmp085_coeffs.ac5);
 146    read16(BMP085_REGISTER_CAL_AC6, &_bmp085_coeffs.ac6);
 147    readS16(BMP085_REGISTER_CAL_B1, &_bmp085_coeffs.b1);
 148    readS16(BMP085_REGISTER_CAL_B2, &_bmp085_coeffs.b2);
 149    readS16(BMP085_REGISTER_CAL_MB, &_bmp085_coeffs.mb);
 150    readS16(BMP085_REGISTER_CAL_MC, &_bmp085_coeffs.mc);
 151    readS16(BMP085_REGISTER_CAL_MD, &_bmp085_coeffs.md);
 152  #endif
 153}
 154
 155/**************************************************************************/
 156/*!
 157
 158*/
 159/**************************************************************************/
 160static void readRawTemperature(int32_t *temperature)
 161{
 162  #if BMP085_USE_DATASHEET_VALS
 163    *temperature = 27898;
 164  #else
 165    uint16_t t;
 166    writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READTEMPCMD);
 167    delay(5);
 168    read16(BMP085_REGISTER_TEMPDATA, &t);
 169    *temperature = t;
 170  #endif
 171}
 172
 173/**************************************************************************/
 174/*!
 175
 176*/
 177/**************************************************************************/
 178static void readRawPressure(int32_t *pressure)
 179{
 180  #if BMP085_USE_DATASHEET_VALS
 181    *pressure = 23843;
 182  #else
 183    uint8_t  p8;
 184    uint16_t p16;
 185    int32_t  p32;
 186
 187    writeCommand(BMP085_REGISTER_CONTROL, BMP085_REGISTER_READPRESSURECMD + (_bmp085Mode << 6));
 188    switch(_bmp085Mode)
 189    {
 190      case BMP085_MODE_ULTRALOWPOWER:
 191        delay(5);
 192        break;
 193      case BMP085_MODE_STANDARD:
 194        delay(8);
 195        break;
 196      case BMP085_MODE_HIGHRES:
 197        delay(14);
 198        break;
 199      case BMP085_MODE_ULTRAHIGHRES:
 200      default:
 201        delay(26);
 202        break;
 203    }
 204
 205    read16(BMP085_REGISTER_PRESSUREDATA, &p16);
 206    p32 = (uint32_t)p16 << 8;
 207    read8(BMP085_REGISTER_PRESSUREDATA+2, &p8);
 208    p32 += p8;
 209    p32 >>= (8 - _bmp085Mode);
 210    
 211    *pressure = p32;
 212  #endif
 213}
 214
 215/**************************************************************************/
 216/*!
 217    @brief  Compute B5 coefficient used in temperature & pressure calcs.
 218*/
 219/**************************************************************************/
 220int32_t Adafruit_BMP085_Unified::computeB5(int32_t ut) {
 221  int32_t X1 = (ut - (int32_t)_bmp085_coeffs.ac6) * ((int32_t)_bmp085_coeffs.ac5) >> 15;
 222  int32_t X2 = ((int32_t)_bmp085_coeffs.mc << 11) / (X1+(int32_t)_bmp085_coeffs.md);
 223  return X1 + X2;
 224}
 225
 226
 227/***************************************************************************
 228 CONSTRUCTOR
 229 ***************************************************************************/
 230 
 231/**************************************************************************/
 232/*!
 233    @brief  Instantiates a new Adafruit_BMP085_Unified class
 234*/
 235/**************************************************************************/
 236Adafruit_BMP085_Unified::Adafruit_BMP085_Unified(int32_t sensorID) {
 237  _sensorID = sensorID;
 238}
 239
 240/***************************************************************************
 241 PUBLIC FUNCTIONS
 242 ***************************************************************************/
 243 
 244/**************************************************************************/
 245/*!
 246    @brief  Setups the HW
 247*/
 248/**************************************************************************/
 249bool Adafruit_BMP085_Unified::begin(bmp085_mode_t mode)
 250{
 251  // Enable I2C
 252  Wire.begin();
 253
 254  /* Mode boundary check */
 255  if ((mode > BMP085_MODE_ULTRAHIGHRES) || (mode < 0))
 256  {
 257    mode = BMP085_MODE_ULTRAHIGHRES;
 258  }
 259
 260  /* Make sure we have the right device */
 261  uint8_t id;
 262  read8(BMP085_REGISTER_CHIPID, &id);
 263  if(id != 0x55)
 264  {
 265    return false;
 266  }
 267
 268  /* Set the mode indicator */
 269  _bmp085Mode = mode;
 270
 271  /* Coefficients need to be read once */
 272  readCoefficients();
 273    
 274  return true;
 275}
 276
 277/**************************************************************************/
 278/*!
 279    @brief  Gets the compensated pressure level in kPa
 280*/
 281/**************************************************************************/
 282void Adafruit_BMP085_Unified::getPressure(float *pressure)
 283{
 284  int32_t  ut = 0, up = 0, compp = 0;
 285  int32_t  x1, x2, b5, b6, x3, b3, p;
 286  uint32_t b4, b7;
 287
 288  /* Get the raw pressure and temperature values */
 289  readRawTemperature(&ut);
 290  readRawPressure(&up);
 291
 292  /* Temperature compensation */
 293  b5 = computeB5(ut);
 294
 295  /* Pressure compensation */
 296  b6 = b5 - 4000;
 297  x1 = (_bmp085_coeffs.b2 * ((b6 * b6) >> 12)) >> 11;
 298  x2 = (_bmp085_coeffs.ac2 * b6) >> 11;
 299  x3 = x1 + x2;
 300  b3 = (((((int32_t) _bmp085_coeffs.ac1) * 4 + x3) << _bmp085Mode) + 2) >> 2;
 301  x1 = (_bmp085_coeffs.ac3 * b6) >> 13;
 302  x2 = (_bmp085_coeffs.b1 * ((b6 * b6) >> 12)) >> 16;
 303  x3 = ((x1 + x2) + 2) >> 2;
 304  b4 = (_bmp085_coeffs.ac4 * (uint32_t) (x3 + 32768)) >> 15;
 305  b7 = ((uint32_t) (up - b3) * (50000 >> _bmp085Mode));
 306
 307  if (b7 < 0x80000000)
 308  {
 309    p = (b7 << 1) / b4;
 310  }
 311  else
 312  {
 313    p = (b7 / b4) << 1;
 314  }
 315
 316  x1 = (p >> 8) * (p >> 8);
 317  x1 = (x1 * 3038) >> 16;
 318  x2 = (-7357 * p) >> 16;
 319  compp = p + ((x1 + x2 + 3791) >> 4);
 320
 321  /* Assign compensated pressure value */
 322  *pressure = compp;
 323}
 324
 325/**************************************************************************/
 326/*!
 327    @brief  Reads the temperatures in degrees Celsius
 328*/
 329/**************************************************************************/
 330void Adafruit_BMP085_Unified::getTemperature(float *temp)
 331{
 332  int32_t UT, X1, X2, B5;     // following ds convention
 333  float t;
 334
 335  readRawTemperature(&UT);
 336
 337  #if BMP085_USE_DATASHEET_VALS
 338    // use datasheet numbers!
 339    UT = 27898;
 340    _bmp085_coeffs.ac6 = 23153;
 341    _bmp085_coeffs.ac5 = 32757;
 342    _bmp085_coeffs.mc = -8711;
 343    _bmp085_coeffs.md = 2868;
 344  #endif
 345
 346  B5 = computeB5(UT);
 347  t = (B5+8) >> 4;
 348  t /= 10;
 349
 350  *temp = t;
 351}
 352
 353/**************************************************************************/
 354/*!
 355    Calculates the altitude (in meters) from the specified atmospheric
 356    pressure (in hPa), and sea-level pressure (in hPa).
 357
 358    @param  seaLevel      Sea-level pressure in hPa
 359    @param  atmospheric   Atmospheric pressure in hPa
 360*/
 361/**************************************************************************/
 362float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric)
 363{
 364  // Equation taken from BMP180 datasheet (page 16):
 365  //  http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
 366
 367  // Note that using the equation from wikipedia can give bad results
 368  // at high altitude.  See this thread for more information:
 369  //  http://forums.adafruit.com/viewtopic.php?f=22&t=58064
 370  
 371  return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903));
 372}
 373
 374/**************************************************************************/
 375/*!
 376    Calculates the altitude (in meters) from the specified atmospheric
 377    pressure (in hPa), and sea-level pressure (in hPa).  Note that this
 378    function just calls the overload of pressureToAltitude which takes
 379    seaLevel and atmospheric pressure--temperature is ignored.  The original
 380    implementation of this function was based on calculations from Wikipedia
 381    which are not accurate at higher altitudes.  To keep compatibility with
 382    old code this function remains with the same interface, but it calls the
 383    more accurate calculation.
 384
 385    @param  seaLevel      Sea-level pressure in hPa
 386    @param  atmospheric   Atmospheric pressure in hPa
 387    @param  temp          Temperature in degrees Celsius
 388*/
 389/**************************************************************************/
 390float Adafruit_BMP085_Unified::pressureToAltitude(float seaLevel, float atmospheric, float temp)
 391{
 392  return pressureToAltitude(seaLevel, atmospheric);
 393}
 394
 395/**************************************************************************/
 396/*!
 397    Calculates the pressure at sea level (in hPa) from the specified altitude 
 398    (in meters), and atmospheric pressure (in hPa).  
 399
 400    @param  altitude      Altitude in meters
 401    @param  atmospheric   Atmospheric pressure in hPa
 402*/
 403/**************************************************************************/
 404float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude, float atmospheric)
 405{
 406  // Equation taken from BMP180 datasheet (page 17):
 407  //  http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
 408
 409  // Note that using the equation from wikipedia can give bad results
 410  // at high altitude.  See this thread for more information:
 411  //  http://forums.adafruit.com/viewtopic.php?f=22&t=58064
 412  
 413  return atmospheric / pow(1.0 - (altitude/44330.0), 5.255);
 414}
 415
 416/**************************************************************************/
 417/*!
 418    Calculates the pressure at sea level (in hPa) from the specified altitude 
 419    (in meters), and atmospheric pressure (in hPa).  Note that this
 420    function just calls the overload of seaLevelForAltitude which takes
 421    altitude and atmospheric pressure--temperature is ignored.  The original
 422    implementation of this function was based on calculations from Wikipedia
 423    which are not accurate at higher altitudes.  To keep compatibility with
 424    old code this function remains with the same interface, but it calls the
 425    more accurate calculation.
 426
 427    @param  altitude      Altitude in meters
 428    @param  atmospheric   Atmospheric pressure in hPa
 429    @param  temp          Temperature in degrees Celsius
 430*/
 431/**************************************************************************/
 432float Adafruit_BMP085_Unified::seaLevelForAltitude(float altitude, float atmospheric, float temp)
 433{
 434  return seaLevelForAltitude(altitude, atmospheric);
 435}
 436
 437
 438
 439/**************************************************************************/
 440/*!
 441    @brief  Provides the sensor_t data for this sensor
 442*/
 443/**************************************************************************/
 444void Adafruit_BMP085_Unified::getSensor(sensor_t *sensor)
 445{
 446  /* Clear the sensor_t object */
 447  memset(sensor, 0, sizeof(sensor_t));
 448
 449  /* Insert the sensor name in the fixed length char array */
 450  strncpy (sensor->name, "BMP085", sizeof(sensor->name) - 1);
 451  sensor->name[sizeof(sensor->name)- 1] = 0;
 452  sensor->version     = 1;
 453  sensor->sensor_id   = _sensorID;
 454  sensor->type        = SENSOR_TYPE_PRESSURE;
 455  sensor->min_delay   = 0;
 456  sensor->max_value   = 1100.0F;               // 300..1100 hPa
 457  sensor->min_value   = 300.0F;
 458  sensor->resolution  = 0.01F;                // Datasheet states 0.01 hPa resolution
 459}
 460
 461/**************************************************************************/
 462/*!
 463    @brief  Reads the sensor and returns the data as a sensors_event_t
 464*/
 465/**************************************************************************/
 466bool Adafruit_BMP085_Unified::getEvent(sensors_event_t *event)
 467{
 468  float pressure_kPa;
 469
 470  /* Clear the event */
 471  memset(event, 0, sizeof(sensors_event_t));
 472
 473  event->version   = sizeof(sensors_event_t);
 474  event->sensor_id = _sensorID;
 475  event->type      = SENSOR_TYPE_PRESSURE;
 476  event->timestamp = 0;
 477  getPressure(&pressure_kPa);
 478  event->pressure = pressure_kPa / 100.0F;
 479  
 480  return true;
 481}