BME280をI2CとSPIで使用するためのライブラリ。

Dependents:   BNO055_BME280_ Yabusame2_gyro GRhanawaizman

BME280.cpp

Committer:
Yajirushi
Date:
2016-11-29
Revision:
0:2baa0f77d4d2

File content as of revision 0:2baa0f77d4d2:

#include "BME280.h"

//ショートカット
#define CS_ACTIVE cs->write(0)
#define CS_INACTIVE cs->write(1)

BME280_CTRL::BME280_CTRL(){
    interface_mode = 0;
}

BME280_CTRL::~BME280_CTRL(){}

char BME280_CTRL::getInterfaceMode(){
    return interface_mode;
}

void BME280_CTRL::init(){}
char BME280_CTRL::rr(char regAddr){return 0x00;}
char BME280_CTRL::rrc(char startRegAddr, char *receiveBytes, char length){return 0x00;}
char BME280_CTRL::wr(char regAddr, char wBytes){return 0x00;}
















BME280_SPI_CTRL::BME280_SPI_CTRL(SPI* si, DigitalOut* spi_cs, unsigned int speedHz){
    iface = si;
    cs = spi_cs;
    speed = speedHz;
    interface_mode = 1;
}

BME280_SPI_CTRL::~BME280_SPI_CTRL(){
    delete iface;
    delete cs;
}

void BME280_SPI_CTRL::init(){
    CS_INACTIVE;

    iface->format(8, 3);
    iface->frequency(speed);
    wait_ms(5);
}

char BME280_SPI_CTRL::rr(char regAddr){
    char ret = 0xFF;

    //CS立ち下げ
    CS_ACTIVE;

    //読み取りモードでレジスタ指定
    iface->write(0x80 | (regAddr & 0x7F));

    //返答のためダミー送信
    ret = iface->write(0x00);

    //CS立ち上げ
    CS_INACTIVE;

    return ret;
}

char BME280_SPI_CTRL::rrc(char startRegAddr, char *receiveBytes, char length){
    //最大連続読み取りは42byteまで
    if(length < 0 || length > 42) return -1;

    //CS立ち下げ
    CS_ACTIVE;

    //読み取りモードでレジスタ指定
    iface->write(0x80 | (startRegAddr & 0x7F));

    //返答のためlengthの数だけダミー送信
    for(int i=0; i<length; i++){
        receiveBytes[i] = iface->write(0x00);
    }

    //CS立ち上げ
    CS_INACTIVE;

    return 1;
}

char BME280_SPI_CTRL::wr(char regAddr, char wBytes){
    char ret = 0xFF;

    //CS立ち下げ
    CS_ACTIVE;

    //書き込みモードでレジスタ指定
    iface->write(regAddr & 0x7F);

    //値を書き込み
    ret = iface->write(wBytes);

    //CS立ち上げ
    CS_INACTIVE;

    //3-WIRE SPI判定
    if(regAddr == BME280R_CONFIG){
        interface_mode = (wBytes & 0x01)? 2 : 1;
    }

    return ret;
}
















BME280_I2C_CTRL::BME280_I2C_CTRL(I2C* iic, char addr, unsigned int freq){
    iface = iic;
    i2c_writeAddr = addr << 1;
    i2c_readAddr = i2c_writeAddr + 1;
    i2c_freq = freq;
}

BME280_I2C_CTRL::~BME280_I2C_CTRL(){
    delete iface;
}

void BME280_I2C_CTRL::init(){
    iface->frequency(i2c_freq);
    wait_ms(5);
}

char BME280_I2C_CTRL::rr(char regAddr){
    char ary[2];

    ary[0] = regAddr;
    ary[1] = 0x00;

    iface->write(i2c_writeAddr, ary, 1);
    iface->read(i2c_readAddr, ary, 1);

    return ary[0];
}

char BME280_I2C_CTRL::rrc(char startRegAddr, char *receiveBytes, char length){
    //最大連続読み取りは42byteまで
    if(length < 0 || length > 42) return -1;

    char ary[2];

    ary[0] = startRegAddr;
    ary[1] = 0x00;

    iface->write(i2c_writeAddr, ary, 1);
    iface->read(i2c_readAddr, receiveBytes, length);

    return 1;
}

char BME280_I2C_CTRL::wr(char regAddr, char wBytes){
    char ary[2];

    ary[0] = regAddr;
    ary[1] = wBytes;

    iface->write(i2c_writeAddr, ary, 2);

    return 1;
}

















