Library to control a BMP180 sensor.

BMP180 sensor

BMP180.cpp

Committer:
Wosser1sProductions
Date:
2016-08-26
Revision:
0:373de0f4d5cd
Child:
1:608e890e88e7

File content as of revision 0:373de0f4d5cd:

/*
  @file BMP180.cpp
  @brief Barometric Pressure and Temperature Sensor BMP180 Breakout I2C Library
*/

#include "BMP180.h"

BMP180::BMP180(I2C& i2c) : m_i2c(i2c) {
    m_altitude      = 0;
    m_oss           = STANDARD;
}

int BMP180::initialize(float altitude, OverSamplingSetting oss) {
    char data[22];
    int errors = 0;

    m_altitude      = altitude;
    m_oss           = oss;

    // read calibration data
    data[0]=0xAA;
    errors = m_i2c.write(BMP180_I2C_ADDRESS, data, 1);  // set the eeprom pointer position to 0xAA
    errors += m_i2c.read(BMP180_I2C_ADDRESS, data, 22); // read 11 x 16 bits at this position
    wait_ms(10);

    // store calibration data for further calculus
    ac1 = data[0]  << 8 | data[1];
    ac2 = data[2]  << 8 | data[3];
    ac3 = data[4]  << 8 | data[5];
    ac4 = data[6]  << 8 | data[7];
    ac5 = data[8]  << 8 | data[9];
    ac6 = data[10] << 8 | data[11];
    b1  = data[12] << 8 | data[13];
    b2  = data[14] << 8 | data[15];
    //mb  = data[16] << 8 | data[17];   // Not used?
    mc  = data[18] << 8 | data[19];
    md  = data[20] << 8 | data[21];

    // Pre-calc
    ac1 = ac1 << 2;
    mc  = mc  << 11;

    return errors == 0; // 0 = ACK = success
}

int BMP180::ReadData(float& pTemperature, float& pPressure) {
    long t, p;

    if (!ReadRawTemperature(&t) || !ReadRawPressure(&p))
        return 0;   // Error

    pTemperature    = TrueTemperature(t);
    pPressure       = TruePressure(p);

    return 1;
}

int BMP180::ReadRawTemperature(long* pUt) {
    int errors = 0;

    // request temperature measurement
    m_data[0] = 0xF4;
    m_data[1] = 0x2E;
    errors = m_i2c.write(BMP180_I2C_ADDRESS, m_data, 2); // write 0XF2 into reg 0XF4

    wait_ms(5);

    // read raw temperature data
    m_data[0] = 0xF6;
    errors += m_i2c.write(BMP180_I2C_ADDRESS, m_data, 2); // set eeprom pointer position to 0XF6
    errors += m_i2c.read(BMP180_I2C_ADDRESS, m_data, 2);  // get 16 bits at this position

    if (errors) return 0;
    *pUt = m_data[0] << 8 | m_data[1];

    return 1;
}

int BMP180::ReadRawPressure(long* pUp) {
    int errors = 0;

    // request pressure measurement
    m_data[0] = 0xF4;
    m_data[1] = 0x34 + (m_oss << 6);
    errors = m_i2c.write(BMP180_I2C_ADDRESS, m_data, 2); // write 0x34 + (m_oss << 6) into reg 0XF4

    switch (m_oss) {    // Rounded up wait times to be safe
        case ULTRA_LOW_POWER:        wait_ms(5); break;
        case STANDARD:               wait_ms(8); break;
        case HIGH_RESOLUTION:        wait_ms(14); break;
        case ULTRA_HIGH_RESOLUTION:  wait_ms(26); break;
    }

    // read raw pressure data
    m_data[0] = 0xF6;
    errors += m_i2c.write(BMP180_I2C_ADDRESS, m_data, 1); // set eeprom pointer position to 0XF6
    errors += m_i2c.read(BMP180_I2C_ADDRESS, m_data, 2);  // get 16 bits at this position

    if (errors) return 0;
    *pUp = (m_data[0] << 16 | m_data[1] << 8) >> (8 - m_oss);

    return 1;
}

float BMP180::TrueTemperature(long ut) {
    // straight out from the documentation
    x1 = ((ut - ac6) * ac5) >> 15;
    x2 = mc / (x1 + md);
    b5 = x1 + x2;

    // convert to Celsius
    return (long)((b5 + 8) >> 4) / 10.F;
}

float BMP180::TruePressure(long up) {
    long p;

    // straight out from the documentation
    b6 = b5 - 4000;
    x1 = (b2 * (b6 * b6 >> 12)) >> 11;
    x2 = ac2 * b6 >> 11;
    b3 = (((ac1 + x1 + x2) << m_oss) + 2) >> 2;
    x1 = (ac3 * b6) >> 13;
    x2 = (b1 * ((b6 * b6) >> 12)) >> 16;
    x3 = (x1 + x2 + 2) >> 2;
    b4 = ac4 * (unsigned long)(x3 + 32768) >> 15;
    b7 = ((unsigned long)up - b3)* (50000 >> m_oss);
    if (b7 < 0x80000000) p = (b7 << 1) / b4;
    else                 p = (b7 / b4) << 1;
    x1 = (p >> 8) * (p >> 8);
    x1 = (x1 * 3038) >> 16;
    x2 = (-7357 * p) >> 16;
    p = p + ((x1 + x2 + 3791) >> 4);

    // convert to hPa and, if altitude has been initialized, to sea level pressure
    return (m_altitude == 0.F) ? p / 100.F
                               : p / (100.F * pow((1.F - m_altitude / 44330.0L), 5.255L));
}