BME280をI2CとSPIで使用するためのライブラリ。
Dependents: BNO055_BME280_ Yabusame2_gyro GRhanawaizman
Diff: BME280.cpp
- Revision:
- 0:2baa0f77d4d2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BME280.cpp Tue Nov 29 02:58:53 2016 +0000 @@ -0,0 +1,722 @@ +#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; +}