BOARDC_BME280::BOARDC_BME280(PinName mosi, PinName miso, PinName sck, PinName scs, unsigned int spdHz){
    ctrl = new BME280_SPI_CTRL(new SPI(mosi, miso, sck), new DigitalOut(scs), spdHz);
}

BOARDC_BME280::BOARDC_BME280(SPI* spi, PinName scs, unsigned int spdHz){
    ctrl = new BME280_SPI_CTRL(spi, new DigitalOut(scs), spdHz);
}

BOARDC_BME280::BOARDC_BME280(SPI* spi, DigitalOut* spi_cs, unsigned int spdHz){
    ctrl = new BME280_SPI_CTRL(spi, spi_cs, spdHz);
}

BOARDC_BME280::BOARDC_BME280(PinName sda, PinName scl, char addr, unsigned int freq){
    ctrl = new BME280_I2C_CTRL(new I2C(sda, scl), addr, freq);
}

BOARDC_BME280::BOARDC_BME280(I2C* iic, char addr, unsigned int freq){
    ctrl = new BME280_I2C_CTRL(iic, addr, freq);
}

void BOARDC_BME280::initialize(bool initIface){
    if(initIface){
        ctrl->init();
    }

    //設定書き込み(必ずCTRL_HUM→CTRL_MEAS→CONFIGの順に設定)
    ctrl->wr(BME280R_CTRL_HUM, 0x01); //湿度:オーバーサンプリングx1
    ctrl->wr(BME280R_CTRL_MEAS, 0x27); //温度:オーバーサンプリングx1,気圧:オーバーサンプリングx1,ノーマルモード
    ctrl->wr(BME280R_CONFIG, 0xD4); //データ抽出可能時間1000ms,フィルターサンプリングx4

    //3-WIRE SPI使用時(BME280R_CONFIGに設定する値の最下位ビットを1にすると3-WIRE SPIモード)
    //ctrl->wr(BME280R_CONFIG, 0xD5);

    //データがレジスタにコピーされるまで待つ
    while(!isReady()) wait_ms(500);

    //補正データ更新
    updateCalib();
}

char BOARDC_BME280::getInterfaceMode(){
    return ctrl->getInterfaceMode();
}

char BOARDC_BME280::getChipID(){
    return ctrl->rr(BME280R_ID);
}

void BOARDC_BME280::reset(){
    ctrl->wr(BME280R_RESET, 0xB6);
    wait_ms(1500);
    initialize();
}

char BOARDC_BME280::getCTRL_humidity(){
    return ctrl->rr(BME280R_CTRL_HUM);
}

void BOARDC_BME280::setCTRL_humidity(char regVal){
    char meas = ctrl->rr(BME280R_CTRL_MEAS);
    char config = ctrl->rr(BME280R_CONFIG);

    //必ずCTRL_HUM>CTRL_MEAS>CONFIGの順番
    ctrl->wr(BME280R_CTRL_HUM, regVal & 0x07);
    ctrl->wr(BME280R_CTRL_MEAS, meas);
    ctrl->wr(BME280R_CONFIG, config & 0xFD);
}

char BOARDC_BME280::getCTRL_measuring(){
    return ctrl->rr(BME280R_CTRL_MEAS);
}

void BOARDC_BME280::setCTRL_measuring(char regVal){
    char hum = ctrl->rr(BME280R_CTRL_HUM);
    char config = ctrl->rr(BME280R_CONFIG);

    //必ずCTRL_HUM>CTRL_MEAS>CONFIGの順番
    ctrl->wr(BME280R_CTRL_HUM, hum & 0x07);
    ctrl->wr(BME280R_CTRL_MEAS, regVal);
    ctrl->wr(BME280R_CONFIG, config & 0xFD);
}

unsigned int BOARDC_BME280::getOverSample_P(){
    char val = (ctrl->rr(BME280R_CTRL_MEAS) >> 2) & 0x07;

    switch(val){
        case 0:
            return 0;
        case 1:
            return 1;
        case 2:
            return 2;
        case 3:
            return 4;
        case 4:
            return 8;
        case 5:
            return 16;
        default:
            return 16;
    }
}

unsigned int BOARDC_BME280::getOverSample_T(){
    char val = (ctrl->rr(BME280R_CTRL_MEAS) >> 5) & 0x07;

    switch(val){
        case 0:
            return 0;
        case 1:
            return 1;
        case 2:
            return 2;
        case 3:
            return 4;
        case 4:
            return 8;
        case 5:
            return 16;
        default:
            return 16;
    }
}

