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, &reg, 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, &reg, 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