This is a BMP180 Library. Using "Timeout", so you do not need to use "wait".

BMP180.hpp

Committer:
Gaku0606
Date:
2018-07-20
Revision:
0:6953e7630b84

File content as of revision 0:6953e7630b84:

/**
* @file BMP180.hpp
* @brief This is a Library for BMP180
* @author Matsumoto Gaku
* @date 2018/07/10
*/

#pragma once
#include "mbed.h"

#define BMP180_AC1_H    0xAA
#define BMP180_AC1_L    0xAB
#define BMP180_AC2_H    0xAC
#define BMP180_AC2_L    0xAD
#define BMP180_AC3_H    0xAE
#define BMP180_AC3_L    0xAF
#define BMP180_AC4_H    0xB0
#define BMP180_AC4_L    0xB1
#define BMP180_AC5_H    0xB2
#define BMP180_AC5_L    0xB3
#define BMP180_AC6_H    0xB4
#define BMP180_AC6_L    0xB5
#define BMP180_B1_H 0xB6
#define BMP180_B1_L 0xB7
#define BMP180_B2_H 0xB8
#define BMP180_B2_L 0xB9
#define BMP180_MB_H 0xBA
#define BMP180_MB_L 0xBB
#define BMP180_MC_H 0xBC
#define BMP180_MC_L 0xBD
#define BMP180_MD_H 0xBE
#define BMP180_MD_L 0xBF

#define BMP180_SLAVEADDR    0b11101110
//#define BMP180_SLAVEADDR_READ 0xEF

#define BMP180_OUT_MSB  0xF6
#define BMP180_OUT_LSB  0xF7
#define BMP180_OUT_XLSB 0xF8

#define BMP180_CTRL_MEAS    0xF4
#define BMP180_SOFT_REAST   0xE0
#define BMP180_ID   0xD0


/**
* @brief BMP180 class
*/
class BMP180 {


public:

    /**
    * @enum Enum
    * hardware accuracy modes
    * 測定モードの選択
    */
    enum MODE {
        ULTRA_LOW_POWER = 0x34,
        STANDARD = 0x74,
        HIGH_RESOLUTION = 0xB4,
        ULTRA_HIGH_RESOLUTION = 0xF4
    };

    /**
    * @brief BMP180 library's constructor
    * @param Pointer of User I2C 
    */
    BMP180(I2C &i2c) : _i2c(i2c){
        ctrl_meas = ULTRA_HIGH_RESOLUTION;
        convertion_time = 25500;
        oss = 3;

        char coeff[22];
        readReg(BMP180_SLAVEADDR, BMP180_AC1_H, coeff, 22);
        AC1 = ((uint16_t)coeff[0] << 8) | (uint16_t)coeff[1];
        AC2 = ((uint16_t)coeff[2] << 8) | (uint16_t)coeff[3];
        AC3 = ((uint16_t)coeff[4] << 8) | (uint16_t)coeff[5];
        AC4 = ((uint16_t)coeff[6] << 8) | (uint16_t)coeff[7];
        AC5 = ((uint16_t)coeff[8] << 8) | (uint16_t)coeff[9];
        AC6 = ((uint16_t)coeff[10] << 8) | (uint16_t)coeff[11];
        B1 = ((uint16_t)coeff[12] << 8) | (uint16_t)coeff[13];
        B2 = ((uint16_t)coeff[14] << 8) | (uint16_t)coeff[15];
        MB = ((uint16_t)coeff[16] << 8) | (uint16_t)coeff[17];
        MC = ((uint16_t)coeff[18] << 8) | (uint16_t)coeff[19];
        MD = ((uint16_t)coeff[20] << 8) | (uint16_t)coeff[21];

        callFlag_press = 0;
        callFlag_temp = 0;
        pressure = 0.0f;
        temperature = 0.0f;
    };