unsigned int BOARDC_BME280::getOverSample_H(){
    char val = ctrl->rr(BME280R_CTRL_HUM) & 0x07;

    switch(val){
        case 0:
            return 0;
        case 1:
            return 1;
        case 2:
            return 2;
        case 3:
            return 4;
        case 4:
            return 8;
        case 5:
            return 16;
        default:
            return 16;
    }
}

void BOARDC_BME280::setOverSample_P(unsigned int oversampling){
    char hum = ctrl->rr(BME280R_CTRL_HUM);
    char meas = ctrl->rr(BME280R_CTRL_MEAS);
    char config = ctrl->rr(BME280R_CONFIG);

    char ovs = 0;
    switch(oversampling){
        case 0:
            ovs = 0;
            break;
        case 1:
            ovs = 1;
            break;
        case 2:
            ovs = 2;
            break;
        case 4:
            ovs = 3;
            break;
        case 8:
            ovs = 4;
            break;
        case 16:
            ovs = 5;
            break;
        default:
            ovs = 0;
    }

    meas = (meas & 0xE3) | (ovs << 2);

    //必ずCTRL_HUM>CTRL_MEAS>CONFIGの順番
    ctrl->wr(BME280R_CTRL_HUM, hum & 0x07);
    ctrl->wr(BME280R_CTRL_MEAS, meas);
    ctrl->wr(BME280R_CONFIG, config & 0xFD);
}

void BOARDC_BME280::setOverSample_T(unsigned int oversampling){
    char hum = ctrl->rr(BME280R_CTRL_HUM);
    char meas = ctrl->rr(BME280R_CTRL_MEAS);
    char config = ctrl->rr(BME280R_CONFIG);

    char ovs = 0;
    switch(oversampling){
        case 0:
            ovs = 0;
            break;
        case 1:
            ovs = 1;
            break;
        case 2:
            ovs = 2;
            break;
        case 4:
            ovs = 3;
            break;
        case 8:
            ovs = 4;
            break;
        case 16:
            ovs = 5;
            break;
        default:
            ovs = 0;
    }

    meas = (meas & 0x1F) | (ovs << 5);

    //必ずCTRL_HUM>CTRL_MEAS>CONFIGの順番
    ctrl->wr(BME280R_CTRL_HUM, hum & 0x07);
    ctrl->wr(BME280R_CTRL_MEAS, meas);
    ctrl->wr(BME280R_CONFIG, config & 0xFD);
}

void BOARDC_BME280::setOverSample_H(unsigned int oversampling){
    char meas = ctrl->rr(BME280R_CTRL_MEAS);
    char config = ctrl->rr(BME280R_CONFIG);

    char ovs = 0;
    switch(oversampling){
        case 0:
            ovs = 0;
            break;
        case 1:
            ovs = 1;
            break;
        case 2:
            ovs = 2;
            break;
        case 4:
            ovs = 3;
            break;
        case 8:
            ovs = 4;
            break;
        case 16:
            ovs = 5;
            break;
        default:
            ovs = 0;
    }

    //必ずCTRL_HUM>CTRL_MEAS>CONFIGの順番
    ctrl->wr(BME280R_CTRL_HUM, ovs);
    ctrl->wr(BME280R_CTRL_MEAS, meas);
    ctrl->wr(BME280R_CONFIG, config & 0xFD);
}

char BOARDC_BME280::getConfig(){
    return ctrl->rr(BME280R_CONFIG);
}

void BOARDC_BME280::setConfig(char regVal){
    char hum = ctrl->rr(BME280R_CTRL_HUM);
    char meas = ctrl->rr(BME280R_CTRL_MEAS);

    //必ずCTRL_HUM>CTRL_MEAS>CONFIGの順番
    ctrl->wr(BME280R_CTRL_HUM, hum & 0x07);
    ctrl->wr(BME280R_CTRL_MEAS, meas);
    ctrl->wr(BME280R_CONFIG, regVal & 0xFD);
}

char BOARDC_BME280::getStatus(){
    return ctrl->rr(BME280R_STATUS);
}

bool BOARDC_BME280::isReady(){
    return (ctrl->rr(BME280R_STATUS) == 0x00);
}

char BOARDC_BME280::getMode(){
    return ctrl->rr(BME280R_CTRL_MEAS) & 0x03;
}

void BOARDC_BME280::updateCalib(){
    char ary[33];
    memset(ary, 0, 33);

    //26byte+7byte連続読み取り
    //使用されないものはそのまま捨てる
    ctrl->rrc(BME280R_CALIB00, ary, 26);
    ctrl->rrc(BME280R_CALIB26, ary + 26, 7);

    T1 = (ary[1] << 8) | ary[0];
    T2 = (ary[3] << 8) | ary[2];
    T3 = (ary[5] << 8) | ary[4];

    P1 = (ary[7] << 8) | ary[6];
    P2 = (ary[9] << 8) | ary[8];
    P3 = (ary[11] << 8) | ary[10];
    P4 = (ary[13] << 8) | ary[12];
    P5 = (ary[15] << 8) | ary[14];
    P6 = (ary[17] << 8) | ary[16];
    P7 = (ary[19] << 8) | ary[18];
    P8 = (ary[21] << 8) | ary[20];
    P9 = (ary[23] << 8) | ary[22];

    H1 = ary[25];
    H2 = (ary[27] << 8) | ary[26];
    H3 = ary[28];
    H4 = (ary[30] & 0x0F) | (ary[29] << 4); //順番注意
    H5 = (ary[31] << 4) | (ary[30] >> 4);
    H6 = ary[32];
}

void BOARDC_BME280::updateCalibT(){
    char ary[6];
    memset(ary, 0, 6);

    //6byte連続読み取り
    ctrl->rrc(BME280R_CALIB00, ary, 6);

    T1 = (ary[1] << 8) | ary[0];
    T2 = (ary[3] << 8) | ary[2];
    T3 = (ary[5] << 8) | ary[4];
}

void BOARDC_BME280::updateCalibP(){
    char ary[18];
    memset(ary, 0, 18);

    //18byte連続読み取り
    ctrl->rrc(BME280R_CALIB06, ary, 18);

    P1 = (ary[1] << 8) | ary[0];
    P2 = (ary[3] << 8) | ary[2];
    P3 = (ary[5] << 8) | ary[4];
    P4 = (ary[7] << 8) | ary[6];
    P5 = (ary[9] << 8) | ary[8];
    P6 = (ary[11] << 8) | ary[10];
    P7 = (ary[13] << 8) | ary[12];
    P8 = (ary[15] << 8) | ary[14];
    P9 = (ary[17] << 8) | ary[16];
}

void BOARDC_BME280::updateCalibH(){
    char ary[7];
    memset(ary, 0, 7);

    //7byte連続読み取り
    ctrl->rrc(BME280R_CALIB26, ary, 7);

    H1 = ctrl->rr(BME280R_CALIB25);
    H2 = (ary[1] << 8) | ary[0];
    H3 = ary[2];
    H4 = (ary[4] & 0x0F) | (ary[3] << 4); //順番注意
    H5 = (ary[5] << 4) | (ary[4] >> 4);
    H6 = ary[6];
}

float BOARDC_BME280::getTemp(unsigned int mode){
    switch(mode){
        case 0:
            return getTemp_Celsius();
        case 1:
            return getTemp_Fahrenheit();
        case 2:
            return getTemp_Kelvin();
        default:
            return getTemp_Celsius();
    }
}

float BOARDC_BME280::getTemp_Celsius(){
    char ary[3];
    memset(ary, 0, 3);

    //3byte連続読み取り
    ctrl->rrc(BME280R_TEMP_MSB, ary, 3);
    signed int adc_T = (ary[0] << 12) | (ary[1] << 4) | (ary[2] >> 4);

    //Compensation formulas(データシートより)
    signed int var1, var2, T;
    var1 = ((((adc_T >> 3) - ((signed int)T1 << 1))) * ((signed int)T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((signed int)T1)) * ((adc_T >> 4) - ((signed int)T1))) >> 12) * ((signed int)T3)) >> 14;
    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;

    return (((float)T) / 100.0f);
}

float BOARDC_BME280::getTemp_Fahrenheit(){
    return ((getTemp_Celsius() * 9.0f) / 5.0f) + 32.0f;
}

float BOARDC_BME280::getTemp_Kelvin(){
    return getTemp_Celsius() + 273.15f;
}

float BOARDC_BME280::getPress(unsigned int mode){
    switch(mode){
        case 0:
            return getPress_Pascal();
        case 1:
            return getPress_hPa();
        case 2:
            return getPress_psi();
        default:
            return getPress_hPa();
    }
}