    /**
    * @brief Set hardware accurary modes
    * @param mode : ULTRA_HIGH_RESOLUTION etc.
    * @return connection status. if senser's ID could not read, return false.
    * @sa MODE
    */
    bool begin(MODE mode) {
        switch (mode)
        {
        case BMP180::ULTRA_LOW_POWER:
            ctrl_meas = 0x34;
            oss = 0;
            convertion_time = 4500;
            break;
        case BMP180::STANDARD:
            ctrl_meas = 0x74;
            oss = 1;
            convertion_time = 7500;
            break;
        case BMP180::HIGH_RESOLUTION:
            ctrl_meas = 0xB4;
            oss = 2;
            convertion_time = 13500;
            break;
        case BMP180::ULTRA_HIGH_RESOLUTION:
            ctrl_meas = 0xF4;
            oss = 3;
            convertion_time = 25500;
            break;
        default:
            break;
        }

        //センサーチェック
        char result = readReg(BMP180_SLAVEADDR, BMP180_ID);
        if (result == 0x55) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
    * @brief start measuring
    * @detail you have to read data after you excute this. 
    */
    void measure() {
        startTemperature();
    }

    /**
    * @brief get pressure and temperature data
    * @param *press float variable pointer for pressure data
    * @param *temp float variable pointer for temperature data
    */
    void readPressTemp(float *press, float *temp) {
        *press = pressure;
        *temp = temperature;
    }

private:
    void startTemperature() {
        //測定開始
        writeReg(BMP180_SLAVEADDR, BMP180_CTRL_MEAS, 0x2E);
        if (callFlag_temp) {
            callFlag_temp = 0;
            tempTimer.detach();
        }
        //測定終了後にデータを取得する
        callFlag_temp = 1;
        tempTimer.attach_us(this, &BMP180::readTemperature, 4500);
    }

    void startPressure() {
        writeReg(BMP180_SLAVEADDR, BMP180_CTRL_MEAS, ctrl_meas);
        if (callFlag_press) {
            callFlag_press = 0;
            pressTimer.detach();
        }
        callFlag_press = 1;
        pressTimer.attach_us(this, &BMP180::readPressure, convertion_time);

    }

    void readTemperature() {
        callFlag_temp = 0;
        char buff[2];
        readReg(BMP180_SLAVEADDR, BMP180_OUT_MSB, buff,2);
        UT = (uint16_t)buff[0] << 8 | (uint16_t)buff[1];

        startPressure();
    }

    void readPressure() {
        char buff[3];
        readReg(BMP180_SLAVEADDR, BMP180_OUT_MSB, buff, 3);
        UP = ((uint32_t)buff[0] << 16) | ((uint32_t)buff[1] << 8) | (uint32_t)buff[2];
        UP = UP >> (8 - oss);

        //値更新 update pressure and tempsrature
        temperature = CaluculateTrueTemperature();
        pressure = CaluculateTruePressure();
    }

    //生の温度データを校正係数で補正する
    //raw temp data change to accurate data
    float CaluculateTrueTemperature() {

        X1 = ((UT - AC6) * AC5) >> 15;
        X2 = ((long)MC << 11) / (X1 + MD);
        B5 = X1 + X2;
        T = (B5 + 8) >> 4;
        return T * 0.1f;
    }

    //生の気圧データを校正係数で補正する
    //raw press data change to accurate data
    float CaluculateTruePressure() {
        B6 = B5 - 4000;
        X1 = (B2*((B6*B6) >> 12)) >> 11;
        X2 = AC2 * B6 >> 11;
        X3 = X1 + X2;
        B3 = (((AC1 * 4 + X3) << 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 >> 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 += (X1 + X2 + 3791) >> 4;

        return P * 0.01f;//to hPa
    }

public:
    float pressure;
    float temperature;

private:
    I2C _i2c;
    Timeout tempTimer;
    Timeout pressTimer;
    int callFlag_temp;
    int callFlag_press;

    //気圧取得時にctrl_measレジスタに設定する値
    char ctrl_meas;
    //over sampling
    int oss;
    //変換にかかる時間[us]
    int convertion_time;
    short AC1;
    short AC2;
    short AC3;
    unsigned short AC4;
    unsigned short AC5;
    unsigned short AC6;
    short B1;
    short B2;
    short MB;
    short MC;
    short MD;
    //ビット演算ができるようにintでなくlong
    long UT;
    long UP;
    long X1;
    long X2;
    long B5;
    long T;

    long X3;
    long B3;
    unsigned long B4;
    long B6;
    unsigned long B7;
    long P;


    inline void writeReg(char addr, char data)
    {
        _i2c.write(addr, &data, 1, false);
    }

    inline void writeReg(char addr, char reg, char data)
    {
        char temp[2] = { reg, data };
        _i2c.write(addr, temp, 2, false);
    }

    inline char readReg(char addr, char reg)
    {
        char buff[1];
        writeReg(addr, reg);
        _i2c.read(addr | 1, buff, 1, true);
        return buff[0];
    }

    inline void readReg(char addr, char start_reg, char* buff, char num)
    {
        writeReg(addr, start_reg);
        _i2c.read(addr | 1, buff, num, true);
    }
};