float BOARDC_BME280::getPress_Pascal(){
    char ary[3];
    memset(ary, 0, 3);

    //3byte連続読み取り
    ctrl->rrc(BME280R_PRESS_MSB, ary, 3);
    signed int adc_P = (ary[0] << 12) | (ary[1] << 4) | (ary[2] >> 4);

    //Compensation formulas(データシートより)
    signed int var1, var2;
    unsigned int p;
    var1 = (((signed int)t_fine) >> 1) - (signed int)64000;
    var2 = (((var1 >> 2) * (var1 >> 2)) >> 11 ) * ((signed int)P6);
    var2 = var2 + ((var1 * ((signed int)P5)) << 1);
    var2 = (var2 >> 2)+(((signed int)P4) << 16);
    var1 = (((P3 * (((var1 >> 2) * (var1 >> 2)) >> 13 )) >> 3) + ((((signed int)P2) * var1) >> 1)) >> 18;
    var1 =((((32768 + var1)) * ((signed int)P1)) >> 15);
    if (var1 == 0){
        return 0; // avoid exception caused by division by zero
    }
    p = (((unsigned int)(((signed int)1048576) - adc_P) - (var2 >> 12))) * 3125;
    if (p < 0x80000000){
        p = (p << 1) / ((unsigned int)var1);
    }else{
        p = (p / (unsigned int)var1) * 2;
    }
    var1 = (((signed int)P9) * ((signed int)(((p >> 3) * (p >> 3)) >> 13))) >> 12;
    var2 = (((signed int)(p >> 2)) * ((signed int)P8)) >> 13;
    p = (unsigned int)((signed int)p + ((var1 + var2 + P7) >> 4));

    return (float)(p * 1.0f);
}

float BOARDC_BME280::getPress_hPa(){
    return getPress_Pascal() / 100.0f;
}

float BOARDC_BME280::getPress_psi(){
    return getPress_Pascal() / 6894.757293168;
}

float BOARDC_BME280::getHum(){
    char ary[2];
    memset(ary, 0, 2);

    //2byte連続読み取り
    ctrl->rrc(BME280R_HUM_MSB, ary, 2);
    signed int adc_H = (ary[0] << 8) | ary[1];

    //Compensation formulas(データシートより)
    signed int v_x1_u32r;
    v_x1_u32r = (t_fine - ((signed int)76800));
    v_x1_u32r =
        (((((adc_H << 14) - (((signed int)H4) << 20) - (((signed int)H5) * v_x1_u32r)) +
        ((signed int)16384)) >> 15) * (((((((v_x1_u32r * ((signed int)H6)) >> 10) * (((v_x1_u32r *
        ((signed int)H3)) >> 11) + ((signed int)32768))) >> 10) + ((signed int)2097152)) *
        ((signed int)H2) + 8192) >> 14));
    v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((signed int)H1)) >> 4));
    v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
    v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);

    return (float)(((unsigned int)(v_x1_u32r >> 12)) / 1024.0f);
}

double BOARDC_BME280::getPress64(unsigned int mode){
    switch(mode){
        case 0:
            return getPress64_Pascal();
        case 1:
            return getPress64_hPa();
        case 2:
            return getPress64_psi();
        default:
            return getPress64_hPa();
    }
}

double BOARDC_BME280::getPress64_Pascal(){
    char ary[3];
    memset(ary, 0, 3);

    //3byte連続読み取り
    ctrl->rrc(BME280R_PRESS_MSB, ary, 3);
    signed int adc_P = (ary[0] << 16) | (ary[1] << 8) | ary[2];

    //倍精度での算出(データシートより)
    signed long long var1, var2, p;
    var1 = ((signed long long)t_fine) - 128000;
    var2 = var1 * var1 * (signed long long)P6;
    var2 = var2 + ((var1 * (signed long long)P5) << 17);
    var2 = var2 + (((signed long long)P4)<<35);
    var1 = ((var1 * var1 * (signed long long)P3) >> 8) + ((var1 * (signed long long)P2) << 12);
    var1 = (((((signed long long)1) << 47) + var1)) * ((signed long long)P1) >> 33;
    if (var1 == 0){
        return 0; // avoid exception caused by division by zero
    }
    p = 1048576 - adc_P;
    p = (((p<<31) - var2) * 3125) / var1;
    var1 = (((signed long long)P9) * (p >> 13) * (p >> 13)) >> 25;
    var2 = (((signed long long)P8) * p) >> 19;
    p = ((p + var1 + var2) >> 8) + (((signed long long)P7) << 4);

    return (double)((unsigned int)p / 256.0);
}

double BOARDC_BME280::getPress64_hPa(){
    return getPress64_Pascal() / 100.0;
}

double BOARDC_BME280::getPress64_psi(){
    return getPress64_Pascal() / 6894.757293168;
}