├── DFRobot_BME680.cpp ├── DFRobot_BME680.h ├── DFRobot_BME680_I2C.cpp ├── DFRobot_BME680_I2C.h ├── DFRobot_BME680_SPI.cpp ├── DFRobot_BME680_SPI.h ├── LICENSE ├── Python └── RaspberryPi │ ├── DFRobot_BME680.py │ ├── README.md │ ├── README_CN.md │ └── examples │ ├── demo_read_all_data.py │ └── demo_set_low_power.py ├── README.md ├── README_CN.md ├── bme680.c ├── bme680.h ├── bme680_defs.h ├── bsec_datatypes.h ├── bsec_integration.c ├── bsec_integration.h ├── bsec_interface.h ├── examples ├── DFRobot_BME680_I2C │ └── DFRobot_BME680_I2C.ino ├── DFRobot_BME680_SPI │ └── DFRobot_BME680_SPI.ino ├── IAQ_I2C │ └── IAQ_I2C.ino ├── IAQ_SPI │ └── IAQ_SPI.ino ├── README.md └── docs_for_iaq │ ├── BST-BME680-AN008-45.pdf │ └── esp8266 │ ├── eagle.app.v6.common.ld │ ├── libalgobsec.a │ └── platform.txt ├── keywords.txt ├── library.properties └── resources └── images └── SEN0248.png /DFRobot_BME680.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DFRobot_BME680.cpp 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | #include "DFRobot_BME680.h" 12 | 13 | static struct bme680_dev bme680_sensor; 14 | static struct bme680_field_data bme680_data; 15 | static uint8_t convertCmd = (0x05 << 5) | (0x05 << 2) | (0x01); 16 | static uint8_t iaqReady_ = 0; 17 | 18 | void bme680_outputReady(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, 19 | float humidity, float pressure, float raw_temperature, float raw_humidity, 20 | float gas, bsec_library_return_t bsec_status) 21 | { 22 | if(iaq_accuracy != 0) bme680_data.gas_index = iaq; 23 | bme680_data.temperature = temperature; 24 | bme680_data.humidity = humidity; 25 | bme680_data.pressure = pressure; 26 | if(iaq_accuracy != 0) iaqReady_ = 1; 27 | } 28 | 29 | 30 | void bme680_delay_ms(uint32_t period) 31 | { 32 | delay(period); 33 | } 34 | 35 | 36 | int64_t bme680_getus(void) 37 | { 38 | return (millis() * 1000); 39 | } 40 | 41 | 42 | DFRobot_BME680::DFRobot_BME680(bme680_com_fptr_t readReg, bme680_com_fptr_t writeReg, 43 | bme680_delay_fptr_t delayMS, eBME680_INTERFACE interface) 44 | { 45 | bme680_sensor.read = readReg; 46 | bme680_sensor.write = writeReg; 47 | bme680_sensor.delay_ms = delayMS; 48 | switch(interface) { 49 | case eBME680_INTERFACE_I2C: bme680_sensor.intf = BME680_I2C_INTF; break; 50 | case eBME680_INTERFACE_SPI: bme680_sensor.intf = BME680_SPI_INTF; break; 51 | } 52 | } 53 | 54 | 55 | int16_t DFRobot_BME680::begin(void) 56 | { 57 | bme680_sensor.dev_id = this->bme680_I2CAddr; 58 | if(bme680_init(&bme680_sensor) != BME680_OK) { 59 | return -1; 60 | } 61 | uint8_t set_required_settings; 62 | int8_t rslt = 0; 63 | 64 | /* Set the temperature, pressure and humidity settings */ 65 | //bme680_sensor.tph_sett.os_hum = BME680_OS_2X; 66 | //bme680_sensor.tph_sett.os_pres = BME680_OS_4X; 67 | //bme680_sensor.tph_sett.os_temp = BME680_OS_8X; 68 | //bme680_sensor.tph_sett.filter = BME680_FILTER_SIZE_3; 69 | 70 | 71 | bme680_sensor.tph_sett.os_hum = 5; 72 | bme680_sensor.tph_sett.os_pres = 5; 73 | bme680_sensor.tph_sett.os_temp = 5; 74 | bme680_sensor.tph_sett.filter = 4; 75 | 76 | /* Set the remaining gas sensor settings and link the heating profile */ 77 | bme680_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS; 78 | /* Create a ramp heat waveform in 3 steps */ 79 | bme680_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */ 80 | bme680_sensor.gas_sett.heatr_dur = 150; /* milliseconds */ 81 | 82 | /* Select the power mode */ 83 | /* Must be set before writing the sensor configuration */ 84 | bme680_sensor.power_mode = BME680_FORCED_MODE; 85 | 86 | /* Set the required sensor settings needed */ 87 | set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL 88 | | BME680_GAS_SENSOR_SEL; 89 | 90 | /* Set the desired sensor configuration */ 91 | rslt = bme680_set_sensor_settings(set_required_settings, &bme680_sensor); 92 | 93 | /* Set the power mode */ 94 | rslt = bme680_set_sensor_mode(&bme680_sensor); 95 | 96 | /* Get the total measurement duration so as to sleep or wait till the 97 | * measurement is complete */ 98 | uint16_t meas_period; 99 | bme680_get_profile_dur(&meas_period, &bme680_sensor); 100 | bme680_sensor.delay_ms(meas_period); /* Delay till the measurement is ready */ 101 | return 0; 102 | } 103 | 104 | 105 | void DFRobot_BME680::startConvert(void) 106 | { 107 | bme680_sensor.write(bme680_sensor.dev_id, 0x74, &convertCmd, 1); 108 | } 109 | 110 | 111 | void DFRobot_BME680::update(void) 112 | { 113 | bme680_get_sensor_data(&bme680_data, &bme680_sensor); 114 | } 115 | 116 | 117 | int8_t DFRobot_BME680::iaqUpdate(void) 118 | { 119 | uint8_t gasBuf[2] = {0}; 120 | uint16_t gasADC = 0; 121 | uint8_t gasRange = 0; 122 | if(bsec_iot_loop(bme680_delay_ms, bme680_getus, bme680_outputReady) == 0) { 123 | bme680_get_regs(0x2a, gasBuf, 2, &bme680_sensor); 124 | gasADC = (uint16_t) ((uint32_t) gasBuf[0] * 4 | (((uint32_t) gasBuf[1]) / 64)); 125 | gasRange = gasBuf[1] & BME680_GAS_RANGE_MSK; 126 | bme680_data.gas_resistance = calc_gas_resistance(gasADC, gasRange, &bme680_sensor); 127 | return 0; 128 | } 129 | return 1; 130 | } 131 | 132 | 133 | float DFRobot_BME680::readTemperature(void) 134 | { 135 | return bme680_data.temperature; 136 | } 137 | 138 | 139 | float DFRobot_BME680::readPressure(void) 140 | { 141 | return bme680_data.pressure; 142 | } 143 | 144 | 145 | float DFRobot_BME680::readHumidity(void) 146 | { 147 | return bme680_data.humidity; 148 | } 149 | 150 | 151 | float DFRobot_BME680::readAltitude(void) 152 | { 153 | return (1.0 - pow((float)bme680_data.pressure / 100.0f / BME680_SEALEVEL, 0.190284)) * 287.15 / 0.0065; 154 | } 155 | 156 | 157 | float DFRobot_BME680::readCalibratedAltitude(float seaLevel) 158 | { 159 | //data->altitude = 44330.0 * (1.0 - pow((float) data->pressure / 100.0f / BME680_SEALEVEL, 0.1903)); 160 | return (1.0 - pow((float) bme680_data.pressure / seaLevel, 0.190284)) * 287.15 / 0.0065; 161 | } 162 | 163 | 164 | float DFRobot_BME680::readGasResistance(void) 165 | { 166 | return bme680_data.gas_resistance; 167 | } 168 | 169 | 170 | float DFRobot_BME680::readSeaLevel(float altitude) 171 | { 172 | return (bme680_data.pressure / pow(1.0 - (altitude / 44330.0), 5.255)); 173 | } 174 | 175 | 176 | float DFRobot_BME680::readIAQ(void) 177 | { 178 | return bme680_data.gas_index; 179 | } 180 | 181 | 182 | void DFRobot_BME680::setParam(eBME680_param_t eParam, uint8_t dat) 183 | { 184 | if(dat > 0x05) return; 185 | switch(eParam) { 186 | case eBME680_PARAM_TEMPSAMP: writeParamHelper(0x74, dat, 0x07 << 5); break; 187 | case eBME680_PARAM_PREESAMP: writeParamHelper(0x74, dat, 0x07 << 2); break; 188 | case eBME680_PARAM_HUMISAMP: writeParamHelper(0x72, dat, 0x07); break; 189 | case eBME680_PARAM_IIRSIZE: writeParamHelper(0x75, dat, 0x07 << 2); break; 190 | } 191 | } 192 | 193 | 194 | void DFRobot_BME680::setGasHeater(uint16_t temp, uint16_t t) 195 | { 196 | bme680_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */ 197 | bme680_sensor.gas_sett.heatr_dur = 150; /* milliseconds */ 198 | uint8_t set_required_settings = BME680_GAS_SENSOR_SEL; 199 | bme680_set_sensor_settings(set_required_settings, &bme680_sensor); 200 | } 201 | 202 | 203 | uint8_t DFRobot_BME680::isIAQReady(void) 204 | { 205 | return iaqReady_; 206 | } 207 | 208 | 209 | void DFRobot_BME680::writeParamHelper(uint8_t reg, uint8_t dat, uint8_t addr) 210 | { 211 | uint8_t var1 = 0; 212 | uint8_t addrCount = 0; 213 | if(bme680_sensor.intf == BME680_SPI_INTF) bme680_sensor.write(bme680_sensor.dev_id, 0x73, 0x00, 1); 214 | bme680_sensor.read(bme680_sensor.dev_id, reg, &var1, 1); 215 | var1 &= ~addr; 216 | while(!(addr & 0x01)) { 217 | addrCount ++; 218 | addr >>= 1; 219 | } 220 | var1 |= dat << addrCount; 221 | bme680_sensor.write(bme680_sensor.dev_id, reg, &var1, 1); 222 | } 223 | 224 | -------------------------------------------------------------------------------- /DFRobot_BME680.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DFRobot_BME680.h 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | 12 | #ifndef DFROBOT_BME680_H 13 | #define DFROBOT_BME680_H 14 | 15 | #include "Arduino.h" 16 | #include "SPI.h" 17 | #include "Wire.h" 18 | 19 | #include "bsec_integration.h" 20 | 21 | #define BME680_SEALEVEL 1015 22 | 23 | /**\name C standard macros */ 24 | #ifndef NULL 25 | #ifdef __cplusplus 26 | #define NULL 0 27 | #else 28 | #define NULL ((void *) 0) 29 | #endif 30 | #endif 31 | 32 | enum eBME680_INTERFACE { 33 | eBME680_INTERFACE_SPI, 34 | eBME680_INTERFACE_I2C 35 | }; 36 | 37 | typedef void (*pfStartConvert_t)(void); 38 | typedef void (*pfUpdate_t)(void); 39 | 40 | #define supportIAQ() setConvertAndUpdate(); 41 | 42 | void bme680_delay_ms(uint32_t period); 43 | int64_t bme680_getus(void); 44 | 45 | void bme680_outputReady(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity, 46 | float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status); 47 | 48 | typedef enum { 49 | eBME680_PARAM_TEMPSAMP, 50 | eBME680_PARAM_HUMISAMP, 51 | eBME680_PARAM_PREESAMP, 52 | eBME680_PARAM_IIRSIZE 53 | } eBME680_param_t; 54 | 55 | class DFRobot_BME680 56 | { 57 | public: 58 | DFRobot_BME680(bme680_com_fptr_t readReg, bme680_com_fptr_t writeReg, bme680_delay_fptr_t delayMS, eBME680_INTERFACE interface); 59 | uint8_t bme680_I2CAddr = 0; 60 | /** 61 | * @fn begin 62 | * @brief begin BME680 device 63 | * @return result 64 | * @retval non-zero : falid 65 | * @retval 0 : succussful 66 | */ 67 | int16_t begin(void); 68 | /** 69 | * @fn update 70 | * @brief update all data to MCU ram 71 | */ 72 | void update(void); 73 | /** 74 | * @fn iaqUpdate 75 | * @brief update all data to MCU ram with IAQ (only for esp8266 now) 76 | * 77 | * @return result: 78 | * @retval 0 :complete 79 | * @retval 1 :busy 80 | */ 81 | int8_t iaqUpdate(void); 82 | /** 83 | * @fn startConvert 84 | * @brief start convert to get a accurate values 85 | */ 86 | void startConvert(void); 87 | /** 88 | * @fn readTemperature 89 | * @brief read the temperature value (unit C) 90 | * 91 | * @return temperature valu, this value has two decimal points 92 | */ 93 | float readTemperature(void); 94 | /** 95 | * @fn readPressure 96 | * @brief read the pressure value (unit pa) 97 | * 98 | * @return pressure value, this value has two decimal points 99 | */ 100 | float readPressure(void); 101 | /** 102 | * @fn readHumidity 103 | * @brief read the humidity value (unit %rh) 104 | * @return humidity value, this value has two decimal points 105 | */ 106 | float readHumidity(void); 107 | /** 108 | * @fn readAltitude 109 | * @brief read the altitude (unit meter) 110 | * @return altitude value, this value has two decimal points 111 | */ 112 | float readAltitude(void); 113 | /** 114 | * @fn readCalibratedAltitude 115 | * @brief read the Calibrated altitude (unit meter) 116 | * 117 | * @param seaLevel normalised atmospheric pressure 118 | * 119 | * @return calibrated altitude value , this value has two decimal points 120 | */ 121 | float readCalibratedAltitude(float seaLevel); 122 | /** 123 | * @fn readGasResistance 124 | * @brief read the gas resistance(unit ohm) 125 | * @return temperature value, this value has two decimal points 126 | */ 127 | float readGasResistance(void); 128 | /** 129 | * @fn readSeaLevel 130 | * @brief read normalised atmospheric pressure (unit pa) 131 | * @param altitude accurate altitude for normalising 132 | * @return normalised atmospheric pressure 133 | */ 134 | float readSeaLevel(float altitude); 135 | /** 136 | * @fn readIAQ 137 | * @brief read IAQ 138 | * @return The result of IAQ 139 | */ 140 | float readIAQ(void); 141 | /** 142 | * @fn setParam 143 | * @brief set bme680 parament 144 | * 145 | * @param eParam :which param you want to change 146 | * dat :object data, can't more than 5 147 | */ 148 | void setParam(eBME680_param_t eParam, uint8_t dat); 149 | /** 150 | * @fn setGasHeater 151 | * @brief set bme680 gas heater 152 | * @param temp :your object temp 153 | * @param t :time spend in milliseconds 154 | */ 155 | void setGasHeater(uint16_t temp, uint16_t t); 156 | /** 157 | * @fn isIAQReady 158 | * @brief check IAQ ready 159 | * @return result: 160 | * @retval 0 :ready 161 | * @retval 1 :not ready 162 | */ 163 | uint8_t isIAQReady(void); 164 | 165 | private: 166 | void writeParamHelper(uint8_t reg, uint8_t dat, uint8_t addr); 167 | }; 168 | 169 | #endif 170 | 171 | 172 | -------------------------------------------------------------------------------- /DFRobot_BME680_I2C.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DFRobot_BME680_I2C.cpp 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | 12 | #include "DFRobot_BME680_I2C.h" 13 | 14 | 15 | static int8_t bme680_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) 16 | { 17 | Wire.begin(); 18 | Wire.beginTransmission(dev_id); 19 | Wire.write(reg_addr); 20 | Wire.endTransmission(); 21 | Wire.requestFrom(dev_id, (uint8_t)len); 22 | while(Wire.available()) { 23 | *data = Wire.read(); 24 | data ++; 25 | } 26 | return 0; 27 | } 28 | 29 | 30 | static int8_t bme680_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) 31 | { 32 | Wire.begin(); 33 | Wire.beginTransmission(dev_id); 34 | Wire.write(reg_addr); 35 | while(len --) { 36 | Wire.write(*data); 37 | data ++; 38 | } 39 | Wire.endTransmission(); 40 | return 0; 41 | } 42 | 43 | 44 | DFRobot_BME680_I2C::DFRobot_BME680_I2C(uint8_t I2CAddr_) : 45 | DFRobot_BME680(bme680_i2c_read, bme680_i2c_write, bme680_delay_ms, eBME680_INTERFACE_I2C) 46 | { 47 | bme680_I2CAddr = I2CAddr_; 48 | } 49 | 50 | 51 | void DFRobot_BME680_I2C::setConvertAndUpdate() 52 | { 53 | bsec_iot_init(0.33333f, 0, bme680_i2c_write, bme680_i2c_read, bme680_delay_ms, bme680_I2CAddr, BME680_I2C_INTF); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /DFRobot_BME680_I2C.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DFRobot_BME680_I2C.h 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | 12 | #ifndef DFRobot_BME680_I2C_H 13 | #define DFRobot_BME680_I2C_H 14 | 15 | #include "DFRobot_BME680.h" 16 | 17 | 18 | class DFRobot_BME680_I2C : public DFRobot_BME680 19 | { 20 | public: 21 | DFRobot_BME680_I2C(uint8_t I2CAddr); 22 | 23 | void setConvertAndUpdate(void); 24 | }; 25 | 26 | #endif -------------------------------------------------------------------------------- /DFRobot_BME680_SPI.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DFRobot_BME680_SPI.cpp 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | #include "DFRobot_BME680_SPI.h" 12 | 13 | static uint8_t bme680_cs = 0; 14 | 15 | 16 | static int8_t bme680_spi_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) 17 | { 18 | SPI.begin(); 19 | SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); 20 | digitalWrite(bme680_cs, 0); 21 | SPI.transfer(reg_addr | 0x80); 22 | while(len --) { 23 | *data = SPI.transfer(0x00); 24 | data ++; 25 | } 26 | digitalWrite(bme680_cs, 1); 27 | SPI.endTransaction(); 28 | return 0; 29 | } 30 | 31 | 32 | static int8_t bme680_spi_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) 33 | { 34 | SPI.begin(); 35 | SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); 36 | digitalWrite(bme680_cs, 0); 37 | SPI.transfer(reg_addr); 38 | while(len --) { 39 | SPI.transfer(*data); 40 | data ++; 41 | } 42 | digitalWrite(bme680_cs, 1); 43 | SPI.endTransaction(); 44 | return 0; 45 | } 46 | 47 | 48 | DFRobot_BME680_SPI::DFRobot_BME680_SPI(uint8_t pin_cs) : 49 | DFRobot_BME680(bme680_spi_read, bme680_spi_write, bme680_delay_ms, eBME680_INTERFACE_SPI) 50 | { 51 | bme680_cs = pin_cs; 52 | pinMode(bme680_cs, OUTPUT); 53 | digitalWrite(bme680_cs, 1); 54 | } 55 | 56 | 57 | void DFRobot_BME680_SPI::setConvertAndUpdate() 58 | { 59 | bsec_iot_init(0.33333f, 0, bme680_spi_write, bme680_spi_read, bme680_delay_ms, 0x77, BME680_SPI_INTF); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /DFRobot_BME680_SPI.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DFRobot_BME680_SPI.h 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | 12 | #ifndef DFROBOT_BME680_SPI_H 13 | #define DFROBOT_BME680_SPI_H 14 | 15 | #include "DFRobot_BME680.h" 16 | 17 | class DFRobot_BME680_SPI : public DFRobot_BME680 18 | { 19 | public: 20 | DFRobot_BME680_SPI(uint8_t pin_cs); 21 | 22 | void setConvertAndUpdate(void); 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 DFRobot Co.Ltd 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Python/RaspberryPi/DFRobot_BME680.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from __future__ import print_function 3 | 4 | 5 | '''! 6 | @file DFRobot_BME680.py 7 | @brief BME680 is an integrated environmental sensor developed specifically for mobile applications and wearables 8 | @n where size and low power consumption are key requirements. Expanding Bosch Sensortec’s existing family of environmental sensors, 9 | @n the BME680 integrates for the first time individual high linearity and high accuracy sensors for gas, pressure, humidity and temperature. 10 | @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 11 | @license The MIT License (MIT) 12 | @author [luoyufeng](yufeng.luo@dfrobot.com) 13 | @version V1.0 14 | @date 2022-02-09 15 | @url https://github.com/DFRobot/DFRobot_BME680 16 | ''' 17 | 18 | 19 | 20 | import time 21 | import smbus 22 | import math 23 | 24 | # BME680 I2C addresses 25 | _BME680_I2C_ADDR_PRIMARY = 0x76 26 | _BME680_I2C_ADDR_SECONDARY = 0x77 27 | 28 | # BME680 unique chip identifier 29 | _BME680_CHIP_ID = 0x61 30 | 31 | # BME680 coefficients related defines 32 | _BME680_COEFF_SIZE = 41 33 | _BME680_COEFF_ADDR1_LEN = 25 34 | _BME680_COEFF_ADDR2_LEN = 16 35 | 36 | # BME680 field_x related defines 37 | _BME680_FIELD_LENGTH = 15 38 | _BME680_FIELD_ADDR_OFFSET = 17 39 | 40 | # BME680 coefficients related defines 41 | _BME680_COEFF_SIZE = 41 42 | _BME680_COEFF_ADDR1_LENCOEFF_ADDR1_LEN = 25 43 | _BME680_COEFF_ADDR2_LENCOEFF_ADDR2_LEN = 16 44 | 45 | # BME680 field_x related defines 46 | _BME680_FIELD_LENGTHFIELD_LENGTH = 15 47 | _BME680_FIELD_ADDR_OFFSETFIELD_ADDR_OFFSET = 17 48 | 49 | # Soft reset command 50 | _BME680_SOFT_RESET_CMD = 0xb6 51 | 52 | # Error code definitions 53 | _BME680_OK = 0 54 | # Errors 55 | _BME680_E_NULL_PTR = -1 56 | _BME680_E_COM_FAIL = -2 57 | _BME680_E_DEV_NOT_FOUND = -3 58 | _BME680_E_INVALID_LENGTH = -4 59 | 60 | # Warnings 61 | _BME680_W_DEFINE_PWR_MODE = 1 62 | _BME680_W_NO_NEW_DATA = 2 63 | 64 | # Info's 65 | _BME680_I_MIN_CORRECTION = 1 66 | _BME680_I_MAX_CORRECTION = 2 67 | 68 | # Register map 69 | # Other coefficient's address 70 | _BME680_ADDR_RES_HEAT_VAL_ADDR = 0x00 71 | _BME680_ADDR_RES_HEAT_RANGE_ADDR = 0x02 72 | _BME680_ADDR_RANGE_SW_ERR_ADDR = 0x04 73 | _BME680_ADDR_SENS_CONF_START = 0x5A 74 | _BME680_ADDR_GAS_CONF_START = 0x64 75 | 76 | # Field settings 77 | _BME680_FIELD0_ADDR = 0x1d 78 | 79 | # Heater settings 80 | _BME680_RES_HEAT0_ADDR = 0x5a 81 | _BME680_GAS_WAIT0_ADDR = 0x64 82 | 83 | # Sensor configuration registers 84 | _BME680_CONF_HEAT_CTRL_ADDR = 0x70 85 | _BME680_CONF_ODR_RUN_GAS_NBC_ADDR = 0x71 86 | _BME680_CONF_OS_H_ADDR = 0x72 87 | _BME680_MEM_PAGE_ADDR = 0xf3 88 | _BME680_CONF_T_P_MODE_ADDR = 0x74 89 | _BME680_CONF_ODR_FILT_ADDR = 0x75 90 | 91 | # Coefficient's address 92 | _BME680_COEFF_ADDR1 = 0x89 93 | _BME680_COEFF_ADDR2 = 0xe1 94 | 95 | # Chip identifier 96 | _BME680_CHIP_ID_ADDR = 0xd0 97 | 98 | # Soft reset register 99 | _BME680_SOFT_RESET_ADDR = 0xe0 100 | 101 | # Array Index to Field data mapping for Calibration Data 102 | _BME680_T2_LSB_REG = 1 103 | _BME680_T2_MSB_REG = 2 104 | _BME680_T3_REG = 3 105 | _BME680_P1_LSB_REG = 5 106 | _BME680_P1_MSB_REG = 6 107 | _BME680_P2_LSB_REG = 7 108 | _BME680_P2_MSB_REG = 8 109 | _BME680_P3_REG = 9 110 | _BME680_P4_LSB_REG = 11 111 | _BME680_P4_MSB_REG = 12 112 | _BME680_P5_LSB_REG = 13 113 | _BME680_P5_MSB_REG = 14 114 | _BME680_P7_REG = 15 115 | _BME680_P6_REG = 16 116 | _BME680_P8_LSB_REG = 19 117 | _BME680_P8_MSB_REG = 20 118 | _BME680_P9_LSB_REG = 21 119 | _BME680_P9_MSB_REG = 22 120 | _BME680_P10_REG = 23 121 | _BME680_H2_MSB_REG = 25 122 | _BME680_H2_LSB_REG = 26 123 | _BME680_H1_LSB_REG = 26 124 | _BME680_H1_MSB_REG = 27 125 | _BME680_H3_REG = 28 126 | _BME680_H4_REG = 29 127 | _BME680_H5_REG = 30 128 | _BME680_H6_REG = 31 129 | _BME680_H7_REG = 32 130 | _BME680_T1_LSB_REG = 33 131 | _BME680_T1_MSB_REG = 34 132 | _BME680_GH2_LSB_REG = 35 133 | _BME680_GH2_MSB_REG = 36 134 | _BME680_GH1_REG = 37 135 | _BME680_GH3_REG = 38 136 | 137 | # BME680 register buffer index settings 138 | _BME680_REG_FILTER_INDEX = 5 139 | _BME680_REG_TEMP_INDEX = 4 140 | _BME680_REG_PRES_INDEX = 4 141 | _BME680_REG_HUM_INDEX = 2 142 | _BME680_REG_NBCONV_INDEX = 1 143 | _BME680_REG_RUN_GAS_INDEX = 1 144 | _BME680_REG_HCTRL_INDEX = 0 145 | 146 | # Ambient humidity shift value for compensation 147 | _BME680_HUM_REG_SHIFT_VAL = 4 148 | 149 | # Delay related macro declaration 150 | _BME680_RESET_PERIOD = 10 151 | 152 | # SPI memory page settings 153 | _BME680_MEM_PAGE0 = 0x10 154 | _BME680_MEM_PAGE1 = 0x00 155 | 156 | # Run gas enable and disable settings 157 | _BME680_RUN_GAS_DISABLE = 0 158 | _BME680_RUN_GAS_ENABLE = 1 159 | 160 | # Buffer length macro declaration 161 | _BME680_TMP_BUFFER_LENGTH = 40 162 | _BME680_REG_BUFFER_LENGTH = 6 163 | _BME680_FIELD_DATA_LENGTH = 3 164 | _BME680_GAS_REG_BUF_LENGTH = 20 165 | _BME680_GAS_HEATER_PROF_LEN_MAX = 10 166 | 167 | # Settings selector 168 | _BME680_OST_SEL = 1 169 | _BME680_OSP_SEL = 2 170 | _BME680_OSH_SEL = 4 171 | _BME680_GAS_MEAS_SEL = 8 172 | _BME680_FILTER_SEL = 16 173 | _BME680_HCNTRL_SEL = 32 174 | _BME680_RUN_GAS_SEL = 64 175 | _BME680_NBCONV_SEL = 128 176 | _BME680_GAS_SENSOR_SEL = _BME680_GAS_MEAS_SEL | _BME680_RUN_GAS_SEL | _BME680_NBCONV_SEL 177 | 178 | # Number of conversion settings 179 | _BME680_NBCONV_MIN = 0 180 | _BME680_NBCONV_MAX = 9 # Was 10, but there are only 10 settings: 0 1 2 ... 8 9 181 | 182 | # Mask definitions 183 | _BME680_GAS_MEAS_MSK = 0x30 184 | _BME680_NBCONV_MSK = 0X0F 185 | _BME680_FILTER_MSK = 0X1C 186 | _BME680_OST_MSK = 0XE0 187 | _BME680_OSP_MSK = 0X1C 188 | _BME680_OSH_MSK = 0X07 189 | _BME680_HCTRL_MSK = 0x08 190 | _BME680_RUN_GAS_MSK = 0x10 191 | _BME680_MODE_MSK = 0x03 192 | _BME680_RHRANGE_MSK = 0x30 193 | _BME680_RSERROR_MSK = 0xf0 194 | _BME680_NEW_DATA_MSK = 0x80 195 | _BME680_GAS_INDEX_MSK = 0x0f 196 | _BME680_GAS_RANGE_MSK = 0x0f 197 | _BME680_GASM_VALID_MSK = 0x20 198 | _BME680_HEAT_STAB_MSK = 0x10 199 | _BME680_MEM_PAGE_MSK = 0x10 200 | _BME680_SPI_RD_MSK = 0x80 201 | _BME680_SPI_WR_MSK = 0x7f 202 | _BME680_BIT_H1_DATA_MSK = 0x0F 203 | 204 | # Bit position definitions for sensor settings 205 | _BME680_GAS_MEAS_POS = 4 206 | _BME680_FILTER_POS = 2 207 | _BME680_OST_POS = 5 208 | _BME680_OSP_POS = 2 209 | _BME680_OSH_POS = 0 210 | _BME680_RUN_GAS_POS = 4 211 | _BME680_MODE_POS = 0 212 | _BME680_NBCONV_POS = 0 213 | 214 | # Look up tables for the possible gas range values 215 | lookupTable1 = [2147483647, 2147483647, 2147483647, 2147483647, 216 | 2147483647, 2126008810, 2147483647, 2130303777, 2147483647, 217 | 2147483647, 2143188679, 2136746228, 2147483647, 2126008810, 218 | 2147483647, 2147483647] 219 | 220 | lookupTable2 = [4096000000, 2048000000, 1024000000, 512000000, 221 | 255744255, 127110228, 64000000, 32258064, 222 | 16016016, 8000000, 4000000, 2000000, 223 | 1000000, 500000, 250000, 125000] 224 | 225 | def bytes_to_word(msb, lsb, bits=16, signed=False): 226 | word = (msb << 8) | lsb 227 | if signed: 228 | word = twos_comp(word, bits) 229 | return word 230 | 231 | def twos_comp(val, bits=16): 232 | if val & (1 << (bits - 1)) != 0: 233 | val = val - (1 << bits) 234 | return val 235 | 236 | # Sensor field data structure 237 | 238 | class FieldData: 239 | def __init__(self): 240 | # Contains new_data, gasm_valid & heat_stab 241 | self.status = None 242 | self.heat_stable = False 243 | # The index of the heater profile used 244 | self.gas_index = None 245 | # Measurement index to track order 246 | self.meas_index = None 247 | # Temperature in degree celsius x100 248 | self.temperature = None 249 | # Pressure in Pascal 250 | self.pressure = None 251 | # Humidity in % relative humidity x1000 252 | self.humidity = None 253 | # Gas resistance in Ohms 254 | self.gas_resistance = None 255 | 256 | # Structure to hold the Calibration data 257 | 258 | class CalibrationData: 259 | def __init__(self): 260 | self.par_h1 = None 261 | self.par_h2 = None 262 | self.par_h3 = None 263 | self.par_h4 = None 264 | self.par_h5 = None 265 | self.par_h6 = None 266 | self.par_h7 = None 267 | self.par_gh1 = None 268 | self.par_gh2 = None 269 | self.par_gh3 = None 270 | self.par_t1 = None 271 | self.par_t2 = None 272 | self.par_t3 = None 273 | self.par_p1 = None 274 | self.par_p2 = None 275 | self.par_p3 = None 276 | self.par_p4 = None 277 | self.par_p5 = None 278 | self.par_p6 = None 279 | self.par_p7 = None 280 | self.par_p8 = None 281 | self.par_p9 = None 282 | self.par_p10 = None 283 | # Variable to store t_fine size 284 | self.t_fine = None 285 | # Variable to store heater resistance range 286 | self.res_heat_range = None 287 | # Variable to store heater resistance value 288 | self.res_heat_val = None 289 | # Variable to store error range 290 | self.range_sw_err = None 291 | 292 | def set_from_array(self, calibration): 293 | # Temperature related coefficients 294 | self.par_t1 = bytes_to_word(calibration[_BME680_T1_MSB_REG], calibration[_BME680_T1_LSB_REG]) 295 | self.par_t2 = bytes_to_word(calibration[_BME680_T2_MSB_REG], calibration[_BME680_T2_LSB_REG], bits=16, signed=True) 296 | self.par_t3 = twos_comp(calibration[_BME680_T3_REG], bits=8) 297 | 298 | # Pressure related coefficients 299 | self.par_p1 = bytes_to_word(calibration[_BME680_P1_MSB_REG], calibration[_BME680_P1_LSB_REG]) 300 | self.par_p2 = bytes_to_word(calibration[_BME680_P2_MSB_REG], calibration[_BME680_P2_LSB_REG], bits=16, signed=True) 301 | self.par_p3 = twos_comp(calibration[_BME680_P3_REG], bits=8) 302 | self.par_p4 = bytes_to_word(calibration[_BME680_P4_MSB_REG], calibration[_BME680_P4_LSB_REG], bits=16, signed=True) 303 | self.par_p5 = bytes_to_word(calibration[_BME680_P5_MSB_REG], calibration[_BME680_P5_LSB_REG], bits=16, signed=True) 304 | self.par_p6 = twos_comp(calibration[_BME680_P6_REG], bits=8) 305 | self.par_p7 = twos_comp(calibration[_BME680_P7_REG], bits=8) 306 | self.par_p8 = bytes_to_word(calibration[_BME680_P8_MSB_REG], calibration[_BME680_P8_LSB_REG], bits=16, signed=True) 307 | self.par_p9 = bytes_to_word(calibration[_BME680_P9_MSB_REG], calibration[_BME680_P9_LSB_REG], bits=16, signed=True) 308 | self.par_p10 = calibration[_BME680_P10_REG] 309 | 310 | # Humidity related coefficients 311 | self.par_h1 = (calibration[_BME680_H1_MSB_REG] << _BME680_HUM_REG_SHIFT_VAL) | (calibration[_BME680_H1_LSB_REG] & _BME680_BIT_H1_DATA_MSK) 312 | self.par_h2 = (calibration[_BME680_H2_MSB_REG] << _BME680_HUM_REG_SHIFT_VAL) | (calibration[_BME680_H2_LSB_REG] >> _BME680_HUM_REG_SHIFT_VAL) 313 | self.par_h3 = twos_comp(calibration[_BME680_H3_REG], bits=8) 314 | self.par_h4 = twos_comp(calibration[_BME680_H4_REG], bits=8) 315 | self.par_h5 = twos_comp(calibration[_BME680_H5_REG], bits=8) 316 | self.par_h6 = calibration[_BME680_H6_REG] 317 | self.par_h7 = twos_comp(calibration[_BME680_H7_REG], bits=8) 318 | 319 | # Gas heater related coefficients 320 | self.par_gh1 = twos_comp(calibration[_BME680_GH1_REG], bits=8) 321 | self.par_gh2 = bytes_to_word(calibration[_BME680_GH2_MSB_REG], calibration[_BME680_GH2_LSB_REG], bits=16, signed=True) 322 | self.par_gh3 = twos_comp(calibration[_BME680_GH3_REG], bits=8) 323 | 324 | def set_other(self, heat_range, heat_value, sw_error): 325 | self.res_heat_range = (heat_range & _BME680_RHRANGE_MSK) // 16 326 | self.res_heat_val = heat_value 327 | self.range_sw_err = (sw_error & _BME680_RSERROR_MSK) // 16 328 | 329 | # BME680 sensor settings structure which comprises of ODR, 330 | # over-sampling and filter settings. 331 | 332 | class TPHSettings: 333 | def __init__(self): 334 | # Humidity oversampling 335 | self.os_hum = None 336 | # Temperature oversampling 337 | self.os_temp = None 338 | # Pressure oversampling 339 | self.os_pres = None 340 | # Filter coefficient 341 | self.filter = None 342 | 343 | # BME680 gas sensor which comprises of gas settings 344 | ## and status parameters 345 | 346 | class GasSettings: 347 | def __init__(self): 348 | # Variable to store nb conversion 349 | self.nb_conv = None 350 | # Variable to store heater control 351 | self.heatr_ctrl = None 352 | # Run gas enable value 353 | self.run_gas = None 354 | # Pointer to store heater temperature 355 | self.heatr_temp = None 356 | # Pointer to store duration profile 357 | self.heatr_dur = None 358 | 359 | # BME680 device structure 360 | 361 | class BME680Data: 362 | def __init__(self): 363 | # Chip Id 364 | self.chip_id = None 365 | # Device Id 366 | self.dev_id = None 367 | # SPI/I2C interface 368 | self.intf = None 369 | # Memory page used 370 | self.mem_page = None 371 | # Ambient temperature in Degree C 372 | self.ambient_temperature = None 373 | # Field Data 374 | self.data = FieldData() 375 | # Sensor calibration data 376 | self.calibration_data = CalibrationData() 377 | # Sensor settings 378 | self.tph_settings = TPHSettings() 379 | # Gas Sensor settings 380 | self.gas_settings = GasSettings() 381 | # Sensor power modes 382 | self.power_mode = None 383 | # New sensor fields 384 | self.new_fields = None 385 | 386 | 387 | class DFRobot_BME680(BME680Data): 388 | 389 | # Heater control settings 390 | ENABLE_HEATER = 0x00 391 | DISABLE_HEATER = 0x08 392 | 393 | # Gas measurement settings 394 | DISABLE_GAS_MEAS = 0x00 395 | ENABLE_GAS_MEAS = 0x01 396 | 397 | # Over-sampling settings 398 | OS_NONE = 0 399 | OS_1X = 1 400 | OS_2X = 2 401 | OS_4X = 3 402 | OS_8X = 4 403 | OS_16X = 5 404 | 405 | # IIR filter settings 406 | FILTER_SIZE_0 = 0 407 | FILTER_SIZE_1 = 1 408 | FILTER_SIZE_3 = 2 409 | FILTER_SIZE_7 = 3 410 | FILTER_SIZE_15 = 4 411 | FILTER_SIZE_31 = 5 412 | FILTER_SIZE_63 = 6 413 | FILTER_SIZE_127 = 7 414 | 415 | # Power mode settings 416 | SLEEP_MODE = 0 417 | FORCED_MODE = 1 418 | 419 | 420 | def __init__(self, i2c_addr = _BME680_I2C_ADDR_SECONDARY, i2c_device = None): 421 | BME680Data.__init__(self) 422 | 423 | self.i2c_addr = i2c_addr 424 | self._i2c = i2c_device 425 | if self._i2c is None: 426 | import smbus 427 | self._i2c = smbus.SMBus(1) 428 | 429 | self.chip_id = self._get_regs(_BME680_CHIP_ID_ADDR, 1) 430 | if self.chip_id != _BME680_CHIP_ID: 431 | raise RuntimeError("BME680 Not Found. Invalid CHIP ID: 0x{0:02x}".format(self.chip_id)) 432 | 433 | self.soft_reset() 434 | self.set_power_mode(self.SLEEP_MODE) 435 | 436 | self._get_calibration_data() 437 | 438 | self.set_humidity_oversample(self.OS_2X) 439 | self.set_pressure_oversample(self.OS_4X) 440 | self.set_temperature_oversample(self.OS_8X) 441 | self.set_filter(self.FILTER_SIZE_3) 442 | self.set_gas_status(self.ENABLE_GAS_MEAS) 443 | self.set_temp_offset(0) 444 | self.get_sensor_data() 445 | 446 | def _get_calibration_data(self): 447 | calibration = self._get_regs(_BME680_COEFF_ADDR1, _BME680_COEFF_ADDR1_LEN) 448 | calibration += self._get_regs(_BME680_COEFF_ADDR2, _BME680_COEFF_ADDR2_LEN) 449 | 450 | heat_range = self._get_regs(_BME680_ADDR_RES_HEAT_RANGE_ADDR, 1) 451 | heat_value = twos_comp(self._get_regs(_BME680_ADDR_RES_HEAT_VAL_ADDR, 1), bits=8) 452 | sw_error = twos_comp(self._get_regs(_BME680_ADDR_RANGE_SW_ERR_ADDR, 1), bits=8) 453 | 454 | self.calibration_data.set_from_array(calibration) 455 | self.calibration_data.set_other(heat_range, heat_value, sw_error) 456 | 457 | def soft_reset(self): 458 | self._set_regs(_BME680_SOFT_RESET_ADDR, _BME680_SOFT_RESET_CMD) 459 | time.sleep(0.01) 460 | 461 | def set_temp_offset(self, value): 462 | if value == 0: 463 | self.offset_temp_in_t_fine = 0 464 | else: 465 | self.offset_temp_in_t_fine = int(math.copysign((((int(abs(value) * 100)) << 8) - 128) / 5, value)) 466 | 467 | def set_humidity_oversample(self, value): 468 | '''! 469 | @brief Set humidity oversampling 470 | @param value Oversampling value, OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 471 | ''' 472 | self.tph_settings.os_hum = value 473 | self._set_bits(_BME680_CONF_OS_H_ADDR, _BME680_OSH_MSK, _BME680_OSH_POS, value) 474 | 475 | def get_humidity_oversample(self): 476 | return (self._get_regs(_BME680_CONF_OS_H_ADDR, 1) & _BME680_OSH_MSK) >> _BME680_OSH_POS 477 | 478 | def set_pressure_oversample(self, value): 479 | '''! 480 | @brief Set temperature oversampling 481 | @param value Oversampling value, OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 482 | ''' 483 | self.tph_settings.os_pres = value 484 | self._set_bits(_BME680_CONF_T_P_MODE_ADDR, _BME680_OSP_MSK, _BME680_OSP_POS, value) 485 | 486 | def get_pressure_oversample(self): 487 | return (self._get_regs(_BME680_CONF_T_P_MODE_ADDR, 1) & _BME680_OSP_MSK) >> _BME680_OSP_POS 488 | 489 | def set_temperature_oversample(self, value): 490 | '''! 491 | @brief Set pressure oversampling 492 | @param Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 493 | ''' 494 | self.tph_settings.os_temp = value 495 | self._set_bits(_BME680_CONF_T_P_MODE_ADDR, _BME680_OST_MSK, _BME680_OST_POS, value) 496 | 497 | def get_temperature_oversample(self): 498 | return (self._get_regs(_BME680_CONF_T_P_MODE_ADDR, 1) & _BME680_OST_MSK) >> _BME680_OST_POS 499 | 500 | def set_filter(self, value): 501 | '''! 502 | @brief Set IIR filter size to remove short term fluctuations from the temperature and pressure readings 503 | @param increasing resolution but reducing bandwidth 504 | FILTER_SIZE_0 505 | FILTER_SIZE_1 506 | FILTER_SIZE_3 507 | FILTER_SIZE_7 508 | FILTER_SIZE_15 509 | FILTER_SIZE_31 510 | FILTER_SIZE_63 511 | FILTER_SIZE_127 512 | ''' 513 | self.tph_settings.filter = value 514 | self._set_bits(_BME680_CONF_ODR_FILT_ADDR, _BME680_FILTER_MSK, _BME680_FILTER_POS, value) 515 | 516 | def get_filter(self): 517 | return (self._get_regs(_BME680_CONF_ODR_FILT_ADDR, 1) & _BME680_FILTER_MSK) >> _BME680_FILTER_POS 518 | 519 | def select_gas_heater_profile(self, value): 520 | '''! 521 | @brief Set current gas sensor conversion profile 522 | @param value:current gas sensor conversion profile: 0 ~ 9 523 | ''' 524 | if value > _BME680_NBCONV_MAX or value < _BME680_NBCONV_MIN: 525 | raise ValueError("Profile '{}' should be between {} and {}".format(value, _BME680_NBCONV_MIN, _BME680_NBCONV_MAX)) 526 | 527 | self.gas_settings.nb_conv = value 528 | self._set_bits(_BME680_CONF_ODR_RUN_GAS_NBC_ADDR, _BME680_NBCONV_MSK, _BME680_NBCONV_POS, value) 529 | 530 | def get_gas_heater_profile(self): 531 | return self._get_regs(_BME680_CONF_ODR_RUN_GAS_NBC_ADDR, 1) & _BME680_NBCONV_MSK 532 | 533 | def set_gas_status(self, value): 534 | '''! 535 | @brief Enable/disable gas sensor 536 | @param 1 for enable and 0 for disable 537 | ''' 538 | self.gas_settings.run_gas = value 539 | self._set_bits(_BME680_CONF_ODR_RUN_GAS_NBC_ADDR, _BME680_RUN_GAS_MSK, _BME680_RUN_GAS_POS, value) 540 | 541 | def get_gas_status(self): 542 | return (self._get_regs(_BME680_CONF_ODR_RUN_GAS_NBC_ADDR, 1) & _BME680_RUN_GAS_MSK) >> _BME680_RUN_GAS_POS 543 | 544 | def set_gas_heater_profile(self, temperature, duration, nb_profile=0): 545 | self.set_gas_heater_temperature(temperature, nb_profile=nb_profile) 546 | self.set_gas_heater_duration(duration, nb_profile=nb_profile) 547 | 548 | def set_gas_heater_temperature(self, value, nb_profile=0): 549 | '''! 550 | @brief Set gas sensor heater temperature 551 | @param value:target temperature in degrees celsius, between 200 ~ 400 552 | ''' 553 | if nb_profile > _BME680_NBCONV_MAX or value < _BME680_NBCONV_MIN: 554 | raise ValueError("Profile '{}' should be between {} and {}".format(nb_profile, _BME680_NBCONV_MIN, _BME680_NBCONV_MAX)) 555 | 556 | self.gas_settings.heatr_temp = value 557 | temp = int(self._calc_heater_resistance(self.gas_settings.heatr_temp)) 558 | self._set_regs(_BME680_RES_HEAT0_ADDR + nb_profile, temp) 559 | 560 | def set_gas_heater_duration(self, value, nb_profile=0): 561 | '''! 562 | @brief Set gas sensor heater duration 563 | @param value:target duration in milliseconds, between 1 ~ 4032 564 | ''' 565 | if nb_profile > _BME680_NBCONV_MAX or value < _BME680_NBCONV_MIN: 566 | raise ValueError("Profile '{}' should be between {} and {}".format(nb_profile, _BME680_NBCONV_MIN, _BME680_NBCONV_MAX)) 567 | 568 | self.gas_settings.heatr_dur = value 569 | temp = self._calc_heater_duration(self.gas_settings.heatr_dur) 570 | self._set_regs(_BME680_GAS_WAIT0_ADDR + nb_profile, temp) 571 | 572 | def set_power_mode(self, value): 573 | if value not in (self.SLEEP_MODE, self.FORCED_MODE): 574 | print("Power mode should be one of SLEEP_MODE or FORCED_MODE") 575 | 576 | self.power_mode = value 577 | 578 | self._set_bits(_BME680_CONF_T_P_MODE_ADDR, _BME680_MODE_MSK, _BME680_MODE_POS, value) 579 | 580 | 581 | def get_power_mode(self): 582 | self.power_mode = self._get_regs(_BME680_CONF_T_P_MODE_ADDR, 1) 583 | return self.power_mode 584 | 585 | def get_sensor_data(self): 586 | self.set_power_mode(self.FORCED_MODE) 587 | 588 | for attempt in range(10): 589 | status = self._get_regs(_BME680_FIELD0_ADDR, 1) 590 | 591 | if (status & _BME680_NEW_DATA_MSK) == 0: 592 | time.sleep(0.01) 593 | continue 594 | 595 | regs = self._get_regs(_BME680_FIELD0_ADDR, _BME680_FIELD_LENGTH) 596 | 597 | self.data.status = regs[0] & _BME680_NEW_DATA_MSK 598 | # Contains the nb_profile used to obtain the current measurement 599 | self.data.gas_index = regs[0] & _BME680_GAS_INDEX_MSK 600 | self.data.meas_index = regs[1] 601 | 602 | adc_pres = (regs[2] << 12) | (regs[3] << 4) | (regs[4] >> 4) 603 | adc_temp = (regs[5] << 12) | (regs[6] << 4) | (regs[7] >> 4) 604 | adc_hum = (regs[8] << 8) | regs[9] 605 | adc_gas_res = (regs[13] << 2) | (regs[14] >> 6) 606 | gas_range = regs[14] & _BME680_GAS_RANGE_MSK 607 | 608 | self.data.status |= regs[14] & _BME680_GASM_VALID_MSK 609 | self.data.status |= regs[14] & _BME680_HEAT_STAB_MSK 610 | 611 | self.data.heat_stable = (self.data.status & _BME680_HEAT_STAB_MSK) > 0 612 | 613 | temperature = self._calc_temperature(adc_temp) 614 | self.data.temperature = temperature / 100.0 615 | self.ambient_temperature = temperature # Saved for heater calc 616 | 617 | self.data.pressure = self._calc_pressure(adc_pres) / 100.0 618 | self.data.humidity = self._calc_humidity(adc_hum) / 1000.0 619 | self.data.gas_resistance = self._calc_gas_resistance(adc_gas_res, gas_range) 620 | return True 621 | 622 | return False 623 | 624 | def _set_bits(self, register, mask, position, value): 625 | temp = self._get_regs(register, 1) 626 | temp &= ~mask 627 | temp |= value << position 628 | self._set_regs(register, temp) 629 | 630 | def _set_regs(self, register, value): 631 | if isinstance(value, int): 632 | self._i2c.write_byte_data(self.i2c_addr, register, value) 633 | else: 634 | self._i2c.write_i2c_block_data(self.i2c_addr, register, value) 635 | 636 | def _get_regs(self, register, length): 637 | if length == 1: 638 | return self._i2c.read_byte_data(self.i2c_addr, register) 639 | else: 640 | return self._i2c.read_i2c_block_data(self.i2c_addr, register, length) 641 | 642 | def _calc_temperature(self, temperature_adc): 643 | var1 = (temperature_adc >> 3) - (self.calibration_data.par_t1 << 1) 644 | var2 = (var1 * self.calibration_data.par_t2) >> 11 645 | var3 = ((var1 >> 1) * (var1 >> 1)) >> 12 646 | var3 = ((var3) * (self.calibration_data.par_t3 << 4)) >> 14 647 | 648 | self.calibration_data.t_fine = (var2 + var3) + self.offset_temp_in_t_fine 649 | calc_temp = (((self.calibration_data.t_fine * 5) + 128) >> 8) 650 | 651 | return calc_temp 652 | 653 | def _calc_pressure(self, pressure_adc): 654 | var1 = ((self.calibration_data.t_fine) >> 1) - 64000 655 | var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * 656 | self.calibration_data.par_p6) >> 2 657 | var2 = var2 + ((var1 * self.calibration_data.par_p5) << 1) 658 | var2 = (var2 >> 2) + (self.calibration_data.par_p4 << 16) 659 | var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13 ) * 660 | ((self.calibration_data.par_p3 << 5)) >> 3) + 661 | ((self.calibration_data.par_p2 * var1) >> 1)) 662 | var1 = var1 >> 18 663 | 664 | var1 = ((32768 + var1) * self.calibration_data.par_p1) >> 15 665 | calc_pressure = 1048576 - pressure_adc 666 | calc_pressure = ((calc_pressure - (var2 >> 12)) * (3125)) 667 | 668 | if calc_pressure >= (1 << 31): 669 | calc_pressure = ((calc_pressure // var1) << 1) 670 | else: 671 | calc_pressure = ((calc_pressure << 1) // var1) 672 | 673 | var1 = (self.calibration_data.par_p9 * (((calc_pressure >> 3) * 674 | (calc_pressure >> 3)) >> 13)) >> 12 675 | var2 = ((calc_pressure >> 2) * 676 | self.calibration_data.par_p8) >> 13 677 | var3 = ((calc_pressure >> 8) * (calc_pressure >> 8) * 678 | (calc_pressure >> 8) * 679 | self.calibration_data.par_p10) >> 17 680 | 681 | calc_pressure = (calc_pressure) + ((var1 + var2 + var3 + 682 | (self.calibration_data.par_p7 << 7)) >> 4) 683 | 684 | return calc_pressure 685 | 686 | def _calc_humidity(self, humidity_adc): 687 | temp_scaled = ((self.calibration_data.t_fine * 5) + 128) >> 8 688 | var1 = (humidity_adc - ((self.calibration_data.par_h1 * 16))) \ 689 | - (((temp_scaled * self.calibration_data.par_h3) // (100)) >> 1) 690 | var2 = (self.calibration_data.par_h2 691 | * (((temp_scaled * self.calibration_data.par_h4) // (100)) 692 | + (((temp_scaled * ((temp_scaled * self.calibration_data.par_h5) // (100))) >> 6) 693 | // (100)) + (1 * 16384))) >> 10 694 | var3 = var1 * var2 695 | var4 = self.calibration_data.par_h6 << 7 696 | var4 = ((var4) + ((temp_scaled * self.calibration_data.par_h7) // (100))) >> 4 697 | var5 = ((var3 >> 14) * (var3 >> 14)) >> 10 698 | var6 = (var4 * var5) >> 1 699 | calc_hum = (((var3 + var6) >> 10) * (1000)) >> 12 700 | 701 | return min(max(calc_hum,0),100000) 702 | 703 | def _calc_gas_resistance(self, gas_res_adc, gas_range): 704 | var1 = ((1340 + (5 * self.calibration_data.range_sw_err)) * (lookupTable1[gas_range])) >> 16 705 | var2 = (((gas_res_adc << 15) - (16777216)) + var1) 706 | var3 = ((lookupTable2[gas_range] * var1) >> 9) 707 | calc_gas_res = ((var3 + (var2 >> 1)) / var2) 708 | 709 | if calc_gas_res < 0: 710 | calc_gas_res = (1<<32) + calc_gas_res 711 | 712 | return calc_gas_res 713 | 714 | def _calc_heater_resistance(self, temperature): 715 | temperature = min(max(temperature,200),400) 716 | 717 | var1 = ((self.ambient_temperature * self.calibration_data.par_gh3) / 1000) * 256 718 | var2 = (self.calibration_data.par_gh1 + 784) * (((((self.calibration_data.par_gh2 + 154009) * temperature * 5) / 100) + 3276800) / 10) 719 | var3 = var1 + (var2 / 2) 720 | var4 = (var3 / (self.calibration_data.res_heat_range + 4)) 721 | var5 = (131 * self.calibration_data.res_heat_val) + 65536 722 | heatr_res_x100 = (((var4 / var5) - 250) * 34) 723 | heatr_res = ((heatr_res_x100 + 50) / 100) 724 | 725 | return heatr_res 726 | 727 | def _calc_heater_duration(self, duration): 728 | if duration < 0xfc0: 729 | factor = 0 730 | 731 | while duration > 0x3f: 732 | duration /= 4 733 | factor += 1 734 | 735 | return int(duration + (factor * 64)) 736 | 737 | return 0xff -------------------------------------------------------------------------------- /Python/RaspberryPi/README.md: -------------------------------------------------------------------------------- 1 | # DFRobot_BME680 2 | 3 | * [中文版](./README_CN.md) 4 | 5 | BME680 is an integrated environmental sensor developed specifically for mobile applications and wearables 6 | where size and low power consumption are key requirements. Expanding Bosch Sensortec’s existing family of environmental sensors, 7 | the BME680 integrates for the first time individual high linearity and high accuracy sensors for gas, pressure, humidity and temperature. 8 | 9 | ![产品效果图](../../resources/images/SEN0248.png) 10 | 11 | 12 | 13 | ## Product Link([https://www.dfrobot.com/product-1697.html](https://www.dfrobot.com/product-1697.html)) 14 | SKU: SEN0248 15 | 16 | ## Table of Contents 17 | 18 | * [Summary](#summary) 19 | * [Installation](#installation) 20 | * [Methods](#methods) 21 | * [Compatibility](#compatibility) 22 | * [History](#history) 23 | * [Credits](#credits) 24 | 25 | ## Summary 26 | The temperature, pressure, humidity at both ends of the sampling resistance of BME680 can be read through I2C. 27 | These data are printed out through the serial port. 28 | 1. Low standby current 29 | 2. Serial input via I2C-bus 30 | 31 | ## Installation 32 | 33 | This Sensor should work with BME680 on RaspberryPi.
34 | Run the program: 35 | ``` 36 | $> python read_all_data.py 37 | 38 | ``` 39 | 40 | ## Methods 41 | 42 | ```python 43 | '''! 44 | @brief Set humidity oversampling 45 | @param Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 46 | ''' 47 | def set_humidity_oversample(self, value) 48 | 49 | '''! 50 | @brief Set temperature oversampling 51 | @param Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 52 | ''' 53 | def set_pressure_oversample(self, value) 54 | 55 | '''! 56 | @brief Set pressure oversampling 57 | @param Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 58 | ''' 59 | def set_temperature_oversample(self, value) 60 | 61 | '''! 62 | @brief Set IIR filter size to remove short term fluctuations from the temperature and pressure readings 63 | @param increasing resolution but reducing bandwidth 64 | FILTER_SIZE_0 65 | FILTER_SIZE_1 66 | FILTER_SIZE_3 67 | FILTER_SIZE_7 68 | FILTER_SIZE_15 69 | FILTER_SIZE_31 70 | FILTER_SIZE_63 71 | FILTER_SIZE_127 72 | ''' 73 | def set_filter(self, value) 74 | 75 | '''! 76 | @brief Enable/disable gas sensor 77 | @param 1 for enable and 0 for disable 78 | ''' 79 | def set_gas_status(self, value) 80 | 81 | '''! 82 | @brief Set gas sensor heater temperature 83 | @param value:target temperature in degrees celsius, between 200 ~ 400 84 | ''' 85 | def set_gas_heater_temperature(self, value) 86 | 87 | '''! 88 | @brief Set gas sensor heater duration 89 | @param value:target duration in milliseconds, between 1 ~ 4032 90 | ''' 91 | def set_gas_heater_duration(self, value) 92 | 93 | '''! 94 | @brief Set current gas sensor conversion profile 95 | @param value:current gas sensor conversion profile: 0 ~ 9 96 | ''' 97 | def select_gas_heater_profile(self, value) 98 | ``` 99 | 100 | ## Compatibility 101 | 102 | | 主板 | 通过 | 未通过 | 未测试 | 备注 | 103 | | ------------ | :--: | :----: | :----: | :--: | 104 | | RaspberryPi2 | | | √ | | 105 | | RaspberryPi3 | | | √ | | 106 | | RaspberryPi4 | √ | | | | 107 | 108 | * Python 版本 109 | 110 | | Python | 通过 | 未通过 | 未测试 | 备注 | 111 | | ------- | :--: | :----: | :----: | ---- | 112 | | Python2 | √ | | | | 113 | | Python3 | | | √ | | 114 | 115 | ## History 116 | 117 | - 2017/12/04 - Version 2.0.0 released. 118 | - 2017/09/04 - Version 1.0.0 released. 119 | 120 | ## Credits 121 | 122 | Written by luoyufeng(yufeng.luo@dfrobot.com), 2017. (Welcome to our [website](https://www.dfrobot.com/)) 123 | -------------------------------------------------------------------------------- /Python/RaspberryPi/README_CN.md: -------------------------------------------------------------------------------- 1 | # DFRobot_BME680 2 | 3 | * [English Version](./README.md) 4 | 5 | BME680 是专为移动应用和可穿戴设备开发的集成环境传感器其中尺寸和低功耗是关键要求。 BME680 扩展了 Bosch Sensortec
6 | 现有的环境传感器系列,首次集成了用于气体、压力、湿度和温度的单个高线性度和高精度传感器。
7 | 8 | ![产品效果图](../../resources/images/SEN0248.png) 9 | 10 | ## 产品链接([https://www.dfrobot.com.cn/goods-1621.html](https://www.dfrobot.com.cn/goods-1621.html)) 11 | SKU: SEN0248 12 | 13 | ## 目录 14 | 15 | * [概述](#概述) 16 | * [库安装](#库安装) 17 | * [方法](#方法) 18 | * [兼容性](#兼容性) 19 | * [历史](#历史) 20 | * [创作者](#创作者) 21 | 22 | ## 概述 23 | BME680采样电阻两端的温度、压力、湿度可以通过I2C读取。这些数据通过串口打印出来。
24 | 此传感器具有以下特点: 25 | 1. 低待机电流 26 | 2. 通过 I2C 总线的串行输入 27 | 28 | ## 库安装 29 | 1. 下载库至树莓派,要使用这个库,首先要将库下载到Raspberry Pi,命令下载方法如下:
30 | ```python 31 | sudo git clone https://github.com/DFRobot/DFRobot_BME680 32 | ``` 33 | 2. 打开并运行例程,要执行一个例程demo_x.py,请在命令行中输入python demo_x.py。例如,要执行 demo_read_all_data.py例程,你需要输入:
34 | 35 | ```python 36 | python demo_read_all_data.py 37 | ``` 38 | 39 | ## 方法 40 | 41 | ```python 42 | '''! 43 | @brief 设置湿度采样 44 | @param value 采样值: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 45 | ''' 46 | def set_humidity_oversample(self, value) 47 | 48 | '''! 49 | @brief 设置压强采样 50 | @param value 采样值: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 51 | ''' 52 | def set_pressure_oversample(self, value) 53 | 54 | '''! 55 | @brief 设置温度采样 56 | @param value 采样值: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 57 | ''' 58 | def set_temperature_oversample(self, value) 59 | 60 | '''! 61 | @brief 设置 IIR 滤波器大小以消除温度和压力读数的短期波动 62 | @param value 提高分辨率但降低带宽 63 | FILTER_SIZE_0 64 | FILTER_SIZE_1 65 | FILTER_SIZE_3 66 | FILTER_SIZE_7 67 | FILTER_SIZE_15 68 | FILTER_SIZE_31 69 | FILTER_SIZE_63 70 | FILTER_SIZE_127 71 | ''' 72 | def set_filter(self, value) 73 | 74 | '''! 75 | @brief Enable/disable gas sensor 76 | @param value 使能或失能 77 | @retval 1 使能 78 | @retval 0 失能 79 | ''' 80 | def set_gas_status(self, value) 81 | 82 | '''! 83 | @brief 设置气体传感器加热器温度 84 | @param value:以摄氏度为单位的目标温度,在 200 ~ 400 之间 85 | ''' 86 | def set_gas_heater_temperature(self, value) 87 | 88 | '''! 89 | @brief 设置气体传感器加热器持续时间 90 | @param value:目标持续时间,以毫秒为单位,介于 1 ~ 4032 之间 91 | ''' 92 | def set_gas_heater_duration(self, value) 93 | 94 | '''! 95 | @brief 设置当前气体传感器转换配置文件 96 | @param value:当前气体传感器转换配置文件:0 ~ 9 97 | ''' 98 | def select_gas_heater_profile(self, value) 99 | ``` 100 | 101 | ## 兼容性 102 | 103 | | 主板 | 通过 | 未通过 | 未测试 | 备注 | 104 | | ------------ | :--: | :----: | :----: | :--: | 105 | | RaspberryPi2 | | | √ | | 106 | | RaspberryPi3 | | | √ | | 107 | | RaspberryPi4 | √ | | | | 108 | 109 | * Python 版本 110 | 111 | | Python | 通过 | 未通过 | 未测试 | 备注 | 112 | | ------- | :--: | :----: | :----: | ---- | 113 | | Python2 | √ | | | | 114 | | Python3 | | | √ | | 115 | 116 | ## 历史 117 | 118 | - 2017/12/04 - 2.0.0 版本 119 | - 2017/09/04 - 1.0.0 版本 120 | 121 | ## 创作者 122 | 123 | Written by luoyufeng(yufeng.luo@dfrobot.com), 2017. (Welcome to our [website](https://www.dfrobot.com/)) 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /Python/RaspberryPi/examples/demo_read_all_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from __future__ import print_function 3 | 4 | 5 | '''! 6 | @file demo_read_all_data.py 7 | @brief connect bme680 I2C interface with your board (please reference board compatibility) 8 | @n Temprature, Humidity, pressure, altitude, calibrate altitude and gas resistance data will print on serial window. 9 | @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 10 | @license The MIT License (MIT) 11 | @author [luoyufeng](yufeng.luo@dfrobot.com) 12 | @version V1.0 13 | @date 2019-7-2 14 | @url https://github.com/DFRobot/DFRobot_BME680 15 | ''' 16 | 17 | 18 | import sys 19 | sys.path.append('../') 20 | from DFRobot_BME680 import DFRobot_BME680 21 | import time 22 | 23 | sensor = DFRobot_BME680() 24 | 25 | # These calibration data can safely be commented 26 | # out, if desired. 27 | ''' 28 | print("Calibration data:") 29 | for name in dir(sensor.calibration_data): 30 | 31 | if not name.startswith('_'): 32 | value = getattr(sensor.calibration_data, name) 33 | 34 | if isinstance(value, int): 35 | print("{}: {}".format(name, value)) 36 | ''' 37 | # These oversampling settings can be tweaked to 38 | # change the balance between accuracy and noise in 39 | # the data. 40 | 41 | sensor.set_humidity_oversample(sensor.OS_2X) #Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 42 | sensor.set_pressure_oversample(sensor.OS_4X) #Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 43 | sensor.set_temperature_oversample(sensor.OS_8X) #Oversampling value: OS_NONE, OS_1X, OS_2X, OS_4X, OS_8X, OS_16X 44 | sensor.set_filter(sensor.FILTER_SIZE_3) #increasing resolution but reducing bandwidth 45 | sensor.set_gas_status(sensor.ENABLE_GAS_MEAS) #1 for enable and 0 for disable 46 | ''' 47 | print("\n\nInitial reading:") 48 | for name in dir(sensor.data): 49 | value = getattr(sensor.data, name) 50 | 51 | if not name.startswith('_'): 52 | print("{}: {}".format(name, value)) 53 | ''' 54 | sensor.set_gas_heater_temperature(320) #value:target temperature in degrees celsius, between 200 ~ 400 55 | sensor.set_gas_heater_duration(150) #value:target duration in milliseconds, between 1 and 4032 56 | sensor.select_gas_heater_profile(0) #value:current gas sensor conversion profile: 0 to 9 57 | 58 | 59 | print("\n\nPolling:") 60 | while True: 61 | if sensor.get_sensor_data(): 62 | print("temperature: {0:.2f} C, pressure: {1:.2f} hPa, humidity: {2:.2f} %RH".format(sensor.data.temperature, sensor.data.pressure, sensor.data.humidity)) 63 | 64 | time.sleep(1) 65 | -------------------------------------------------------------------------------- /Python/RaspberryPi/examples/demo_set_low_power.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from __future__ import print_function 3 | 4 | 5 | '''! 6 | @file demo_set_low_power.py 7 | @brief connect bme680 I2C interface with your board (please reference board compatibility) 8 | @n You can set sensor low power mode or wake up mode. 9 | @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 10 | @license The MIT License (MIT) 11 | @author [luoyufeng](yufeng.luo@dfrobot.com) 12 | @version V1.0 13 | @date 2019-7-2 14 | @url https://github.com/DFRobot/DFRobot_BME680 15 | ''' 16 | import sys 17 | sys.path.append('../') 18 | from DFRobot_BME680 import DFRobot_BME680 19 | import time 20 | 21 | sensor = DFRobot_BME680() 22 | 23 | #sensor.set_power_mode(sensor.SLEEP_MODE) # set low power mode 24 | sensor.set_power_mode(sensor.FORCED_MODE) # set wake up mode 25 | sensor.get_power_mode() # get current power mode 26 | 27 | if sensor.get_power_mode() == 141: 28 | print("Current power mode is forced") 29 | else: 30 | print("Current power mode is sleep") 31 | 32 | while True: 33 | time.sleep(1) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DFRobot_BME680 2 | 3 | * [中文版](./README_CN.md) 4 | 5 | BME680 is an integrated environmental sensor developed specifically for mobile applications and wearables 6 | where size and low power consumption are key requirements. Expanding Bosch Sensortec’s existing family of environmental sensors, 7 | the BME680 integrates for the first time individual high linearity and high accuracy sensors for gas, pressure, humidity and temperature. 8 | 9 | ![产品效果图](./resources/images/SEN0248.png) 10 | 11 | 12 | 13 | ## Product Link([https://www.dfrobot.com/product-1697.html](https://www.dfrobot.com/product-1697.html)) 14 | SKU: SEN0248 15 | 16 | 17 | ## Table of Contents 18 | 19 | * [Summary](#summary) 20 | * [Installation](#installation) 21 | * [Methods](#methods) 22 | * [Compatibility](#compatibility) 23 | * [History](#history) 24 | * [Credits](#credits) 25 | 26 | ## Summary 27 | Provides an Arduino library for reading and interpreting Bosch BME680 data over I2C over SPI.Reads temperature, humidity, gas, IAQ(details in examples\readme), pressure and calculates altitude. 28 | 29 | 30 | ## Installation 31 | 32 | To use this library download the zip file, uncompress it to a folder named DFRobot_BME680. 33 | Download the zip file first to use this library and uncompress it to a folder named DFRobot_BME680. 34 | 35 | ## Methods 36 | 37 | ```C++ 38 | /** 39 | * @fn begin 40 | * @brief begin BME680 device 41 | * @return result 42 | * @retval non-zero : falid 43 | * @retval 0 : succussful 44 | */ 45 | int16_t begin(void); 46 | /** 47 | * @fn update 48 | * @brief update all data to MCU ram 49 | */ 50 | void update(void); 51 | /** 52 | * @fn iaqUpdate 53 | * @brief update all data to MCU ram with IAQ (only for esp8266 now) 54 | * 55 | * @return result: 56 | * @retval 0 :complete 57 | * @retval 1 :busy 58 | */ 59 | int8_t iaqUpdate(void); 60 | /** 61 | * @fn startConvert 62 | * @brief start convert to get a accurate values 63 | */ 64 | void startConvert(void); 65 | /** 66 | * @fn readTemperature 67 | * @brief read the temperature value (unit C) 68 | * 69 | * @return temperature valu, this value has two decimal points 70 | */ 71 | float readTemperature(void); 72 | /** 73 | * @fn readPressure 74 | * @brief read the pressure value (unit pa) 75 | * 76 | * @return pressure value, this value has two decimal points 77 | */ 78 | float readPressure(void); 79 | /** 80 | * @fn readHumidity 81 | * @brief read the humidity value (unit %rh) 82 | * @return humidity value, this value has two decimal points 83 | */ 84 | float readHumidity(void); 85 | /** 86 | * @fn readAltitude 87 | * @brief read the altitude (unit meter) 88 | * @return altitude value, this value has two decimal points 89 | */ 90 | float readAltitude(void); 91 | /** 92 | * @fn readCalibratedAltitude 93 | * @brief read the Calibrated altitude (unit meter) 94 | * 95 | * @param seaLevel normalised atmospheric pressure 96 | * 97 | * @return calibrated altitude value , this value has two decimal points 98 | */ 99 | float readCalibratedAltitude(float seaLevel); 100 | /** 101 | * @fn readGasResistance 102 | * @brief read the gas resistance(unit ohm) 103 | * @return temperature value, this value has two decimal points 104 | */ 105 | float readGasResistance(void); 106 | /** 107 | * @fn readSeaLevel 108 | * @brief read normalised atmospheric pressure (unit pa) 109 | * @param altitude accurate altitude for normalising 110 | * @return normalised atmospheric pressure 111 | */ 112 | float readSeaLevel(float altitude); 113 | /** 114 | * @fn readIAQ 115 | * @brief read IAQ 116 | * @return The result of IAQ 117 | */ 118 | float readIAQ(void); 119 | /** 120 | * @fn setParam 121 | * @brief set bme680 parament 122 | * 123 | * @param eParam :which param you want to change 124 | * dat :object data, can't more than 5 125 | */ 126 | void setParam(eBME680_param_t eParam, uint8_t dat); 127 | /** 128 | * @fn setGasHeater 129 | * @brief set bme680 gas heater 130 | * @param temp :your object temp 131 | * @param t :time spend in milliseconds 132 | */ 133 | void setGasHeater(uint16_t temp, uint16_t t); 134 | /** 135 | * @fn isIAQReady 136 | * @brief check IAQ ready 137 | * @return result: 138 | * @retval 0 :ready 139 | * @retval 1 :not ready 140 | */ 141 | uint8_t isIAQReady(void); 142 | 143 | ``` 144 | 145 | ## Compatibility 146 | 147 | MCU | Work Well | Work Wrong | Untested | Remarks 148 | ------------------ | :----------: | :----------: | :---------: | ----- 149 | FireBeetle-ESP32 | √ | | | 150 | FireBeetle-ESP8266 | √ | | | 151 | FireBeetle-BLE4.1 | √ | | | 152 | Arduino uno | √ | | | 153 | Arduino leonardo | √ | | | 154 | 155 | ## History 156 | 157 | - 2017/12/04 - Version 2.0.0 released. 158 | - 2017/09/04 - Version 1.0.0 released. 159 | 160 | ## Credits 161 | 162 | Written by Frank(jiehan.guo@dfrobot.com), 2017. (Welcome to our [website](https://www.dfrobot.com/)) 163 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # DFRobot_BME680 2 | 3 | * [English Version](./README.md) 4 | 5 | BME680 是专为移动应用和可穿戴设备开发的集成环境传感器其中尺寸和低功耗是关键要求。 BME680 扩展了 Bosch Sensortec
6 | 现有的环境传感器系列,首次集成了用于气体、压力、湿度和温度的单个高线性度和高精度传感器。
7 | 8 | ![产品效果图](./resources/images/SEN0248.png) 9 | 10 | ## 产品链接([https://www.dfrobot.com.cn/goods-1621.html](https://www.dfrobot.com.cn/goods-1621.html)) 11 | SKU: SEN0248 12 | 13 | ## 目录 14 | 15 | * [概述](#概述) 16 | * [库安装](#库安装) 17 | * [方法](#方法) 18 | * [兼容性](#兼容性) 19 | * [历史](#历史) 20 | * [创作者](#创作者) 21 | 22 | ## 概述 23 | 24 | 提供一个 Arduino 库,用于通过 I2C 通过 SPI 读取和解释 Bosch BME680 数据。读取温度、湿度、气体、IAQ(示例\自述文件中的详细信息)、压力并计算高度。 25 | 26 | ## 库安装 27 | 28 | 这里有2种安装方法: 29 | 1. 使用此库前,请首先下载库文件,将其粘贴到\Arduino\libraries目录中,然后打开examples文件夹并在该文件夹中运行演示。 30 | 2. 直接在Arduino软件库管理中搜索下载 DFRobot_AHT20 库 31 | 32 | 33 | ## 方法 34 | ```C++ 35 | /** 36 | * @fn begin 37 | * @brief 初始化BME680传感器设备 38 | * @return 结果 39 | * @retval 非0值 : 失败 40 | * @retval 0 : 成功 41 | */ 42 | int16_t begin(void); 43 | 44 | /** 45 | * @fn update 46 | * @brief 将所有数据更新到 MCU 内存 47 | */ 48 | void update(void); 49 | 50 | /** 51 | * @fn iaqUpdate 52 | * @brief 使用 IAQ 将所有数据更新到 MCU ram(现在仅适用于 esp8266) 53 | * 54 | * @return 更新状态: 55 | * @retval 0 :完成 56 | * @retval 1 :正在忙 57 | */ 58 | int8_t iaqUpdate(void); 59 | 60 | /** 61 | * @fn startConvert 62 | * @brief 开始转换以获得准确的值 63 | */ 64 | void startConvert(void); 65 | /** 66 | * @fn readTemperature 67 | * @brief 获取温度值 (单位 摄氏度) 68 | * 69 | * @return 温度值, 这个值有两个小数点 70 | */ 71 | float readTemperature(void); 72 | /** 73 | * @fn readPressure 74 | * @brief 读取压强值 (单位 帕) 75 | * 76 | * @return 压强值, 这个值有两个小数点 77 | */ 78 | float readPressure(void); 79 | /** 80 | * @fn readHumidity 81 | * @brief 读取湿度值 (单位 %rh) 82 | * @return 湿度值, 这个值有两个小数点 83 | */ 84 | float readHumidity(void); 85 | /** 86 | * @fn readAltitude 87 | * @brief 读取高度(单位米) 88 | * @return 高度值, 这个值有两个小数点 89 | */ 90 | float readAltitude(void); 91 | /** 92 | * @fn readCalibratedAltitude 93 | * @brief 读取校准高度(单位米) 94 | * 95 | * @param seaLevel 正规化大气压 96 | * 97 | * @return 标定高度值,该值有两位小数 98 | */ 99 | float readCalibratedAltitude(float seaLevel); 100 | /** 101 | * @fn readGasResistance 102 | * @brief 读取气体电阻(单位欧姆) 103 | * @return 温度值,这个值有两位小数 104 | */ 105 | float readGasResistance(void); 106 | /** 107 | * @fn readSeaLevel 108 | * @brief 读取标准化大气压力(单位帕) 109 | * @param altitude 标准化大气压力 110 | * @return 标准化大气压力 111 | */ 112 | float readSeaLevel(float altitude); 113 | /** 114 | * @fn readIAQ 115 | * @brief 读 IAQ 116 | * @return 返回 IAQ的值 117 | */ 118 | float readIAQ(void); 119 | /** 120 | * @fn setParam 121 | * @brief 设置bme680的参数 122 | * 123 | * @param eParam : 需要设置的参数 124 | * dat : 对象数据,不能超过5 125 | */ 126 | void setParam(eBME680_param_t eParam, uint8_t dat); 127 | /** 128 | * @fn setGasHeater 129 | * @brief 设置bme680燃气加热器 130 | * @param temp :目标温度 131 | * @param t :以毫秒为单位花费的时间 132 | */ 133 | void setGasHeater(uint16_t temp, uint16_t t); 134 | /** 135 | * @fn isIAQReady 136 | * @brief 检测 IAQ 是否准备好 137 | * @return result: 138 | * @retval 0 :准备完成 139 | * @retval 1 :繁忙中 140 | */ 141 | uint8_t isIAQReady(void); 142 | 143 | ``` 144 | 145 | ## 兼容性 146 | 147 | MCU | Work Well | Work Wrong | Untested | Remarks 148 | ------------------ | :----------: | :----------: | :---------: | ----- 149 | FireBeetle-ESP32 | √ | | | 150 | FireBeetle-ESP8266 | √ | | | 151 | FireBeetle-BLE4.1 | √ | | | 152 | Arduino uno | √ | | | 153 | Arduino leonardo | √ | | | 154 | 155 | ## 历史 156 | - 2017/12/04 - 2.0.0 版本 157 | - 2017/09/04 - 1.0.0 版本 158 | 159 | ## 创作者 160 | 161 | Written by Frank(jiehan.guo@dfrobot.com), 2021. (Welcome to our [website](https://www.dfrobot.com/)) 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /bme680.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bme680.c 3 | * @brief Sensor driver for BME680 sensor. 4 | * 5 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 6 | * @license The MIT License (MIT) 7 | * @author Frank(jiehan.guo@dfrobot.com) 8 | * @version V1.0 9 | * @date 2017-12-04 10 | * @url https://github.com/DFRobot/DFRobot_BME680 11 | */ 12 | 13 | #include "bme680.h" 14 | 15 | /** Success / +ve value -> Warning / -ve value -> Error 37 | */ 38 | static int8_t get_calib_data(struct bme680_dev *dev); 39 | 40 | /** 41 | * @fn set_gas_config 42 | * @brief This internal API is used to set the gas configuration of the sensor. 43 | * 44 | * @param dev :Structure instance of bme680_dev. 45 | * 46 | * @return Result of API execution status. 47 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 48 | */ 49 | static int8_t set_gas_config(struct bme680_dev *dev); 50 | 51 | /** 52 | * @fn get_gas_config 53 | * @brief This internal API is used to get the gas configuration of the sensor. 54 | * @param dev :Structure instance of bme680_dev. 55 | * @return Result of API execution status. 56 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 57 | */ 58 | static int8_t get_gas_config(struct bme680_dev *dev); 59 | 60 | /** 61 | * @fn calc_heater_dur 62 | * @brief This internal API is used to calculate the Heat duration value. 63 | * @param dur :Value of the duration to be shared. 64 | * @return uint8_t threshold duration after calculation. 65 | */ 66 | static uint8_t calc_heater_dur(uint16_t dur); 67 | 68 | /** 69 | * @fn calc_temperature 70 | * @brief This internal API is used to calculate the temperature value. 71 | * @param temp_adc :Contains the temperature ADC value . 72 | * @param dev :Structure instance of bme680_dev. 73 | * @return uint32_t calculated temperature. 74 | */ 75 | static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev); 76 | 77 | /** 78 | * @fn calc_pressure 79 | * @brief This internal API is used to calculate the pressure value. 80 | * @param pres_adc :Contains the pressure ADC value . 81 | * @param dev :Structure instance of bme680_dev. 82 | * @return uint32_t calculated pressure. 83 | */ 84 | static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev); 85 | 86 | /** 87 | * @fn calc_humidity 88 | * @brief This internal API is used to calculate the humidity value. 89 | * @param hum_adc :Contains the humidity ADC value. 90 | * @param dev :Structure instance of bme680_dev. 91 | * 92 | * @return uint32_t calculated humidity. 93 | */ 94 | static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev); 95 | 96 | /** 97 | * @fn calc_heater_res 98 | * @brief This internal API is used to calculate the Heat Resistance value. 99 | * @param temp :Contains the temporary value. 100 | * @param dev :Structure instance of bme680_dev. 101 | * @return uint8_t calculated heater resistance. 102 | */ 103 | static uint8_t calc_heater_res(uint16_t temp, const struct bme680_dev *dev); 104 | 105 | /** 106 | * @fn read_field_data 107 | * @brief This internal API is used to calculate the field data of sensor. 108 | * 109 | * @param data :Structure instance to hold the data 110 | * @param dev :Structure instance of bme680_dev. 111 | * 112 | * @return int8_t result of the field data from sensor. 113 | */ 114 | static int8_t read_field_data(struct bme680_field_data *data, struct bme680_dev *dev); 115 | 116 | /** 117 | * @fn set_mem_page 118 | * @brief This internal API is used to set the memory page based on register address. 119 | * 120 | * @n The value of memory page 121 | * @n value | Description 122 | * @n --------|-------------- 123 | * @n 0 | BME680_PAGE0_SPI 124 | * @n 1 | BME680_PAGE1_SPI 125 | * 126 | * @param reg_addr :Contains the register address array. 127 | * @param dev :Structure instance of bme680_dev. 128 | * 129 | * @return Result of API execution status 130 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 131 | */ 132 | static int8_t set_mem_page(uint8_t reg_addr, struct bme680_dev *dev); 133 | 134 | /** 135 | * @fn get_mem_page 136 | * @brief This internal API is used to get the memory page based on register address. 137 | * @n The value of memory page 138 | * @n value | Description 139 | * @n --------|-------------- 140 | * @n 0 | BME680_PAGE0_SPI 141 | * @n 1 | BME680_PAGE1_SPI 142 | * 143 | * @param dev :Structure instance of bme680_dev. 144 | * 145 | * @return Result of API execution status 146 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 147 | */ 148 | static int8_t get_mem_page(struct bme680_dev *dev); 149 | 150 | /** 151 | * @fn null_ptr_check 152 | * @brief This internal API is used to validate the device pointer for null conditions. 153 | * 154 | * @param dev :Structure instance of bme680_dev. 155 | * 156 | * @return Result of API execution status 157 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 158 | */ 159 | static int8_t null_ptr_check(const struct bme680_dev *dev); 160 | 161 | /** 162 | * @fn boundary_check 163 | * @brief This internal API is used to check the boundary conditions. 164 | * 165 | * @param value :pointer to the value. 166 | * @param min :minimum value. 167 | * @param max :maximum value. 168 | * @param dev :Structure instance of bme680_dev. 169 | * 170 | * @return Result of API execution status 171 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 172 | */ 173 | static int8_t boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev); 174 | 175 | /****************** Global Function Definitions *******************************/ 176 | int8_t bme680_init(struct bme680_dev *dev) 177 | { 178 | int8_t rslt; 179 | 180 | /* Check for null pointer in the device structure*/ 181 | rslt = null_ptr_check(dev); 182 | if (rslt == BME680_OK) { 183 | /* Soft reset to restore it to default values*/ 184 | rslt = bme680_soft_reset(dev); 185 | if (rslt == BME680_OK) { 186 | rslt = bme680_get_regs(BME680_CHIP_ID_ADDR, &dev->chip_id, 1, dev); 187 | if (rslt == BME680_OK) { 188 | if (dev->chip_id == BME680_CHIP_ID) { 189 | /* Get the Calibration data */ 190 | rslt = get_calib_data(dev); 191 | } else { 192 | rslt = BME680_E_DEV_NOT_FOUND; 193 | } 194 | } 195 | } 196 | } 197 | 198 | return rslt; 199 | } 200 | 201 | int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev) 202 | { 203 | int8_t rslt; 204 | 205 | /* Check for null pointer in the device structure*/ 206 | rslt = null_ptr_check(dev); 207 | if (rslt == BME680_OK) { 208 | if (dev->intf == BME680_SPI_INTF) { 209 | /* Set the memory page */ 210 | rslt = set_mem_page(reg_addr, dev); 211 | if (rslt == BME680_OK) 212 | reg_addr = reg_addr | BME680_SPI_RD_MSK; 213 | } 214 | dev->com_rslt = dev->read(dev->dev_id, reg_addr, reg_data, len); 215 | if (dev->com_rslt != 0) 216 | rslt = BME680_E_COM_FAIL; 217 | } 218 | 219 | return rslt; 220 | } 221 | 222 | int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev) 223 | { 224 | int8_t rslt; 225 | /* Length of the temporary buffer is 2*(length of register)*/ 226 | uint8_t tmp_buff[BME680_TMP_BUFFER_LENGTH] = { 0 }; 227 | uint16_t index; 228 | 229 | /* Check for null pointer in the device structure*/ 230 | rslt = null_ptr_check(dev); 231 | if (rslt == BME680_OK) { 232 | if ((len > 0) && (len < BME680_TMP_BUFFER_LENGTH / 2)) { 233 | /* Interleave the 2 arrays */ 234 | for (index = 0; index < len; index++) { 235 | if (dev->intf == BME680_SPI_INTF) { 236 | /* Set the memory page */ 237 | rslt = set_mem_page(reg_addr[index], dev); 238 | tmp_buff[(2 * index)] = reg_addr[index] & BME680_SPI_WR_MSK; 239 | } else { 240 | tmp_buff[(2 * index)] = reg_addr[index]; 241 | } 242 | tmp_buff[(2 * index) + 1] = reg_data[index]; 243 | } 244 | /* Write the interleaved array */ 245 | if (rslt == BME680_OK) { 246 | dev->com_rslt = dev->write(dev->dev_id, tmp_buff[0], &tmp_buff[1], (2 * len) - 1); 247 | if (dev->com_rslt != 0) 248 | rslt = BME680_E_COM_FAIL; 249 | } 250 | } else { 251 | rslt = BME680_E_INVALID_LENGTH; 252 | } 253 | } 254 | 255 | return rslt; 256 | } 257 | 258 | int8_t bme680_soft_reset(struct bme680_dev *dev) 259 | { 260 | int8_t rslt; 261 | uint8_t reg_addr = BME680_SOFT_RESET_ADDR; 262 | /* 0xb6 is the soft reset command */ 263 | uint8_t soft_rst_cmd = BME680_SOFT_RESET_CMD; 264 | 265 | /* Check for null pointer in the device structure*/ 266 | rslt = null_ptr_check(dev); 267 | if (rslt == BME680_OK) { 268 | if (dev->intf == BME680_SPI_INTF) 269 | rslt = get_mem_page(dev); 270 | 271 | /* Reset the device */ 272 | if (rslt == BME680_OK) { 273 | rslt = bme680_set_regs(®_addr, &soft_rst_cmd, 1, dev); 274 | /* Wait for 5ms */ 275 | dev->delay_ms(BME680_RESET_PERIOD); 276 | 277 | if (rslt == BME680_OK) { 278 | /* After reset get the memory page */ 279 | if (dev->intf == BME680_SPI_INTF) 280 | rslt = get_mem_page(dev); 281 | } 282 | } 283 | } 284 | 285 | return rslt; 286 | } 287 | 288 | int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) 289 | { 290 | int8_t rslt; 291 | uint8_t reg_addr; 292 | uint8_t data = 0; 293 | uint8_t count = 0; 294 | uint8_t reg_array[BME680_REG_BUFFER_LENGTH] = { 0 }; 295 | uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 }; 296 | uint8_t intended_power_mode = dev->power_mode; /* Save intended power mode */ 297 | 298 | /* Check for null pointer in the device structure*/ 299 | rslt = null_ptr_check(dev); 300 | if (rslt == BME680_OK) { 301 | if (desired_settings & BME680_GAS_MEAS_SEL) 302 | rslt = set_gas_config(dev); 303 | 304 | dev->power_mode = BME680_SLEEP_MODE; 305 | if (rslt == BME680_OK) 306 | rslt = bme680_set_sensor_mode(dev); 307 | 308 | /* Selecting the filter */ 309 | if (desired_settings & BME680_FILTER_SEL) { 310 | rslt = boundary_check(&dev->tph_sett.filter, BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127, dev); 311 | reg_addr = BME680_CONF_ODR_FILT_ADDR; 312 | 313 | if (rslt == BME680_OK) 314 | rslt = bme680_get_regs(reg_addr, &data, 1, dev); 315 | 316 | if (desired_settings & BME680_FILTER_SEL) 317 | data = BME680_SET_BITS(data, BME680_FILTER, dev->tph_sett.filter); 318 | 319 | reg_array[count] = reg_addr; /* Append configuration */ 320 | data_array[count] = data; 321 | count++; 322 | } 323 | 324 | /* Selecting heater control for the sensor */ 325 | if (desired_settings & BME680_HCNTRL_SEL) { 326 | rslt = boundary_check(&dev->gas_sett.heatr_ctrl, BME680_ENABLE_HEATER, 327 | BME680_DISABLE_HEATER, dev); 328 | reg_addr = BME680_CONF_HEAT_CTRL_ADDR; 329 | 330 | if (rslt == BME680_OK) 331 | rslt = bme680_get_regs(reg_addr, &data, 1, dev); 332 | data = BME680_SET_BITS_POS_0(data, BME680_HCTRL, dev->gas_sett.heatr_ctrl); 333 | 334 | reg_array[count] = reg_addr; /* Append configuration */ 335 | data_array[count] = data; 336 | count++; 337 | } 338 | 339 | /* Selecting heater T,P oversampling for the sensor */ 340 | if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { 341 | rslt = boundary_check(&dev->tph_sett.os_temp, BME680_OS_NONE, BME680_OS_16X, dev); 342 | reg_addr = BME680_CONF_T_P_MODE_ADDR; 343 | 344 | if (rslt == BME680_OK) 345 | rslt = bme680_get_regs(reg_addr, &data, 1, dev); 346 | 347 | if (desired_settings & BME680_OST_SEL) 348 | data = BME680_SET_BITS(data, BME680_OST, dev->tph_sett.os_temp); 349 | 350 | if (desired_settings & BME680_OSP_SEL) 351 | data = BME680_SET_BITS(data, BME680_OSP, dev->tph_sett.os_pres); 352 | 353 | reg_array[count] = reg_addr; 354 | data_array[count] = data; 355 | count++; 356 | } 357 | 358 | /* Selecting humidity oversampling for the sensor */ 359 | if (desired_settings & BME680_OSH_SEL) { 360 | rslt = boundary_check(&dev->tph_sett.os_hum, BME680_OS_NONE, BME680_OS_16X, dev); 361 | reg_addr = BME680_CONF_OS_H_ADDR; 362 | 363 | if (rslt == BME680_OK) 364 | rslt = bme680_get_regs(reg_addr, &data, 1, dev); 365 | data = BME680_SET_BITS_POS_0(data, BME680_OSH, dev->tph_sett.os_hum); 366 | 367 | reg_array[count] = reg_addr; /* Append configuration */ 368 | data_array[count] = data; 369 | count++; 370 | } 371 | 372 | /* Selecting the runGas and NB conversion settings for the sensor */ 373 | if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { 374 | rslt = boundary_check(&dev->gas_sett.run_gas, BME680_RUN_GAS_DISABLE, 375 | BME680_RUN_GAS_ENABLE, dev); 376 | if (rslt == BME680_OK) { 377 | /* Validate boundary conditions */ 378 | rslt = boundary_check(&dev->gas_sett.nb_conv, BME680_NBCONV_MIN, 379 | BME680_NBCONV_MAX, dev); 380 | } 381 | 382 | reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR; 383 | 384 | if (rslt == BME680_OK) 385 | rslt = bme680_get_regs(reg_addr, &data, 1, dev); 386 | 387 | if (desired_settings & BME680_RUN_GAS_SEL) 388 | data = BME680_SET_BITS(data, BME680_RUN_GAS, dev->gas_sett.run_gas); 389 | 390 | if (desired_settings & BME680_NBCONV_SEL) 391 | data = BME680_SET_BITS_POS_0(data, BME680_NBCONV, dev->gas_sett.nb_conv); 392 | 393 | reg_array[count] = reg_addr; /* Append configuration */ 394 | data_array[count] = data; 395 | count++; 396 | } 397 | 398 | if (rslt == BME680_OK) 399 | rslt = bme680_set_regs(reg_array, data_array, count, dev); 400 | 401 | /* Restore previous intended power mode */ 402 | dev->power_mode = intended_power_mode; 403 | } 404 | 405 | return rslt; 406 | } 407 | 408 | int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) 409 | { 410 | int8_t rslt; 411 | /* starting address of the register array for burst read*/ 412 | uint8_t reg_addr = BME680_CONF_HEAT_CTRL_ADDR; 413 | uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 }; 414 | 415 | /* Check for null pointer in the device structure*/ 416 | rslt = null_ptr_check(dev); 417 | if (rslt == BME680_OK) { 418 | rslt = bme680_get_regs(reg_addr, data_array, BME680_REG_BUFFER_LENGTH, dev); 419 | 420 | if (rslt == BME680_OK) { 421 | if (desired_settings & BME680_GAS_MEAS_SEL) 422 | rslt = get_gas_config(dev); 423 | 424 | /* get the T,P,H ,Filter,ODR settings here */ 425 | if (desired_settings & BME680_FILTER_SEL) 426 | dev->tph_sett.filter = BME680_GET_BITS(data_array[BME680_REG_FILTER_INDEX], 427 | BME680_FILTER); 428 | 429 | if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { 430 | dev->tph_sett.os_temp = BME680_GET_BITS(data_array[BME680_REG_TEMP_INDEX], BME680_OST); 431 | dev->tph_sett.os_pres = BME680_GET_BITS(data_array[BME680_REG_PRES_INDEX], BME680_OSP); 432 | } 433 | 434 | if (desired_settings & BME680_OSH_SEL) 435 | dev->tph_sett.os_hum = BME680_GET_BITS_POS_0(data_array[BME680_REG_HUM_INDEX], 436 | BME680_OSH); 437 | 438 | /* get the gas related settings */ 439 | if (desired_settings & BME680_HCNTRL_SEL) 440 | dev->gas_sett.heatr_ctrl = BME680_GET_BITS_POS_0(data_array[BME680_REG_HCTRL_INDEX], 441 | BME680_HCTRL); 442 | 443 | if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { 444 | dev->gas_sett.nb_conv = BME680_GET_BITS_POS_0(data_array[BME680_REG_NBCONV_INDEX], 445 | BME680_NBCONV); 446 | dev->gas_sett.run_gas = BME680_GET_BITS(data_array[BME680_REG_RUN_GAS_INDEX], 447 | BME680_RUN_GAS); 448 | } 449 | } 450 | } else { 451 | rslt = BME680_E_NULL_PTR; 452 | } 453 | 454 | return rslt; 455 | } 456 | 457 | int8_t bme680_set_sensor_mode(struct bme680_dev *dev) 458 | { 459 | int8_t rslt; 460 | uint8_t tmp_pow_mode; 461 | uint8_t pow_mode = 0; 462 | uint8_t reg_addr = BME680_CONF_T_P_MODE_ADDR; 463 | 464 | /* Check for null pointer in the device structure*/ 465 | rslt = null_ptr_check(dev); 466 | if (rslt == BME680_OK) { 467 | /* Call recursively until in sleep */ 468 | do { 469 | rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &tmp_pow_mode, 1, dev); 470 | if (rslt == BME680_OK) { 471 | /* Put to sleep before changing mode */ 472 | pow_mode = (tmp_pow_mode & BME680_MODE_MSK); 473 | 474 | if (pow_mode != BME680_SLEEP_MODE) { 475 | tmp_pow_mode = tmp_pow_mode & (~BME680_MODE_MSK); /* Set to sleep */ 476 | rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); 477 | dev->delay_ms(BME680_POLL_PERIOD_MS); 478 | } 479 | } 480 | } while (pow_mode != BME680_SLEEP_MODE); 481 | 482 | /* Already in sleep */ 483 | if (dev->power_mode != BME680_SLEEP_MODE) { 484 | tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK) | (dev->power_mode & BME680_MODE_MSK); 485 | if (rslt == BME680_OK) 486 | rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); 487 | } 488 | } 489 | 490 | return rslt; 491 | } 492 | 493 | int8_t bme680_get_sensor_mode(struct bme680_dev *dev) 494 | { 495 | int8_t rslt; 496 | uint8_t mode; 497 | 498 | /* Check for null pointer in the device structure*/ 499 | rslt = null_ptr_check(dev); 500 | if (rslt == BME680_OK) { 501 | rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &mode, 1, dev); 502 | /* Masking the other register bit info*/ 503 | dev->power_mode = mode & BME680_MODE_MSK; 504 | } 505 | 506 | return rslt; 507 | } 508 | 509 | void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev) 510 | { 511 | uint32_t tph_dur; /* Calculate in us */ 512 | 513 | /* TPH measurement duration */ 514 | tph_dur = ((uint32_t) (dev->tph_sett.os_temp + dev->tph_sett.os_pres + dev->tph_sett.os_hum) * UINT32_C(1963)); 515 | tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ 516 | tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ 517 | tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ 518 | tph_dur /= UINT32_C(1000); /* Convert to ms */ 519 | 520 | tph_dur += UINT32_C(1); /* Wake up duration of 1ms */ 521 | /* The remaining time should be used for heating */ 522 | dev->gas_sett.heatr_dur = duration - (uint16_t) tph_dur; 523 | } 524 | 525 | void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev) 526 | { 527 | uint32_t tph_dur; /* Calculate in us */ 528 | 529 | /* TPH measurement duration */ 530 | tph_dur = ((uint32_t) (dev->tph_sett.os_temp + dev->tph_sett.os_pres + dev->tph_sett.os_hum) * UINT32_C(1963)); 531 | tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ 532 | tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ 533 | tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ 534 | tph_dur /= UINT32_C(1000); /* Convert to ms */ 535 | 536 | tph_dur += UINT32_C(1); /* Wake up duration of 1ms */ 537 | 538 | *duration = (uint16_t) tph_dur; 539 | 540 | /* Get the gas duration only when the run gas is enabled */ 541 | if (dev->gas_sett.run_gas) { 542 | /* The remaining time should be used for heating */ 543 | *duration += dev->gas_sett.heatr_dur; 544 | } 545 | } 546 | 547 | int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev) 548 | { 549 | int8_t rslt; 550 | 551 | /* Check for null pointer in the device structure*/ 552 | rslt = null_ptr_check(dev); 553 | if (rslt == BME680_OK) { 554 | /* Reading the sensor data in forced mode only */ 555 | rslt = read_field_data(data, dev); 556 | if (rslt == BME680_OK) { 557 | if (data->status & BME680_NEW_DATA_MSK) 558 | dev->new_fields = 1; 559 | else 560 | dev->new_fields = 0; 561 | } 562 | } 563 | 564 | return rslt; 565 | } 566 | 567 | static int8_t get_calib_data(struct bme680_dev *dev) 568 | { 569 | int8_t rslt; 570 | uint8_t coeff_array[BME680_COEFF_SIZE] = { 0 }; 571 | uint8_t temp_var = 0; /* Temporary variable */ 572 | 573 | /* Check for null pointer in the device structure*/ 574 | rslt = null_ptr_check(dev); 575 | if (rslt == BME680_OK) { 576 | rslt = bme680_get_regs(BME680_COEFF_ADDR1, coeff_array, BME680_COEFF_ADDR1_LEN, dev); 577 | /* Append the second half in the same array */ 578 | if (rslt == BME680_OK) 579 | rslt = bme680_get_regs(BME680_COEFF_ADDR2, &coeff_array[BME680_COEFF_ADDR1_LEN] 580 | , BME680_COEFF_ADDR2_LEN, dev); 581 | 582 | /* Temperature related coefficients */ 583 | dev->calib.par_t1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T1_MSB_REG], 584 | coeff_array[BME680_T1_LSB_REG])); 585 | dev->calib.par_t2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T2_MSB_REG], 586 | coeff_array[BME680_T2_LSB_REG])); 587 | dev->calib.par_t3 = (int8_t) (coeff_array[BME680_T3_REG]); 588 | 589 | /* Pressure related coefficients */ 590 | dev->calib.par_p1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P1_MSB_REG], 591 | coeff_array[BME680_P1_LSB_REG])); 592 | dev->calib.par_p2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P2_MSB_REG], 593 | coeff_array[BME680_P2_LSB_REG])); 594 | dev->calib.par_p3 = (int8_t) coeff_array[BME680_P3_REG]; 595 | dev->calib.par_p4 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P4_MSB_REG], 596 | coeff_array[BME680_P4_LSB_REG])); 597 | dev->calib.par_p5 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P5_MSB_REG], 598 | coeff_array[BME680_P5_LSB_REG])); 599 | dev->calib.par_p6 = (int8_t) (coeff_array[BME680_P6_REG]); 600 | dev->calib.par_p7 = (int8_t) (coeff_array[BME680_P7_REG]); 601 | dev->calib.par_p8 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P8_MSB_REG], 602 | coeff_array[BME680_P8_LSB_REG])); 603 | dev->calib.par_p9 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P9_MSB_REG], 604 | coeff_array[BME680_P9_LSB_REG])); 605 | dev->calib.par_p10 = (uint8_t) (coeff_array[BME680_P10_REG]); 606 | 607 | /* Humidity related coefficients */ 608 | dev->calib.par_h1 = (uint16_t) (((uint16_t) coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) 609 | | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); 610 | dev->calib.par_h2 = (uint16_t) (((uint16_t) coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) 611 | | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); 612 | dev->calib.par_h3 = (int8_t) coeff_array[BME680_H3_REG]; 613 | dev->calib.par_h4 = (int8_t) coeff_array[BME680_H4_REG]; 614 | dev->calib.par_h5 = (int8_t) coeff_array[BME680_H5_REG]; 615 | dev->calib.par_h6 = (uint8_t) coeff_array[BME680_H6_REG]; 616 | dev->calib.par_h7 = (int8_t) coeff_array[BME680_H7_REG]; 617 | 618 | /* Gas heater related coefficients */ 619 | dev->calib.par_gh1 = (int8_t) coeff_array[BME680_GH1_REG]; 620 | dev->calib.par_gh2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_GH2_MSB_REG], 621 | coeff_array[BME680_GH2_LSB_REG])); 622 | dev->calib.par_gh3 = (int8_t) coeff_array[BME680_GH3_REG]; 623 | 624 | /* Other coefficients */ 625 | if (rslt == BME680_OK) { 626 | rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_RANGE_ADDR, &temp_var, 1, dev); 627 | 628 | dev->calib.res_heat_range = ((temp_var & BME680_RHRANGE_MSK) / 16); 629 | if (rslt == BME680_OK) { 630 | rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_VAL_ADDR, &temp_var, 1, dev); 631 | 632 | dev->calib.res_heat_val = (int8_t) temp_var; 633 | if (rslt == BME680_OK) 634 | rslt = bme680_get_regs(BME680_ADDR_RANGE_SW_ERR_ADDR, &temp_var, 1, dev); 635 | } 636 | } 637 | dev->calib.range_sw_err = ((int8_t) temp_var & (int8_t) BME680_RSERROR_MSK) / 16; 638 | } 639 | 640 | return rslt; 641 | } 642 | 643 | static int8_t set_gas_config(struct bme680_dev *dev) 644 | { 645 | int8_t rslt; 646 | 647 | /* Check for null pointer in the device structure*/ 648 | rslt = null_ptr_check(dev); 649 | if (rslt == BME680_OK) { 650 | 651 | uint8_t reg_addr[2] = {0}; 652 | uint8_t reg_data[2] = {0}; 653 | 654 | if (dev->power_mode == BME680_FORCED_MODE) { 655 | reg_addr[0] = BME680_RES_HEAT0_ADDR; 656 | reg_data[0] = calc_heater_res(dev->gas_sett.heatr_temp, dev); 657 | reg_addr[1] = BME680_GAS_WAIT0_ADDR; 658 | reg_data[1] = calc_heater_dur(dev->gas_sett.heatr_dur); 659 | dev->gas_sett.nb_conv = 0; 660 | } else { 661 | rslt = BME680_W_DEFINE_PWR_MODE; 662 | } 663 | if (rslt == BME680_OK) 664 | rslt = bme680_set_regs(reg_addr, reg_data, 2, dev); 665 | } 666 | 667 | return rslt; 668 | } 669 | 670 | static int8_t get_gas_config(struct bme680_dev *dev) 671 | { 672 | int8_t rslt; 673 | /* starting address of the register array for burst read*/ 674 | uint8_t reg_addr1 = BME680_ADDR_SENS_CONF_START; 675 | uint8_t reg_addr2 = BME680_ADDR_GAS_CONF_START; 676 | uint8_t data_array[BME680_GAS_HEATER_PROF_LEN_MAX] = { 0 }; 677 | uint8_t index; 678 | 679 | /* Check for null pointer in the device structure*/ 680 | rslt = null_ptr_check(dev); 681 | if (rslt == BME680_OK) { 682 | if (BME680_SPI_INTF == dev->intf) { 683 | /* Memory page switch the SPI address*/ 684 | rslt = set_mem_page(reg_addr1, dev); 685 | } 686 | 687 | if (rslt == BME680_OK) { 688 | rslt = bme680_get_regs(reg_addr1, data_array, BME680_GAS_HEATER_PROF_LEN_MAX, dev); 689 | if (rslt == BME680_OK) { 690 | for (index = 0; index < BME680_GAS_HEATER_PROF_LEN_MAX; index++) 691 | dev->gas_sett.heatr_temp = data_array[index]; 692 | } 693 | 694 | rslt = bme680_get_regs(reg_addr2, data_array, BME680_GAS_HEATER_PROF_LEN_MAX, dev); 695 | if (rslt == BME680_OK) { 696 | for (index = 0; index < BME680_GAS_HEATER_PROF_LEN_MAX; index++) 697 | dev->gas_sett.heatr_dur = data_array[index]; 698 | } 699 | } 700 | } 701 | 702 | return rslt; 703 | } 704 | 705 | static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev) 706 | { 707 | int64_t var1; 708 | int64_t var2; 709 | int64_t var3; 710 | int16_t calc_temp; 711 | 712 | var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dev->calib.par_t1 << 1); 713 | var2 = (var1 * (int32_t) dev->calib.par_t2) >> 11; 714 | var3 = ((var1 >> 1) * (var1 >> 1)) >> 12; 715 | var3 = ((var3) * ((int32_t) dev->calib.par_t3 << 4)) >> 14; 716 | dev->calib.t_fine = (int32_t) (var2 + var3); 717 | calc_temp = (int16_t) (((dev->calib.t_fine * 5) + 128) >> 8); 718 | 719 | return calc_temp; 720 | } 721 | 722 | static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev) 723 | { 724 | int32_t var1 = 0; 725 | int32_t var2 = 0; 726 | int32_t var3 = 0; 727 | int32_t var4 = 0; 728 | int32_t pressure_comp = 0; 729 | 730 | var1 = (((int32_t)dev->calib.t_fine) >> 1) - 64000; 731 | var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * 732 | (int32_t)dev->calib.par_p6) >> 2; 733 | var2 = var2 + ((var1 * (int32_t)dev->calib.par_p5) << 1); 734 | var2 = (var2 >> 2) + ((int32_t)dev->calib.par_p4 << 16); 735 | var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * 736 | ((int32_t)dev->calib.par_p3 << 5)) >> 3) + 737 | (((int32_t)dev->calib.par_p2 * var1) >> 1); 738 | var1 = var1 >> 18; 739 | var1 = ((32768 + var1) * (int32_t)dev->calib.par_p1) >> 15; 740 | pressure_comp = 1048576 - pres_adc; 741 | pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125)); 742 | var4 = (1 << 31); 743 | if (pressure_comp >= var4) 744 | pressure_comp = ((pressure_comp / (uint32_t)var1) << 1); 745 | else 746 | pressure_comp = ((pressure_comp << 1) / (uint32_t)var1); 747 | var1 = ((int32_t)dev->calib.par_p9 * (int32_t)(((pressure_comp >> 3) * 748 | (pressure_comp >> 3)) >> 13)) >> 12; 749 | var2 = ((int32_t)(pressure_comp >> 2) * 750 | (int32_t)dev->calib.par_p8) >> 13; 751 | var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) * 752 | (int32_t)(pressure_comp >> 8) * 753 | (int32_t)dev->calib.par_p10) >> 17; 754 | 755 | pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 + 756 | ((int32_t)dev->calib.par_p7 << 7)) >> 4); 757 | 758 | return (uint32_t)pressure_comp; 759 | 760 | } 761 | 762 | static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev) 763 | { 764 | int32_t var1; 765 | int32_t var2; 766 | int32_t var3; 767 | int32_t var4; 768 | int32_t var5; 769 | int32_t var6; 770 | int32_t temp_scaled; 771 | int32_t calc_hum; 772 | 773 | temp_scaled = (((int32_t) dev->calib.t_fine * 5) + 128) >> 8; 774 | var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) dev->calib.par_h1 * 16))) 775 | - (((temp_scaled * (int32_t) dev->calib.par_h3) / ((int32_t) 100)) >> 1); 776 | var2 = ((int32_t) dev->calib.par_h2 777 | * (((temp_scaled * (int32_t) dev->calib.par_h4) / ((int32_t) 100)) 778 | + (((temp_scaled * ((temp_scaled * (int32_t) dev->calib.par_h5) / ((int32_t) 100))) >> 6) 779 | / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10; 780 | var3 = var1 * var2; 781 | var4 = (int32_t) dev->calib.par_h6 << 7; 782 | var4 = ((var4) + ((temp_scaled * (int32_t) dev->calib.par_h7) / ((int32_t) 100))) >> 4; 783 | var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; 784 | var6 = (var4 * var5) >> 1; 785 | calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12; 786 | 787 | if (calc_hum > 100000) /* Cap at 100%rH */ 788 | calc_hum = 100000; 789 | else if (calc_hum < 0) 790 | calc_hum = 0; 791 | 792 | return (uint32_t) calc_hum; 793 | } 794 | 795 | uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, struct bme680_dev *dev) 796 | { 797 | int64_t var1; 798 | uint64_t var2; 799 | int64_t var3; 800 | uint32_t calc_gas_res; 801 | 802 | var1 = (int64_t) ((1340 + (5 * (int64_t) dev->calib.range_sw_err)) * 803 | ((int64_t) lookupTable1[gas_range])) >> 16; 804 | var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1); 805 | var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9); 806 | calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2); 807 | 808 | return calc_gas_res; 809 | } 810 | 811 | static uint8_t calc_heater_res(uint16_t temp, const struct bme680_dev *dev) 812 | { 813 | uint8_t heatr_res; 814 | int32_t var1; 815 | int32_t var2; 816 | int32_t var3; 817 | int32_t var4; 818 | int32_t var5; 819 | int32_t heatr_res_x100; 820 | 821 | if (temp < 200) /* Cap temperature */ 822 | temp = 200; 823 | else if (temp > 400) 824 | temp = 400; 825 | 826 | var1 = (((int32_t) dev->amb_temp * dev->calib.par_gh3) / 1000) * 256; 827 | var2 = (dev->calib.par_gh1 + 784) * (((((dev->calib.par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10); 828 | var3 = var1 + (var2 / 2); 829 | var4 = (var3 / (dev->calib.res_heat_range + 4)); 830 | var5 = (131 * dev->calib.res_heat_val) + 65536; 831 | heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34); 832 | heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100); 833 | 834 | return heatr_res; 835 | } 836 | 837 | static uint8_t calc_heater_dur(uint16_t dur) 838 | { 839 | uint8_t factor = 0; 840 | uint8_t durval; 841 | 842 | if (dur >= 0xfc0) { 843 | durval = 0xff; /* Max duration*/ 844 | } else { 845 | while (dur > 0x3F) { 846 | dur = dur / 4; 847 | factor += 1; 848 | } 849 | durval = (uint8_t) (dur + (factor * 64)); 850 | } 851 | 852 | return durval; 853 | } 854 | 855 | static int8_t read_field_data(struct bme680_field_data *data, struct bme680_dev *dev) 856 | { 857 | int8_t rslt; 858 | uint8_t buff[BME680_FIELD_LENGTH] = { 0 }; 859 | uint8_t gas_range; 860 | uint32_t adc_temp; 861 | uint32_t adc_pres; 862 | uint16_t adc_hum; 863 | uint16_t adc_gas_res; 864 | uint8_t tries = 10; 865 | 866 | /* Check for null pointer in the device structure*/ 867 | rslt = null_ptr_check(dev); 868 | do { 869 | if (rslt == BME680_OK) { 870 | rslt = bme680_get_regs(((uint8_t) (BME680_FIELD0_ADDR)), buff, (uint16_t) BME680_FIELD_LENGTH, 871 | dev); 872 | 873 | data->status = buff[0] & BME680_NEW_DATA_MSK; 874 | data->gas_index = buff[0] & BME680_GAS_INDEX_MSK; 875 | data->meas_index = buff[1]; 876 | 877 | /* read the raw data from the sensor */ 878 | adc_pres = (uint32_t) (((uint32_t) buff[2] * 4096) | ((uint32_t) buff[3] * 16) 879 | | ((uint32_t) buff[4] / 16)); 880 | adc_temp = (uint32_t) (((uint32_t) buff[5] * 4096) | ((uint32_t) buff[6] * 16) 881 | | ((uint32_t) buff[7] / 16)); 882 | adc_hum = (uint16_t) (((uint32_t) buff[8] * 256) | (uint32_t) buff[9]); 883 | adc_gas_res = (uint16_t) ((uint32_t) buff[13] * 4 | (((uint32_t) buff[14]) / 64)); 884 | gas_range = buff[14] & BME680_GAS_RANGE_MSK; 885 | 886 | data->status |= buff[14] & BME680_GASM_VALID_MSK; 887 | data->status |= buff[14] & BME680_HEAT_STAB_MSK; 888 | 889 | if (data->status & BME680_NEW_DATA_MSK) { 890 | data->temperature = calc_temperature(adc_temp, dev); 891 | data->pressure = calc_pressure(adc_pres, dev); 892 | data->humidity = calc_humidity(adc_hum, dev); 893 | data->gas_resistance = calc_gas_resistance(adc_gas_res, gas_range, dev); 894 | break; 895 | } 896 | /* Delay to poll the data */ 897 | dev->delay_ms(BME680_POLL_PERIOD_MS); 898 | } 899 | tries--; 900 | } while (tries); 901 | 902 | if (!tries) 903 | rslt = BME680_W_NO_NEW_DATA; 904 | 905 | return rslt; 906 | } 907 | 908 | static int8_t set_mem_page(uint8_t reg_addr, struct bme680_dev *dev) 909 | { 910 | int8_t rslt; 911 | uint8_t reg; 912 | uint8_t mem_page; 913 | 914 | /* Check for null pointers in the device structure*/ 915 | rslt = null_ptr_check(dev); 916 | if (rslt == BME680_OK) { 917 | if (reg_addr > 0x7f) 918 | mem_page = BME680_MEM_PAGE1; 919 | else 920 | mem_page = BME680_MEM_PAGE0; 921 | 922 | if (mem_page != dev->mem_page) { 923 | dev->mem_page = mem_page; 924 | 925 | dev->com_rslt = dev->read(dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); 926 | if (dev->com_rslt != 0) 927 | rslt = BME680_E_COM_FAIL; 928 | 929 | if (rslt == BME680_OK) { 930 | reg = reg & (~BME680_MEM_PAGE_MSK); 931 | reg = reg | (dev->mem_page & BME680_MEM_PAGE_MSK); 932 | 933 | dev->com_rslt = dev->write(dev->dev_id, BME680_MEM_PAGE_ADDR & BME680_SPI_WR_MSK, 934 | ®, 1); 935 | if (dev->com_rslt != 0) 936 | rslt = BME680_E_COM_FAIL; 937 | } 938 | } 939 | } 940 | 941 | return rslt; 942 | } 943 | 944 | static int8_t get_mem_page(struct bme680_dev *dev) 945 | { 946 | int8_t rslt; 947 | uint8_t reg; 948 | 949 | /* Check for null pointer in the device structure*/ 950 | rslt = null_ptr_check(dev); 951 | if (rslt == BME680_OK) { 952 | dev->com_rslt = dev->read(dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); 953 | if (dev->com_rslt != 0) 954 | rslt = BME680_E_COM_FAIL; 955 | else 956 | dev->mem_page = reg & BME680_MEM_PAGE_MSK; 957 | } 958 | 959 | return rslt; 960 | } 961 | 962 | static int8_t boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev) 963 | { 964 | int8_t rslt = BME680_OK; 965 | 966 | if (value != NULL) { 967 | /* Check if value is below minimum value */ 968 | if (*value < min) { 969 | /* Auto correct the invalid value to minimum value */ 970 | *value = min; 971 | dev->info_msg |= BME680_I_MIN_CORRECTION; 972 | } 973 | /* Check if value is above maximum value */ 974 | if (*value > max) { 975 | /* Auto correct the invalid value to maximum value */ 976 | *value = max; 977 | dev->info_msg |= BME680_I_MAX_CORRECTION; 978 | } 979 | } else { 980 | rslt = BME680_E_NULL_PTR; 981 | } 982 | 983 | return rslt; 984 | } 985 | 986 | static int8_t null_ptr_check(const struct bme680_dev *dev) 987 | { 988 | int8_t rslt; 989 | 990 | if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) { 991 | /* Device structure pointer is not valid */ 992 | rslt = BME680_E_NULL_PTR; 993 | } else { 994 | /* Device structure is fine */ 995 | rslt = BME680_OK; 996 | } 997 | 998 | return rslt; 999 | } 1000 | -------------------------------------------------------------------------------- /bme680.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file bme680.h 3 | * 4 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 5 | * @license The MIT License (MIT) 6 | * @author Frank(jiehan.guo@dfrobot.com) 7 | * @version V1.0 8 | * @date 2017-12-04 9 | * @url https://github.com/DFRobot/DFRobot_BME680 10 | */ 11 | 12 | #ifndef BME680_H_ 13 | #define BME680_H_ 14 | 15 | /*! CPP guard */ 16 | #ifdef __cplusplus 17 | extern "C" 18 | { 19 | #endif 20 | 21 | /* Header includes */ 22 | #include "bme680_defs.h" 23 | 24 | /** 25 | * @fn bme680_init 26 | * @brief This API is the entry point. 27 | * @n It reads the chip-id and calibration data from the sensor. 28 | * @param dev : Structure instance of bme680_dev 29 | * @return Result of API execution status 30 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 31 | */ 32 | int8_t bme680_init(struct bme680_dev *dev); 33 | 34 | /** 35 | * @fn bme680_set_regs 36 | * @brief This API writes the given data to the register address of the sensor. 37 | * @param reg_addr : Register address from where the data to be written. 38 | * @param reg_data : Pointer to data buffer which is to be written in the sensor. 39 | * @param len : No of bytes of data to write.. 40 | * @param dev : Structure instance of bme680_dev. 41 | * @return Result of API execution status 42 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 43 | */ 44 | int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev); 45 | 46 | /** 47 | * @fn bme680_get_regs 48 | * @brief This API reads the data from the given register address of the sensor. 49 | * @param reg_addr : Register address from where the data to be read 50 | * @param reg_data : Pointer to data buffer to store the read data. 51 | * @param len : No of bytes of data to be read. 52 | * @param dev : Structure instance of bme680_dev. 53 | * @return Result of API execution status 54 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 55 | */ 56 | int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev); 57 | 58 | /** 59 | * @fn bme680_soft_reset 60 | * @brief This API performs the soft reset of the sensor. 61 | * @param dev : Structure instance of bme680_dev. 62 | * 63 | * @return Result of API execution status 64 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. 65 | */ 66 | int8_t bme680_soft_reset(struct bme680_dev *dev); 67 | 68 | /** 69 | * @fn bme680_set_sensor_mode 70 | * @brief This API is used to set the power mode of the sensor. 71 | * @param dev : Structure instance of bme680_dev 72 | * @note : Pass the value to bme680_dev.power_mode structure variable. 73 | * @n value | mode 74 | * @n ------|------------------ 75 | * @n 0x00 | BME680_SLEEP_MODE 76 | * @n 0x01 | BME680_FORCED_MODE 77 | * 78 | * @return Result of API execution status 79 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 80 | */ 81 | int8_t bme680_set_sensor_mode(struct bme680_dev *dev); 82 | 83 | /** 84 | * @brief This API is used to get the power mode of the sensor. 85 | * @param dev : Structure instance of bme680_dev 86 | * @note : bme680_dev.power_mode structure variable hold the power mode. 87 | * @n 88 | * @n value | mode 89 | * @n ---------|------------------ 90 | * @n 0x00 | BME680_SLEEP_MODE 91 | * @n 0x01 | BME680_FORCED_MODE 92 | * @return Result of API execution status 93 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 94 | */ 95 | int8_t bme680_get_sensor_mode(struct bme680_dev *dev); 96 | 97 | /** 98 | * @brief This API is used to set the profile duration of the sensor. 99 | * @param dev : Structure instance of bme680_dev. 100 | * @param duration : Duration of the measurement in ms. 101 | * @return Nothing 102 | */ 103 | void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev); 104 | 105 | /** 106 | * @fn bme680_get_profile_dur 107 | * @brief This API is used to get the profile duration of the sensor. 108 | * 109 | * @param duration : Duration of the measurement in ms. 110 | * @param dev : Structure instance of bme680_dev. 111 | * @return Nothing 112 | */ 113 | void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev); 114 | 115 | /** 116 | * @fn bme680_get_sensor_data 117 | * @brief This API reads the pressure, temperature and humidity and gas data 118 | * @n from the sensor, compensates the data and store it in the bme680_data 119 | * @n structure instance passed by the user. 120 | * @param data: Structure instance to hold the data. 121 | * @param dev : Structure instance of bme680_dev. 122 | * 123 | * @return Result of API execution status 124 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error 125 | */ 126 | int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev); 127 | 128 | /** 129 | * @fn bme680_set_sensor_settings 130 | * @brief This API is used to set the oversampling, filter and T,P,H, gas selection settings in the sensor. 131 | * 132 | * @param desired_settings : Variable used to select the settings which are to be set in the sensor. 133 | * @n 134 | * @n Macros | Functionality 135 | * @n ---------------------------------|---------------------------------------------- 136 | * @n BME680_OST_SEL | To set temperature oversampling. 137 | * @n BME680_OSP_SEL | To set pressure oversampling. 138 | * @n BME680_OSH_SEL | To set humidity oversampling. 139 | * @n BME680_GAS_MEAS_SEL | To set gas measurement setting. 140 | * @n BME680_FILTER_SEL | To set filter setting. 141 | * @n BME680_HCNTRL_SEL | To set humidity control setting. 142 | * @n BME680_RUN_GAS_SEL | To set run gas setting. 143 | * @n BME680_NBCONV_SEL | To set NB conversion setting. 144 | * @n BME680_GAS_SENSOR_SEL | To set all gas sensor related settings 145 | * @param dev : Structure instance of bme680_dev. 146 | * 147 | * @note : Below are the macros to be used by the user for selecting the 148 | * @n desired settings. User can do OR operation of these macros for configuring multiple settings. 149 | * 150 | * @return Result of API execution status 151 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. 152 | */ 153 | int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev); 154 | 155 | /** 156 | * @fn bme680_get_sensor_settings 157 | * @brief This API is used to get the oversampling, filter and T,P,H, gas selection 158 | * @n settings in the sensor. 159 | * 160 | * @param desired_settings : Variable used to select the settings which 161 | * @n are to be get from the sensor. 162 | * @param dev : Structure instance of bme680_dev. 163 | * 164 | * @return Result of API execution status 165 | * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. 166 | */ 167 | int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev); 168 | 169 | uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, struct bme680_dev *dev); 170 | #ifdef __cplusplus 171 | } 172 | #endif 173 | #endif -------------------------------------------------------------------------------- /bme680_defs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bme680_defs.h 3 | * @brief Sensor driver for BME680 sensor. 4 | * 5 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 6 | * @license The MIT License (MIT) 7 | * @author Frank(jiehan.guo@dfrobot.com) 8 | * @version V1.0 9 | * @date 2017-12-04 10 | * @url https://github.com/DFRobot/DFRobot_BME680 11 | */ 12 | 13 | #ifndef BME680_DEFS_H_ 14 | #define BME680_DEFS_H_ 15 | 16 | /********************************************************/ 17 | /* header includes */ 18 | #ifdef __KERNEL__ 19 | #include 20 | #include 21 | #else 22 | #include 23 | #include 24 | #endif 25 | 26 | /******************************************************************************/ 27 | /*! @name Common macros */ 28 | /******************************************************************************/ 29 | 30 | #if !defined(UINT8_C) && !defined(INT8_C) 31 | #define INT8_C(x) (x) 32 | #define UINT8_C(x) (x) 33 | #endif 34 | 35 | #if !defined(UINT16_C) && !defined(INT16_C) 36 | #define INT16_C(x) (x) 37 | #define UINT16_C(x) (x) 38 | #endif 39 | 40 | #if !defined(INT32_C) && !defined(UINT32_C) 41 | #define INT32_C(x) (x) 42 | #define UINT32_C(x) (x) 43 | #endif 44 | 45 | #if !defined(INT64_C) && !defined(UINT64_C) 46 | #define INT64_C(x) (x) 47 | #define UINT64_C(x) (x) 48 | #endif 49 | 50 | /**@}*/ 51 | 52 | /**\name C standard macros */ 53 | #ifndef NULL 54 | #ifdef __cplusplus 55 | #define NULL 0 56 | #else 57 | #define NULL ((void *) 0) 58 | #endif 59 | #endif 60 | 61 | /** BME680 General config */ 62 | #define BME680_POLL_PERIOD_MS UINT8_C(10) 63 | 64 | /** BME680 I2C addresses */ 65 | #define BME680_I2C_ADDR_PRIMARY UINT8_C(0x76) 66 | #define BME680_I2C_ADDR_SECONDARY UINT8_C(0x77) 67 | 68 | /** BME680 unique chip identifier */ 69 | #define BME680_CHIP_ID UINT8_C(0x61) 70 | 71 | /** BME680 coefficients related defines */ 72 | #define BME680_COEFF_SIZE UINT8_C(0x41) 73 | #define BME680_COEFF_ADDR1_LEN UINT8_C(25) 74 | #define BME680_COEFF_ADDR2_LEN UINT8_C(16) 75 | 76 | /** BME680 field_x related defines */ 77 | #define BME680_FIELD_LENGTH UINT8_C(15) 78 | #define BME680_FIELD_ADDR_OFFSET UINT8_C(17) 79 | 80 | /** Soft reset command */ 81 | #define BME680_SOFT_RESET_CMD UINT8_C(0xb6) 82 | 83 | /** Error code definitions */ 84 | #define BME680_OK INT8_C(0) 85 | /* Errors */ 86 | #define BME680_E_NULL_PTR INT8_C(-1) 87 | #define BME680_E_COM_FAIL INT8_C(-2) 88 | #define BME680_E_DEV_NOT_FOUND INT8_C(-3) 89 | #define BME680_E_INVALID_LENGTH INT8_C(-4) 90 | 91 | /* Warnings */ 92 | #define BME680_W_DEFINE_PWR_MODE INT8_C(1) 93 | #define BME680_W_NO_NEW_DATA INT8_C(2) 94 | 95 | /* Info's */ 96 | #define BME680_I_MIN_CORRECTION UINT8_C(1) 97 | #define BME680_I_MAX_CORRECTION UINT8_C(2) 98 | 99 | /** Register map */ 100 | /** Other coefficient's address */ 101 | #define BME680_ADDR_RES_HEAT_VAL_ADDR UINT8_C(0x00) 102 | #define BME680_ADDR_RES_HEAT_RANGE_ADDR UINT8_C(0x02) 103 | #define BME680_ADDR_RANGE_SW_ERR_ADDR UINT8_C(0x04) 104 | #define BME680_ADDR_SENS_CONF_START UINT8_C(0x5A) 105 | #define BME680_ADDR_GAS_CONF_START UINT8_C(0x64) 106 | 107 | /** Field settings */ 108 | #define BME680_FIELD0_ADDR UINT8_C(0x1d) 109 | 110 | /** Heater settings */ 111 | #define BME680_RES_HEAT0_ADDR UINT8_C(0x5a) 112 | #define BME680_GAS_WAIT0_ADDR UINT8_C(0x64) 113 | 114 | /** Sensor configuration registers */ 115 | #define BME680_CONF_HEAT_CTRL_ADDR UINT8_C(0x70) 116 | #define BME680_CONF_ODR_RUN_GAS_NBC_ADDR UINT8_C(0x71) 117 | #define BME680_CONF_OS_H_ADDR UINT8_C(0x72) 118 | #define BME680_MEM_PAGE_ADDR UINT8_C(0xf3) 119 | #define BME680_CONF_T_P_MODE_ADDR UINT8_C(0x74) 120 | #define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75) 121 | 122 | /** Coefficient's address */ 123 | #define BME680_COEFF_ADDR1 UINT8_C(0x89) 124 | #define BME680_COEFF_ADDR2 UINT8_C(0xe1) 125 | 126 | /** Chip identifier */ 127 | #define BME680_CHIP_ID_ADDR UINT8_C(0xd0) 128 | 129 | /** Soft reset register */ 130 | #define BME680_SOFT_RESET_ADDR UINT8_C(0xe0) 131 | 132 | /** Heater control settings */ 133 | #define BME680_ENABLE_HEATER UINT8_C(0x00) 134 | #define BME680_DISABLE_HEATER UINT8_C(0x08) 135 | 136 | /** Gas measurement settings */ 137 | #define BME680_DISABLE_GAS_MEAS UINT8_C(0x00) 138 | #define BME680_ENABLE_GAS_MEAS UINT8_C(0x01) 139 | 140 | /** Over-sampling settings */ 141 | #define BME680_OS_NONE UINT8_C(0) 142 | #define BME680_OS_1X UINT8_C(1) 143 | #define BME680_OS_2X UINT8_C(2) 144 | #define BME680_OS_4X UINT8_C(3) 145 | #define BME680_OS_8X UINT8_C(4) 146 | #define BME680_OS_16X UINT8_C(5) 147 | 148 | /** IIR filter settings */ 149 | #define BME680_FILTER_SIZE_0 UINT8_C(0) 150 | #define BME680_FILTER_SIZE_1 UINT8_C(1) 151 | #define BME680_FILTER_SIZE_3 UINT8_C(2) 152 | #define BME680_FILTER_SIZE_7 UINT8_C(3) 153 | #define BME680_FILTER_SIZE_15 UINT8_C(4) 154 | #define BME680_FILTER_SIZE_31 UINT8_C(5) 155 | #define BME680_FILTER_SIZE_63 UINT8_C(6) 156 | #define BME680_FILTER_SIZE_127 UINT8_C(7) 157 | 158 | /** Power mode settings */ 159 | #define BME680_SLEEP_MODE UINT8_C(0) 160 | #define BME680_FORCED_MODE UINT8_C(1) 161 | 162 | /** Delay related macro declaration */ 163 | #define BME680_RESET_PERIOD UINT32_C(10) 164 | 165 | /** SPI memory page settings */ 166 | #define BME680_MEM_PAGE0 UINT8_C(0x10) 167 | #define BME680_MEM_PAGE1 UINT8_C(0x00) 168 | 169 | /** Ambient humidity shift value for compensation */ 170 | #define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) 171 | 172 | /** Run gas enable and disable settings */ 173 | #define BME680_RUN_GAS_DISABLE UINT8_C(0) 174 | #define BME680_RUN_GAS_ENABLE UINT8_C(1) 175 | 176 | /** Buffer length macro declaration */ 177 | #define BME680_TMP_BUFFER_LENGTH UINT8_C(40) 178 | #define BME680_REG_BUFFER_LENGTH UINT8_C(6) 179 | #define BME680_FIELD_DATA_LENGTH UINT8_C(3) 180 | #define BME680_GAS_REG_BUF_LENGTH UINT8_C(20) 181 | #define BME680_GAS_HEATER_PROF_LEN_MAX UINT8_C(10) 182 | 183 | /** Settings selector */ 184 | #define BME680_OST_SEL UINT16_C(1) 185 | #define BME680_OSP_SEL UINT16_C(2) 186 | #define BME680_OSH_SEL UINT16_C(4) 187 | #define BME680_GAS_MEAS_SEL UINT16_C(8) 188 | #define BME680_FILTER_SEL UINT16_C(16) 189 | #define BME680_HCNTRL_SEL UINT16_C(32) 190 | #define BME680_RUN_GAS_SEL UINT16_C(64) 191 | #define BME680_NBCONV_SEL UINT16_C(128) 192 | #define BME680_GAS_SENSOR_SEL (BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) 193 | 194 | /** Number of conversion settings*/ 195 | #define BME680_NBCONV_MIN UINT8_C(0) 196 | #define BME680_NBCONV_MAX UINT8_C(10) 197 | 198 | /** Mask definitions */ 199 | #define BME680_GAS_MEAS_MSK UINT8_C(0x30) 200 | #define BME680_NBCONV_MSK UINT8_C(0X0F) 201 | #define BME680_FILTER_MSK UINT8_C(0X1C) 202 | #define BME680_OST_MSK UINT8_C(0XE0) 203 | #define BME680_OSP_MSK UINT8_C(0X1C) 204 | #define BME680_OSH_MSK UINT8_C(0X07) 205 | #define BME680_HCTRL_MSK UINT8_C(0x08) 206 | #define BME680_RUN_GAS_MSK UINT8_C(0x10) 207 | #define BME680_MODE_MSK UINT8_C(0x03) 208 | #define BME680_RHRANGE_MSK UINT8_C(0x30) 209 | #define BME680_RSERROR_MSK UINT8_C(0xf0) 210 | #define BME680_NEW_DATA_MSK UINT8_C(0x80) 211 | #define BME680_GAS_INDEX_MSK UINT8_C(0x0f) 212 | #define BME680_GAS_RANGE_MSK UINT8_C(0x0f) 213 | #define BME680_GASM_VALID_MSK UINT8_C(0x20) 214 | #define BME680_HEAT_STAB_MSK UINT8_C(0x10) 215 | #define BME680_MEM_PAGE_MSK UINT8_C(0x10) 216 | #define BME680_SPI_RD_MSK UINT8_C(0x80) 217 | #define BME680_SPI_WR_MSK UINT8_C(0x7f) 218 | #define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) 219 | 220 | /** Bit position definitions for sensor settings */ 221 | #define BME680_GAS_MEAS_POS UINT8_C(4) 222 | #define BME680_FILTER_POS UINT8_C(2) 223 | #define BME680_OST_POS UINT8_C(5) 224 | #define BME680_OSP_POS UINT8_C(2) 225 | #define BME680_RUN_GAS_POS UINT8_C(4) 226 | 227 | /** Array Index to Field data mapping for Calibration Data*/ 228 | #define BME680_T2_LSB_REG (1) 229 | #define BME680_T2_MSB_REG (2) 230 | #define BME680_T3_REG (3) 231 | #define BME680_P1_LSB_REG (5) 232 | #define BME680_P1_MSB_REG (6) 233 | #define BME680_P2_LSB_REG (7) 234 | #define BME680_P2_MSB_REG (8) 235 | #define BME680_P3_REG (9) 236 | #define BME680_P4_LSB_REG (11) 237 | #define BME680_P4_MSB_REG (12) 238 | #define BME680_P5_LSB_REG (13) 239 | #define BME680_P5_MSB_REG (14) 240 | #define BME680_P7_REG (15) 241 | #define BME680_P6_REG (16) 242 | #define BME680_P8_LSB_REG (19) 243 | #define BME680_P8_MSB_REG (20) 244 | #define BME680_P9_LSB_REG (21) 245 | #define BME680_P9_MSB_REG (22) 246 | #define BME680_P10_REG (23) 247 | #define BME680_H2_MSB_REG (25) 248 | #define BME680_H2_LSB_REG (26) 249 | #define BME680_H1_LSB_REG (26) 250 | #define BME680_H1_MSB_REG (27) 251 | #define BME680_H3_REG (28) 252 | #define BME680_H4_REG (29) 253 | #define BME680_H5_REG (30) 254 | #define BME680_H6_REG (31) 255 | #define BME680_H7_REG (32) 256 | #define BME680_T1_LSB_REG (33) 257 | #define BME680_T1_MSB_REG (34) 258 | #define BME680_GH2_LSB_REG (35) 259 | #define BME680_GH2_MSB_REG (36) 260 | #define BME680_GH1_REG (37) 261 | #define BME680_GH3_REG (38) 262 | 263 | /** BME680 register buffer index settings*/ 264 | #define BME680_REG_FILTER_INDEX UINT8_C(5) 265 | #define BME680_REG_TEMP_INDEX UINT8_C(4) 266 | #define BME680_REG_PRES_INDEX UINT8_C(4) 267 | #define BME680_REG_HUM_INDEX UINT8_C(2) 268 | #define BME680_REG_NBCONV_INDEX UINT8_C(1) 269 | #define BME680_REG_RUN_GAS_INDEX UINT8_C(1) 270 | #define BME680_REG_HCTRL_INDEX UINT8_C(0) 271 | 272 | /** Macro to combine two 8 bit data's to form a 16 bit data */ 273 | #define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) 274 | 275 | /** Macro to SET and GET BITS of a register */ 276 | #define BME680_SET_BITS(reg_data, bitname, data) \ 277 | ((reg_data & ~(bitname##_MSK)) | \ 278 | ((data << bitname##_POS) & bitname##_MSK)) 279 | #define BME680_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \ 280 | (bitname##_POS)) 281 | 282 | /** Macro variant to handle the bitname position if it is zero */ 283 | #define BME680_SET_BITS_POS_0(reg_data, bitname, data) \ 284 | ((reg_data & ~(bitname##_MSK)) | \ 285 | (data & bitname##_MSK)) 286 | #define BME680_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) 287 | 288 | /** 289 | * @fn bme680_com_fptr_t 290 | * @brief Generic communication function pointer 291 | * @param dev_id: Place holder to store the id of the device structure 292 | * @n Can be used to store the index of the Chip select or 293 | * @n I2C address of the device. 294 | * @param reg_addr: Used to select the register the where data needs to 295 | * be read from or written to. 296 | * @param data: Data array to read/write 297 | * @param len: Length of the data array 298 | * @return int8_t type 299 | */ 300 | typedef int8_t (*bme680_com_fptr_t)(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len); 301 | 302 | /** 303 | * @fn bme680_delay_fptr_t 304 | * @brief Delay function pointer 305 | * @param[in] period: Time period in milliseconds 306 | */ 307 | typedef void (*bme680_delay_fptr_t)(uint32_t period); 308 | 309 | /** 310 | * @enum bme680_intf 311 | * @brief Interface selection Enumerations 312 | */ 313 | enum bme680_intf { 314 | 315 | BME680_SPI_INTF, 316 | BME680_I2C_INTF /**< I2C interface */ 317 | }; 318 | 319 | /** 320 | * @struct bme680_field_data 321 | * @brief Sensor field data structure 322 | */ 323 | struct bme680_field_data { 324 | uint8_t status; /**< Contains new_data, gasm_valid & heat_stab */ 325 | uint8_t gas_index; /**< The index of the heater profile used */ 326 | uint8_t meas_index; /**< Measurement index to track order */ 327 | int16_t temperature; /**< Temperature in degree celsius x100 */ 328 | uint32_t pressure; /**< Pressure in Pascal */ 329 | uint32_t humidity; /**< Humidity in % relative humidity x1000 */ 330 | uint32_t gas_resistance; /**< Gas resistance in Ohms */ 331 | }; 332 | 333 | /** 334 | * @struct bme680_calib_data 335 | * @brief Structure to hold the Calibration data 336 | */ 337 | struct bme680_calib_data { 338 | 339 | uint16_t par_h1; /**< Variable to store calibrated humidity data */ 340 | uint16_t par_h2; /**< Variable to store calibrated humidity data */ 341 | int8_t par_h3; /**< Variable to store calibrated humidity data */ 342 | int8_t par_h4; /**< Variable to store calibrated humidity data */ 343 | int8_t par_h5; /**< Variable to store calibrated humidity data */ 344 | uint8_t par_h6; /**< Variable to store calibrated humidity data */ 345 | int8_t par_h7; /**< Variable to store calibrated humidity data */ 346 | int8_t par_gh1; /**< Variable to store calibrated gas data */ 347 | int16_t par_gh2; /**< Variable to store calibrated gas data */ 348 | int8_t par_gh3; /**< Variable to store calibrated gas data */ 349 | uint16_t par_t1; /**< Variable to store calibrated temperature data */ 350 | int16_t par_t2; /**< Variable to store calibrated temperature data */ 351 | int8_t par_t3; /**< Variable to store calibrated temperature data */ 352 | uint16_t par_p1; /**< Variable to store calibrated pressure data */ 353 | int16_t par_p2; /**< Variable to store calibrated pressure data */ 354 | int8_t par_p3; /**< Variable to store calibrated pressure data */ 355 | int16_t par_p4; /**< Variable to store calibrated pressure data */ 356 | int16_t par_p5; /**< Variable to store calibrated pressure data */ 357 | int8_t par_p6; /**< Variable to store calibrated pressure data */ 358 | int8_t par_p7; /**< Variable to store calibrated pressure data */ 359 | int16_t par_p8; /**< Variable to store calibrated pressure data */ 360 | int16_t par_p9; /**< Variable to store calibrated pressure data */ 361 | uint8_t par_p10; /**< Variable to store calibrated pressure data */ 362 | int32_t t_fine; /**< Variable to store t_fine size */ 363 | uint8_t res_heat_range;/**< Variable to store heater resistance range */ 364 | int8_t res_heat_val; /**< Variable to store heater resistance value */ 365 | int8_t range_sw_err; /**< Variable to store error range */ 366 | }; 367 | 368 | /** 369 | * @struct bme680_tph_sett 370 | * @brief BME680 sensor settings structure which comprises of ODR, 371 | * over-sampling and filter settings. 372 | */ 373 | struct bme680_tph_sett { 374 | uint8_t os_hum; /**< Humidity oversampling */ 375 | uint8_t os_temp;/**< Temperature oversampling */ 376 | uint8_t os_pres;/**< Pressure oversampling */ 377 | uint8_t filter; /**< Filter coefficient */ 378 | }; 379 | 380 | /** 381 | * @struct bme680_gas_sett 382 | * @brief BME680 gas sensor which comprises of gas settings 383 | * and status parameters 384 | */ 385 | struct bme680_gas_sett { 386 | uint8_t nb_conv; /**< Variable to store nb conversion */ 387 | uint8_t heatr_ctrl; /**< Variable to store heater control */ 388 | uint8_t run_gas; /**< Run gas enable value */ 389 | uint16_t heatr_temp;/**< Pointer to store heater temperature */ 390 | uint16_t heatr_dur; /**< Pointer to store duration profile */ 391 | }; 392 | 393 | /** 394 | * @struct bme680_dev 395 | * @brief BME680 device structure 396 | */ 397 | struct bme680_dev { 398 | uint8_t chip_id; /**< Chip Id */ 399 | uint8_t dev_id; /**< Device Id */ 400 | enum bme680_intf intf; /**< SPI/I2C interface */ 401 | uint8_t mem_page; /**< Memory page used */ 402 | int8_t amb_temp; /**< Ambient temperature in Degree C*/ 403 | struct bme680_calib_data calib; /**< Sensor calibration data */ 404 | struct bme680_tph_sett tph_sett; /**< Sensor settings */ 405 | struct bme680_gas_sett gas_sett; /**< Gas Sensor settings */ 406 | uint8_t power_mode; /**< Sensor power modes */ 407 | uint8_t new_fields; /**< New sensor fields */ 408 | uint8_t info_msg; /**< Store the info messages */ 409 | bme680_com_fptr_t read; /**< Burst read structure */ 410 | bme680_com_fptr_t write; /**< Burst write structure */ 411 | bme680_delay_fptr_t delay_ms; /**< Delay in ms */ 412 | int8_t com_rslt; /**< Communication function result */ 413 | }; 414 | 415 | 416 | 417 | #endif 418 | -------------------------------------------------------------------------------- /bsec_datatypes.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file bme680_defs.h 3 | * @brief Contains the data types used by BSEC 4 | * 5 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 6 | * @license The MIT License (MIT) 7 | * @author Frank(jiehan.guo@dfrobot.com) 8 | * @version V1.0 9 | * @date 2017-12-04 10 | * @url https://github.com/DFRobot/DFRobot_BME680 11 | */ 12 | 13 | #ifndef __BSEC_DATATYPES_H__ 14 | #define __BSEC_DATATYPES_H__ 15 | 16 | #ifdef __cplusplus 17 | extern "C" 18 | { 19 | #endif 20 | 21 | 22 | #ifdef __KERNEL__ 23 | #include 24 | #endif 25 | #include 26 | #include 27 | 28 | #define BSEC_MAX_PHYSICAL_SENSOR (6) ///< Number of physical sensors that need allocated space before calling bsec_update_subscription() */ 29 | #define BSEC_MAX_PROPERTY_BLOB_SIZE (400) ///< Maximum size (in bytes) of the data blobs returned by bsec_get_state() and bsec_get_configuration() */ 30 | #define BSEC_SAMPLE_RATE_DISABLED (65535.0f) ///< Sample rate of a disabled sensor */ 31 | #define BSEC_SAMPLE_RATE_ULP (0.0033333f) ///< Sample rate in case of Ultra Low Power Mode */ 32 | #define BSEC_SAMPLE_RATE_LP (0.33333f) ///< Sample rate in case of Low Power Mode */ 33 | 34 | #define BSEC_PROCESS_PRESSURE (1 << (BSEC_INPUT_PRESSURE-1)) ///< process_data bitfield constant for pressure @sa bsec_bme_settings_t */ 35 | #define BSEC_PROCESS_TEMPERATURE (1 << (BSEC_INPUT_TEMPERATURE-1)) ///< process_data bitfield constant for temperature @sa bsec_bme_settings_t */ 36 | #define BSEC_PROCESS_HUMIDITY (1 << (BSEC_INPUT_HUMIDITY-1)) ///< process_data bitfield constant for humidity @sa bsec_bme_settings_t */ 37 | #define BSEC_PROCESS_GAS (1 << (BSEC_INPUT_GASRESISTOR-1)) ///< process_data bitfield constant for gas sensor @sa bsec_bme_settings_t */ 38 | #define BSEC_NUMBER_OUTPUTS (13) ///< Number of outputs, depending on solution */ 39 | #define BSEC_OUTPUT_INCLUDED (4250095) ///< bitfield that indicates which outputs are included in the solution */ 40 | 41 | /** 42 | * @enum bsec_physical_sensor_t 43 | * @brief Enumeration for input (physical) sensors. 44 | * @n Used to populate bsec_input_t::sensor_id. It is also used in bsec_sensor_configuration_t::sensor_id structs 45 | * @n returned in the parameter required_sensor_settings of bsec_update_subscription() 46 | * @sa bsec_sensor_configuration_t 47 | * @sa bsec_input_t 48 | */ 49 | typedef enum 50 | { 51 | BSEC_INPUT_PRESSURE = 1, /**< Pressure sensor output of BMExxx [Pa]*/ 52 | BSEC_INPUT_HUMIDITY = 2, /**< Humidity sensor output of BMExxx [%] 53 | Relative humidity strongly depends on the temperature (it is measured at). It may required a convertion to 54 | the temperature outside of the device. */ 55 | BSEC_INPUT_TEMPERATURE = 3, /**< Temperature sensor output of BMExxx [degrees Celcius] 56 | The BME680 is factory trimmed, thus the temperature sensor of the BME680 is very accurate. 57 | The temperature value is a very local measurement value and can be influenced by external heat sources. */ 58 | BSEC_INPUT_GASRESISTOR = 4, /**< Gas sensor resistance output of BMExxx [Ohm] 59 | The restistance value changes due to varying VOC concentrations (the higher the concentration of reducing VOCs, 60 | the lower the resistance and vice versa). */ 61 | BSEC_INPUT_HEATSOURCE = 14, /**< Additional input for device heat compensation 62 | IAQ solution: The value is substracted from ::BSEC_INPUT_TEMPERATURE to compute 63 | ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE. 64 | ALL solution: Generic heatsource 1*/ 65 | 66 | } bsec_physical_sensor_t; 67 | 68 | /** 69 | * @enum bsec_virtual_sensor_t 70 | * @brief Enumeration for output (virtual) sensors. 71 | * @n Used to populate bsec_output_t::sensor_id. It is also used in bsec_sensor_configuration_t::sensor_id structs 72 | * @n passed in the parameter requested_virtual_sensors of bsec_update_subscription(). 73 | * @sa bsec_sensor_configuration_t @sa bsec_output_t 74 | */ 75 | typedef enum 76 | { 77 | BSEC_OUTPUT_IAQ_ESTIMATE = 1, /** Indoor-air-qualiy estimate [0-500]. Indoor-air-quality (IAQ) gives an indication of 78 | the relative change in ambient TVOCs detected by BME680. 79 | The IAQ scale ranges from 0 (clean air) to 500 (heavily polluted air). During operation, algorithms 80 | automatically calibrate and adapt themselves to the typical environments where the sensor is operated 81 | (e.g., home, workplace, inside a car, etc.).This automatic background calibration ensures that users experience 82 | consistent IAQ performance. The calibration process considers the recent measurement history (typ. up to four 83 | days) to ensure that IAQ=25 corresponds to typical good air and IAQ=250 indicates typical polluted air.*/ 84 | BSEC_OUTPUT_RAW_TEMPERATURE = 6, /**< Temperature sensor signal [degrees Celcius]. Temperature directly measured by BME680 in degree Celcius. 85 | This value is cross-influenced by the sensor heating and device specific heating.*/ 86 | BSEC_OUTPUT_RAW_PRESSURE = 7, /**< Pressure sensor signal [Pa]. Pressure directly measured by the BME680 in Pa.*/ 87 | BSEC_OUTPUT_RAW_HUMIDITY = 8, /**< Relative humidity sensor signal [%] .Relative humidity directly measured by the BME680 in %. 88 | This value is cross-influenced by the sensor heating and device specific heating. */ 89 | BSEC_OUTPUT_RAW_GAS = 9, /**< Gas sensor signal [Ohm]. 90 | Gas resistance measured directly by the BME680 in Ohm.The restistance value changes due to varying VOC 91 | concentrations (the higher the concentration of reducing VOCs, the lower the resistance and vice versa).*/ 92 | BSEC_OUTPUT_STABILIZATION_STATUS = 12, /**< Gas sensor stabilization status [boolean] 93 | Indicates initial stabilization status of the gas sensor element: stabilization is ongoing (0) or stablization is finished (1).*/ 94 | BSEC_OUTPUT_RUN_IN_STATUS = 13, /**< Gas sensor run-in status [boolean]. 95 | Indicates power-on stabilization status of the gas sensor element: stabilization is ongoing (0) or stablization is finished (1).*/ 96 | BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 15, /**< Sensor heat compensated temperature [degrees Celcius] 97 | Temperature measured by BME680 which is compensated for the influence of sensor (heater) in degree Celcius. 98 | The self heating introduced by the heater is depending on the sensor operation mode and the sensor supply voltage.*/ 99 | BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 16, /**< Sensor heat compensated humidity [%]. Relative measured by BME680 which is compensated for the influence of sensor (heater) in %. 100 | It converts the ::BSEC_INPUT_HUMIDITY from temperature ::BSEC_INPUT_TEMPERATURE to temperature::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE. 101 | IAQ soultion: If ::BSEC_INPUT_HEATSOURCE is used for device specific temperature compensation, it will be 102 | effective for ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY too.*/ 103 | 104 | } bsec_virtual_sensor_t; 105 | 106 | /** 107 | * 108 | * @brief Enumeration for function return codes 109 | */ 110 | typedef enum 111 | { 112 | BSEC_OK = 0, /**< Function execution successful */ 113 | BSEC_E_DOSTEPS_INVALIDINPUT = -1, /**< Input (physical) sensor id passed to bsec_do_steps() is not in the valid range or not valid for requested virtual sensor */ 114 | BSEC_E_DOSTEPS_VALUELIMITS = -2, /**< Value of input (physical) sensor signal passed to bsec_do_steps() is not in the valid range */ 115 | BSEC_E_DOSTEPS_DUPLICATEINPUT = -6, /**< Duplicate input (physical) sensor ids passed as input to bsec_do_steps() */ 116 | BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE = 2, /**< No memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs == 0 */ 117 | BSEC_W_DOSTEPS_EXCESSOUTPUTS = 3, /**< Not enough memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs < maximum number of requested output (virtual) sensors */ 118 | BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4, /**< Duplicate timestamps passed to bsec_do_steps() */ 119 | BSEC_E_SU_WRONGDATARATE = -10, /**< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is zero */ 120 | BSEC_E_SU_SAMPLERATELIMITS = -12, /**< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not match with the sampling rate allowed for that sensor */ 121 | BSEC_E_SU_DUPLICATEGATE = -13, /**< Duplicate output (virtual) sensor ids requested through bsec_update_subscription() */ 122 | BSEC_E_SU_INVALIDSAMPLERATE = -14, /**< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not fall within the global minimum and maximum sampling rates */ 123 | BSEC_E_SU_GATECOUNTEXCEEDSARRAY = -15, /**< Not enough memory allocated to hold returned input (physical) sensor data from bsec_update_subscription(), i.e., n_required_sensor_settings < #BSEC_MAX_PHYSICAL_SENSOR */ 124 | BSEC_E_SU_SAMPLINTVLINTEGERMULT = -16, /**< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is not correct */ 125 | BSEC_E_SU_MULTGASSAMPLINTVL = -17, /**< The sample_rate of the requested output (virtual), which requires the gas sensor, is not equal to the sample_rate that the gas sensor is being operated */ 126 | BSEC_E_SU_HIGHHEATERONDURATION = -18, /**< The duration of one measurement is longer than the requested sampling interval */ 127 | BSEC_W_SU_UNKNOWNOUTPUTGATE = 10, /**< Output (virtual) sensor id passed to bsec_update_subscription() is not in the valid range; e.g., n_requested_virtual_sensors > actual number of output (virtual) sensors requested */ 128 | BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12, /**< No output (virtual) sensor data were requested via bsec_update_subscription() */ 129 | BSEC_E_PARSE_SECTIONEXCEEDSWORKBUFFER = -32, /**< n_work_buffer_size passed to bsec_set_[configuration/state]() not sufficient */ 130 | BSEC_E_CONFIG_FAIL = -33, /**< Configuration failed */ 131 | BSEC_E_CONFIG_VERSIONMISMATCH = -34, /**< Version encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current version */ 132 | BSEC_E_CONFIG_FEATUREMISMATCH = -35, /**< Enabled features encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current library implementation */ 133 | BSEC_E_CONFIG_CRCMISMATCH = -36, /**< serialized_[settings/state] passed to bsec_set_[configuration/state]() is corrupted */ 134 | BSEC_E_CONFIG_EMPTY = -37, /**< n_serialized_[settings/state] passed to bsec_set_[configuration/state]() is to short to be valid */ 135 | BSEC_E_CONFIG_INSUFFICIENTWORKBUFFER = -38, /**< Provided work_buffer is not large enough to hold the desired string */ 136 | BSEC_E_CONFIG_INVALIDSTRINGSIZE = -40, /**< String size encoded in configuration/state strings passed to bsec_set_[configuration/state]() does not match with the actual string size n_serialized_[settings/state] passed to these functions */ 137 | BSEC_E_CONFIG_INSUFFICIENTBUFFER = -41, /**< String buffer nsufficient to hold serialized data from BSEC library */ 138 | BSEC_E_SET_INVALIDCHANNELIDENTIFIER = -100, /**< Internal error code */ 139 | BSEC_E_SET_INVALIDLENGTH = -104, /**< Internal error code */ 140 | BSEC_W_SC_CALL_TIMING_VIOLATION = 100, /**< Difference between actual and defined sampling intervals of bsec_sensor_control() greater than allowed */ 141 | } bsec_library_return_t; 142 | 143 | /** 144 | * @struct bsec_version_t 145 | * @brief Structure containing the version information 146 | * @n Please note that configuration and state strings are coded to a specific version and will not be accepted by other 147 | * @n versions of BSEC. 148 | * 149 | */ 150 | typedef struct 151 | { 152 | uint8_t major; /**< Major version */ 153 | uint8_t minor; /**< Minor version */ 154 | uint8_t major_bugfix; /**< Major bug fix version */ 155 | uint8_t minor_bugfix; /**< Minor bug fix version */ 156 | } bsec_version_t; 157 | 158 | /** 159 | * @struct bsec_input_t 160 | * @brief Time stamp in nanosecond resolution [ns]. Structure describing an input sample to the library 161 | * @n Each input sample is provided to BSEC as an element in a struct array of this type. Timestamps must be provided 162 | * @n in nanosecond resolution. Moreover, duplicate timestamps for subsequent samples are not allowed and will results in 163 | * @n an error code being returned from bsec_do_steps(). 164 | * 165 | * @n The meaning unit of the signal field are determined by the bsec_input_t::sensor_id field content. Possible 166 | * @n bsec_input_t::sensor_id values and and their meaning are described in ::bsec_physical_sensor_t. 167 | * 168 | * @sa bsec_physical_sensor_t 169 | * 170 | */ 171 | typedef struct 172 | { 173 | int64_t time_stamp; /**< Time stamp in nanosecond resolution [ns]. 174 | Timestamps must be provided as non-repeating and increasing values. They can have their 0-points at system start or 175 | at a defined wall-clock time (e.g., 01-Jan-1970 00:00:00)*/ 176 | float signal; /**< @brief Signal sample in the unit defined for the respective sensor_id @sa bsec_physical_sensor_t */ 177 | uint8_t signal_dimensions; /**< @brief Signal dimensions (reserved for future use, shall be set to 1) */ 178 | uint8_t sensor_id; /**< @brief Identifier of physical sensor @sa bsec_physical_sensor_t */ 179 | } bsec_input_t; 180 | 181 | /** 182 | * @struct bsec_output_t 183 | * @brief Structure describing an output sample of the library. 184 | * @n Each output sample is returned from BSEC by populating the element of a struct array of this type. The contents of 185 | * @n the signal field is defined by the supplied bsec_output_t::sensor_id. Possible output bsec_output_t::sensor_id values 186 | * @n are defined in ::bsec_virtual_sensor_t. 187 | * @sa bsec_virtual_sensor_t 188 | */ 189 | typedef struct 190 | { 191 | int64_t time_stamp; /**< @brief Time stamp in nanosecond resolution as provided as input [ns] */ 192 | float signal; /**< @brief Signal sample in the unit defined for the respective bsec_output_t::sensor_id @sa bsec_virtual_sensor_t */ 193 | uint8_t signal_dimensions; /**< @brief Signal dimensions (reserved for future use, shall be set to 1) */ 194 | uint8_t sensor_id; /**< @brief Identifier of virtual sensor @sa bsec_virtual_sensor_t */ 195 | uint8_t accuracy; /**< Accuracy status 0-4 196 | Some virtual sensors provide a value in the accuracy field. If this is the case, the meaning of the field is as follows: 197 | | Name | Value | Accuracy description | 198 | |----------------------------|-------|-------------------------------------------------------------| 199 | | UNRELIABLE | 0 | Sensor data is unreliable, the sensor must be calibrated | 200 | | LOW_ACCURACY | 1 | Low accuracy, sensor should be calibrated | 201 | | MEDIUM_ACCURACY | 2 | Medium accuracy, sensor calibration may improve performance | 202 | | HIGH_ACCURACY | 3 | High accuracy | 203 | For example: 204 | - Ambient temperature accuracy is derived from change in the temperature in 1 minute. 205 | 206 | | Virtual sensor | Value | Accuracy description | 207 | |--------------------- |-------|------------------------------------------------------------------------------| 208 | | Ambient temperature | 0 | The difference in ambient temperature is greater than 4 degree in one minute | 209 | | | 1 | The difference in ambient temperature is less than 4 degree in one minute | 210 | | | 2 | The difference in ambient temperature is less than 3 degree in one minute | 211 | | | 3 | The difference in ambient temperature is less than 2 degree in one minute | 212 | 213 | - IAQ accuracy indicator will notify the user when she/he should initiate a calibration process. Calibration is 214 | performed automatically in the background if the sensor is exposed to clean and polluted air for approximately 215 | 30 minutes each. 216 | 217 | | Virtual sensor | Value | Accuracy description | 218 | |----------------------------|-------|-----------------------------------------------------------------| 219 | | IAQ | 0 | The sensor is not yet stablized or in a run-in status | 220 | | | 1 | Calibration required | 221 | | | 2 | Calibration on-going | 222 | | | 3 | Calibration is done, now IAQ estimate achieves best perfomance |*/ 223 | } bsec_output_t; 224 | 225 | /** 226 | * @struct bsec_sensor_configuration_t 227 | * @brief Structure describing sample rate of physical/virtual sensors 228 | * @n This structure is used together with bsec_update_subscription() to enable BSEC outputs and to retrieve information 229 | * @n about the sample rates used for BSEC inputs. 230 | */ 231 | typedef struct 232 | { 233 | float sample_rate; /**< Sample rate of the virtual or physical sensor in Hertz [Hz]. Only supported sample rates are allowed.*/ 234 | uint8_t sensor_id; /**< Identifier of the virtual or physical sensor. 235 | The meaning of this field changes depening on whether the structs are as the requested_virtual_sensors argument 236 | to bsec_update_subscription() or as the required_sensor_settings argument. 237 | | bsec_update_subscription() argument | sensor_id field interpretation | 238 | |-------------------------------------|--------------------------------| 239 | | requested_virtual_sensors | ::bsec_virtual_sensor_t | 240 | | required_sensor_settings | ::bsec_physical_sensor_t |*/ 241 | } bsec_sensor_configuration_t; 242 | 243 | /** 244 | * @struct bsec_bme_settings_t 245 | * @brief Structure returned by bsec_sensor_control() to configure BMExxx sensor 246 | * 247 | * @n This structure contains settings that must be used to configure the BMExxx to perform a forced-mode measurement. 248 | * @n A measurement should only be executed if bsec_bme_settings_t::trigger_measurement is 1. If so, the oversampling 249 | * @n settings for temperature, humidity, and pressure should be set to the provided settings provided in 250 | * @n bsec_bme_settings_t::temperature_oversampling, bsec_bme_settings_t::humidity_oversampling, and 251 | * @n bsec_bme_settings_t::pressure_oversampling, respectively. 252 | * 253 | * @n In case of bsec_bme_settings_t::run_gas = 1, the gas sensor must be enabled with the provided 254 | * @n bsec_bme_settings_t::heater_temperature and bsec_bme_settings_t::heating_duration settings. 255 | */ 256 | typedef struct 257 | { 258 | int64_t next_call; /**< Time stamp of the next call of the sensor_control*/ 259 | uint32_t process_data; /**< Bit field describing which data is to be passed to bsec_do_steps() @sa BSEC_PROCESS_* */ 260 | uint16_t heater_temperature; /**< Heating temperature [degrees Celsius] */ 261 | uint16_t heating_duration; /**< Heating duration [ms] */ 262 | uint8_t run_gas; /**< Enable gas measurements [0/1] */ 263 | uint8_t pressure_oversampling; /**< Pressure oversampling settings [0-5] */ 264 | uint8_t temperature_oversampling; /**< Temperature oversampling settings [0-5] */ 265 | uint8_t humidity_oversampling; /**< Humidity oversampling settings [0-5] */ 266 | uint8_t trigger_measurement; /**< Trigger a forced measurement with these settings now [0/1] */ 267 | } bsec_bme_settings_t; 268 | 269 | /* internal defines and backward compatbility */ 270 | #define BSEC_STRUCT_NAME Bsec ///< Internal struct name 271 | 272 | 273 | #ifdef __cplusplus 274 | } 275 | #endif 276 | 277 | #endif 278 | -------------------------------------------------------------------------------- /bsec_integration.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bsec_integration.c 3 | * @brief Private part of the example for using of BSEC library. 4 | * 5 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 6 | * @license The MIT License (MIT) 7 | * @author Frank(jiehan.guo@dfrobot.com) 8 | * @version V1.0 9 | * @date 2017-12-04 10 | * @url https://github.com/DFRobot/DFRobot_BME680 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "bsec_integration.h" 18 | 19 | #include "Arduino.h" 20 | 21 | /**********************************************************************************************************************/ 22 | /* local macro definitions */ 23 | /**********************************************************************************************************************/ 24 | 25 | #define NUM_USED_OUTPUTS 7 26 | 27 | /**********************************************************************************************************************/ 28 | /* global variable declarations */ 29 | /**********************************************************************************************************************/ 30 | 31 | /* Global sensor APIs data structure */ 32 | static struct bme680_dev bme680_g; 33 | 34 | /* Global temperature offset to be subtracted */ 35 | static float bme680_temperature_offset_g = 0.0f; 36 | 37 | /**********************************************************************************************************************/ 38 | /* functions */ 39 | /**********************************************************************************************************************/ 40 | 41 | /** 42 | * @fn bme680_bsec_update_subscription 43 | * @brief Virtual sensor subscription.Please call this function before processing of data using bsec_do_steps function. 44 | * @param sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP) 45 | * @return subscription result, zero when successful 46 | */ 47 | static bsec_library_return_t bme680_bsec_update_subscription(float sample_rate) 48 | { 49 | bsec_sensor_configuration_t requested_virtual_sensors[NUM_USED_OUTPUTS]; 50 | uint8_t n_requested_virtual_sensors = NUM_USED_OUTPUTS; 51 | 52 | bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR]; 53 | uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR; 54 | 55 | bsec_library_return_t status = BSEC_OK; 56 | 57 | /* note: Virtual sensors as desired to be added here */ 58 | requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ_ESTIMATE; 59 | requested_virtual_sensors[0].sample_rate = sample_rate; 60 | requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE; 61 | requested_virtual_sensors[1].sample_rate = sample_rate; 62 | requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE; 63 | requested_virtual_sensors[2].sample_rate = sample_rate; 64 | requested_virtual_sensors[3].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY; 65 | requested_virtual_sensors[3].sample_rate = sample_rate; 66 | requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_RAW_GAS; 67 | requested_virtual_sensors[4].sample_rate = sample_rate; 68 | requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE; 69 | requested_virtual_sensors[5].sample_rate = sample_rate; 70 | requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY; 71 | requested_virtual_sensors[6].sample_rate = sample_rate; 72 | 73 | /* Call bsec_update_subscription() to enable/disable the requested virtual sensors */ 74 | status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings, 75 | &n_required_sensor_settings); 76 | 77 | return status; 78 | } 79 | 80 | /** 81 | * @fn bsec_iot_init 82 | * @brief Initialize the BME680 sensor and the BSEC library 83 | * 84 | * @param sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP) 85 | * @param temperature_offset device-specific temperature offset (due to self-heating) 86 | * @param bus_write pointer to the bus writing function 87 | * @param bus_read pointer to the bus reading function 88 | * @param sleep pointer to the system specific sleep function 89 | * @param state_load pointer to the system-specific state load function 90 | * @param config_load pointer to the system-specific config load function 91 | * 92 | * @return zero if successful, negative otherwise 93 | */ 94 | return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme680_com_fptr_t bus_write, 95 | bme680_com_fptr_t bus_read, sleep_fct sleep, uint8_t addr, enum bme680_intf intf) 96 | { 97 | return_values_init ret = {BME680_OK, BSEC_OK}; 98 | bsec_library_return_t bsec_status = BSEC_OK; 99 | 100 | uint8_t bsec_state[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0}; 101 | uint8_t bsec_config[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0}; 102 | uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0}; 103 | int bsec_state_len, bsec_config_len; 104 | 105 | /* Fixed I2C configuration */ 106 | bme680_g.dev_id = addr; 107 | bme680_g.intf = intf; 108 | /* User configurable I2C configuration */ 109 | bme680_g.write = bus_write; 110 | bme680_g.read = bus_read; 111 | bme680_g.delay_ms = sleep; 112 | 113 | /* Initialize BME680 API */ 114 | ret.bme680_status = bme680_init(&bme680_g); 115 | if (ret.bme680_status != BME680_OK) 116 | { 117 | return ret; 118 | } 119 | 120 | /* Initialize BSEC library */ 121 | ret.bsec_status = bsec_init(); 122 | if (ret.bsec_status != BSEC_OK) 123 | { 124 | return ret; 125 | } 126 | 127 | /* Set temperature offset */ 128 | bme680_temperature_offset_g = temperature_offset; 129 | 130 | /* Call to the function which sets the library with subscription information */ 131 | ret.bsec_status = bme680_bsec_update_subscription(sample_rate); 132 | if (ret.bsec_status != BSEC_OK) 133 | { 134 | return ret; 135 | } 136 | 137 | return ret; 138 | } 139 | 140 | /** 141 | * @fn bme680_bsec_trigger_measurement 142 | * @brief Trigger the measurement based on sensor settings 143 | * 144 | * @param sensor_settings settings of the BME680 sensor adopted by sensor control function 145 | * @param sleep pointer to the system specific sleep function 146 | * 147 | * @return uint32_t 148 | */ 149 | static uint32_t bme680_bsec_trigger_measurement(bsec_bme_settings_t *sensor_settings, sleep_fct sleep) 150 | { 151 | uint16_t meas_period; 152 | uint8_t set_required_settings; 153 | int8_t bme680_status = BME680_OK; 154 | 155 | /* Check if a forced-mode measurement should be triggered now */ 156 | if (sensor_settings->trigger_measurement) 157 | { 158 | /* Set sensor configuration */ 159 | 160 | bme680_g.tph_sett.os_hum = sensor_settings->humidity_oversampling; 161 | bme680_g.tph_sett.os_pres = sensor_settings->pressure_oversampling; 162 | bme680_g.tph_sett.os_temp = sensor_settings->temperature_oversampling; 163 | bme680_g.gas_sett.run_gas = sensor_settings->run_gas; 164 | bme680_g.gas_sett.heatr_temp = sensor_settings->heater_temperature; /* degree Celsius */ 165 | bme680_g.gas_sett.heatr_dur = sensor_settings->heating_duration; /* milliseconds */ 166 | 167 | /* Select the power mode */ 168 | /* Must be set before writing the sensor configuration */ 169 | bme680_g.power_mode = BME680_FORCED_MODE; 170 | /* Set the required sensor settings needed */ 171 | set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL; 172 | 173 | /* Set the desired sensor configuration */ 174 | bme680_status = bme680_set_sensor_settings(set_required_settings, &bme680_g); 175 | 176 | /* Set power mode as forced mode and trigger forced mode measurement */ 177 | bme680_status = bme680_set_sensor_mode(&bme680_g); 178 | 179 | /* Get the total measurement duration so as to sleep or wait till the measurement is complete */ 180 | bme680_get_profile_dur(&meas_period, &bme680_g); 181 | 182 | /* Delay till the measurement is ready. Timestamp resolution in ms */ 183 | return ((uint32_t)meas_period); 184 | } else return 0; 185 | } 186 | 187 | /** 188 | * @fn bme680_bsec_read_data 189 | * @brief Read the data from registers and populate the inputs structure to be passed to do_steps function 190 | * 191 | * @param[in] time_stamp_trigger settings of the sensor returned from sensor control function 192 | * @param[in] inputs input structure containing the information on sensors to be passed to do_steps 193 | * @param[in] num_bsec_inputs number of inputs to be passed to do_steps 194 | * @param[in] bsec_process_data process data variable returned from sensor_control 195 | * 196 | * @return none 197 | */ 198 | static void bme680_bsec_read_data(int64_t time_stamp_trigger, bsec_input_t *inputs, uint8_t *num_bsec_inputs, int32_t bsec_process_data) 199 | { 200 | static struct bme680_field_data data; 201 | int8_t bme680_status = BME680_OK; 202 | 203 | /* We only have to read data if the previous call the bsec_sensor_control() actually asked for it */ 204 | if (bsec_process_data) 205 | { 206 | bme680_status = bme680_get_sensor_data(&data, &bme680_g); 207 | 208 | if (data.status & BME680_NEW_DATA_MSK) 209 | { 210 | /* Pressure to be processed by BSEC */ 211 | if (bsec_process_data & BSEC_PROCESS_PRESSURE) 212 | { 213 | /* Place presssure sample into input struct */ 214 | inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE; 215 | inputs[*num_bsec_inputs].signal = data.pressure; 216 | inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger; 217 | (*num_bsec_inputs)++; 218 | } 219 | /* Temperature to be processed by BSEC */ 220 | if (bsec_process_data & BSEC_PROCESS_TEMPERATURE) 221 | { 222 | /* Place temperature sample into input struct */ 223 | inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE; 224 | inputs[*num_bsec_inputs].signal = data.temperature / 100.0f; 225 | inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger; 226 | (*num_bsec_inputs)++; 227 | 228 | /* Also add optional heatsource input which will be subtracted from the temperature reading to 229 | * compensate for device-specific self-heating (supported in BSEC IAQ solution)*/ 230 | inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HEATSOURCE; 231 | inputs[*num_bsec_inputs].signal = bme680_temperature_offset_g; 232 | inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger; 233 | (*num_bsec_inputs)++; 234 | } 235 | /* Humidity to be processed by BSEC */ 236 | if (bsec_process_data & BSEC_PROCESS_HUMIDITY) 237 | { 238 | /* Place humidity sample into input struct */ 239 | inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY; 240 | inputs[*num_bsec_inputs].signal = data.humidity / 1000.0f; 241 | inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger; 242 | (*num_bsec_inputs)++; 243 | } 244 | /* Gas to be processed by BSEC */ 245 | if (bsec_process_data & BSEC_PROCESS_GAS) 246 | { 247 | /* Check whether gas_valid flag is set */ 248 | if(data.status & BME680_GASM_VALID_MSK) 249 | { 250 | /* Place sample into input struct */ 251 | inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR; 252 | inputs[*num_bsec_inputs].signal = data.gas_resistance; 253 | inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger; 254 | (*num_bsec_inputs)++; 255 | } 256 | } 257 | } 258 | } 259 | } 260 | 261 | /** 262 | * @fn bme680_bsec_process_data 263 | * @brief This function is written to process the sensor data for the requested virtual sensors 264 | * 265 | * @param[in] bsec_inputs input structure containing the information on sensors to be passed to do_steps 266 | * @param[in] num_bsec_inputs number of inputs to be passed to do_steps 267 | * @param[in] output_ready pointer to the function processing obtained BSEC outputs 268 | * 269 | * @return none 270 | */ 271 | static void bme680_bsec_process_data(bsec_input_t *bsec_inputs, uint8_t num_bsec_inputs, output_ready_fct output_ready) 272 | { 273 | /* Output buffer set to the maximum virtual sensor outputs supported */ 274 | bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS]; 275 | uint8_t num_bsec_outputs = 0; 276 | uint8_t index = 0; 277 | 278 | bsec_library_return_t bsec_status = BSEC_OK; 279 | 280 | int64_t timestamp = 0; 281 | float iaq = 0.0f; 282 | uint8_t iaq_accuracy = 0; 283 | float temp = 0.0f; 284 | float raw_temp = 0.0f; 285 | float raw_pressure = 0.0f; 286 | float humidity = 0.0f; 287 | float raw_humidity = 0.0f; 288 | float raw_gas = 0.0f; 289 | 290 | /* Check if something should be processed by BSEC */ 291 | if (num_bsec_inputs > 0) 292 | { 293 | /* Set number of outputs to the size of the allocated buffer */ 294 | /* BSEC_NUMBER_OUTPUTS to be defined */ 295 | num_bsec_outputs = BSEC_NUMBER_OUTPUTS; 296 | 297 | /* Perform processing of the data by BSEC 298 | Note: 299 | * The number of outputs you get depends on what you asked for during bsec_update_subscription(). This is 300 | handled under bme680_bsec_update_subscription() function in this example file. 301 | * The number of actual outputs that are returned is written to num_bsec_outputs. */ 302 | bsec_status = bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs); 303 | 304 | /* Iterate through the outputs and extract the relevant ones. */ 305 | for (index = 0; index < num_bsec_outputs; index++) 306 | { 307 | switch (bsec_outputs[index].sensor_id) 308 | { 309 | case BSEC_OUTPUT_IAQ_ESTIMATE: 310 | iaq = bsec_outputs[index].signal; 311 | iaq_accuracy = bsec_outputs[index].accuracy; 312 | break; 313 | case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: 314 | temp = bsec_outputs[index].signal; 315 | break; 316 | case BSEC_OUTPUT_RAW_PRESSURE: 317 | raw_pressure = bsec_outputs[index].signal; 318 | break; 319 | case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: 320 | humidity = bsec_outputs[index].signal; 321 | break; 322 | case BSEC_OUTPUT_RAW_GAS: 323 | raw_gas = bsec_outputs[index].signal; 324 | break; 325 | case BSEC_OUTPUT_RAW_TEMPERATURE: 326 | raw_temp = bsec_outputs[index].signal; 327 | break; 328 | case BSEC_OUTPUT_RAW_HUMIDITY: 329 | raw_humidity = bsec_outputs[index].signal; 330 | break; 331 | default: 332 | continue; 333 | } 334 | 335 | /* Assume that all the returned timestamps are the same */ 336 | timestamp = bsec_outputs[index].time_stamp; 337 | } 338 | 339 | /* Pass the extracted outputs to the user provided output_ready() function. */ 340 | output_ready(timestamp, iaq, iaq_accuracy, temp, humidity, raw_pressure, raw_temp, 341 | raw_humidity, raw_gas, bsec_status); 342 | } 343 | } 344 | int8_t bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready) 345 | { 346 | /* Timestamp variables */ 347 | static int64_t time_stamp = 0; 348 | static int64_t time_stamp_interval_ms = 0; 349 | 350 | /* Allocate enough memory for up to BSEC_MAX_PHYSICAL_SENSOR physical inputs*/ 351 | static bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR]; 352 | 353 | /* Number of inputs to BSEC */ 354 | static uint8_t num_bsec_inputs = 0; 355 | 356 | /* BSEC sensor settings struct */ 357 | static bsec_bme_settings_t sensor_settings; 358 | 359 | /* Save state variables */ 360 | static uint8_t bsec_state[BSEC_MAX_PROPERTY_BLOB_SIZE]; 361 | static uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE]; 362 | static uint32_t bsec_state_len = 0; 363 | static uint32_t n_samples = 0; 364 | 365 | static bsec_library_return_t bsec_status = BSEC_OK; 366 | 367 | static uint32_t waitTime = 0; 368 | static unsigned long lastTime = 0; 369 | 370 | if(waitTime == 0) { 371 | /* get the timestamp in nanoseconds before calling bsec_sensor_control() */ 372 | time_stamp = get_timestamp_us() * 1000; 373 | 374 | /* Retrieve sensor settings to be used in this time instant by calling bsec_sensor_control */ 375 | bsec_sensor_control(time_stamp, &sensor_settings); 376 | 377 | /* Trigger a measurement if necessary */ 378 | lastTime = millis(); 379 | waitTime = bme680_bsec_trigger_measurement(&sensor_settings, sleep); 380 | return 1; 381 | } else if((millis() - lastTime) >= waitTime) { 382 | waitTime = 0; 383 | /* Call the API to get current operation mode of the sensor */ 384 | bme680_get_sensor_mode(&bme680_g); 385 | 386 | /* When the measurement is completed and data is ready for reading, the sensor must be in BME680_SLEEP_MODE. 387 | * Read operation mode to check whether measurement is completely done and wait until the sensor is no more 388 | * in BME680_FORCED_MODE. */ 389 | while (bme680_g.power_mode == BME680_FORCED_MODE) 390 | { 391 | /* sleep for 5 ms */ 392 | sleep(5); 393 | bme680_get_sensor_mode(&bme680_g); 394 | } 395 | 396 | /* Read data from last measurement */ 397 | num_bsec_inputs = 0; 398 | bme680_bsec_read_data(time_stamp, bsec_inputs, &num_bsec_inputs, sensor_settings.process_data); 399 | 400 | /* Time to invoke BSEC to perform the actual processing */ 401 | bme680_bsec_process_data(bsec_inputs, num_bsec_inputs, output_ready); 402 | return 0; 403 | } 404 | return 1; 405 | } 406 | 407 | /*! @}*/ 408 | 409 | -------------------------------------------------------------------------------- /bsec_integration.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bsec_integration.h 3 | * @brief Contains BSEC integration API 4 | * 5 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 6 | * @license The MIT License (MIT) 7 | * @author Frank(jiehan.guo@dfrobot.com) 8 | * @version V1.0 9 | * @date 2017-12-04 10 | * @url https://github.com/DFRobot/DFRobot_BME680 11 | */ 12 | 13 | #ifndef __BSEC_INTEGRATION_H__ 14 | #define __BSEC_INTEGRATION_H__ 15 | 16 | #ifdef __cplusplus 17 | extern "C" 18 | { 19 | #endif 20 | 21 | /**********************************************************************************************************************/ 22 | /* header files */ 23 | /**********************************************************************************************************************/ 24 | 25 | /* Use the following bme680 driver: https://github.com/BoschSensortec/BME680_driver/releases/tag/bme680_v3.5.1 */ 26 | #include "bme680.h" 27 | /* BSEC header files are available in the inc/ folder of the release package */ 28 | #include "bsec_interface.h" 29 | #include "bsec_datatypes.h" 30 | 31 | 32 | /**********************************************************************************************************************/ 33 | /* type definitions */ 34 | /**********************************************************************************************************************/ 35 | 36 | /* function pointer to the system specific sleep function */ 37 | typedef void (*sleep_fct)(uint32_t t_ms); 38 | 39 | /* function pointer to the system specific timestamp derivation function */ 40 | typedef int64_t (*get_timestamp_us_fct)(); 41 | 42 | /* function pointer to the function processing obtained BSEC outputs */ 43 | typedef void (*output_ready_fct)(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity, 44 | float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status); 45 | 46 | /* function pointer to the function loading a previous BSEC state from NVM */ 47 | typedef uint32_t (*state_load_fct)(uint8_t *state_buffer, uint32_t n_buffer); 48 | 49 | /* function pointer to the function saving BSEC state to NVM */ 50 | typedef void (*state_save_fct)(const uint8_t *state_buffer, uint32_t length); 51 | 52 | /* function pointer to the function loading the BSEC configuration string from NVM */ 53 | typedef uint32_t (*config_load_fct)(uint8_t *state_buffer, uint32_t n_buffer); 54 | 55 | typedef struct{ 56 | int8_t bme680_status; /**< Result of API execution status */ 57 | bsec_library_return_t bsec_status; /**< Result of BSEC library */ 58 | }return_values_init; 59 | 60 | /** 61 | * @fn bsec_iot_init 62 | * @brief Initialize the BME680 sensor and the BSEC library 63 | * 64 | * @param sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP) 65 | * @param temperature_offset device-specific temperature offset (due to self-heating) 66 | * @param bus_write pointer to the bus writing function 67 | * @param bus_read pointer to the bus reading function 68 | * @param sleep pointer to the system-specific sleep function 69 | * @param state_load pointer to the system-specific state load function 70 | * 71 | * @return zero if successful, negative otherwise 72 | */ 73 | return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme680_com_fptr_t bus_write, bme680_com_fptr_t bus_read, 74 | sleep_fct sleep, uint8_t addr, enum bme680_intf intf); 75 | 76 | /** 77 | * @fn bsec_iot_loop 78 | * @brief Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data 79 | * 80 | * @param sleep pointer to the system-specific sleep function 81 | * @param get_timestamp_us pointer to the system-specific timestamp derivation function 82 | * @param output_ready pointer to the function processing obtained BSEC outputs 83 | * @param state_save pointer to the system-specific state save function 84 | * @param save_intvl interval at which BSEC state should be saved (in samples) 85 | * 86 | * @return return_values_init struct with the result of the API and the BSEC library 87 | */ 88 | int8_t bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready); 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif /* __BSEC_INTEGRATION_H__ */ 95 | 96 | /*! @}*/ 97 | 98 | -------------------------------------------------------------------------------- /bsec_interface.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bsec_interface.h 3 | * @brief Contains the API for BSEC 4 | * 5 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 6 | * @license The MIT License (MIT) 7 | * @author Frank(jiehan.guo@dfrobot.com) 8 | * @version V1.0 9 | * @date 2017-12-04 10 | * @url https://github.com/DFRobot/DFRobot_BME680 11 | */ 12 | 13 | 14 | #ifndef __BSEC_INTERFACE_H__ 15 | #define __BSEC_INTERFACE_H__ 16 | 17 | #include "bsec_datatypes.h" 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * @fn bsec_get_version 25 | * @brief Return the version information of BSEC library 26 | * @param bsec_version_p pointer to struct which is to be populated with the version information 27 | * @return Zero if successful, otherwise an error code 28 | */ 29 | 30 | bsec_library_return_t bsec_get_version(bsec_version_t * bsec_version_p); 31 | 32 | /** 33 | * @brief Initialize the library 34 | * 35 | * @n Initialization and reset of BSEC is performed by calling bsec_init(). Calling this function sets up the relation 36 | * @n among all internal modules, initializes run-time dependent library states and resets the configuration and state 37 | * @n of all BSEC signal processing modules to defaults. 38 | * 39 | * @n Before any further use, the library must be initialized. This ensure that all memory and states are in defined 40 | * @n conditions prior to processing any data. 41 | * 42 | * @return Zero if successful, otherwise an error code 43 | */ 44 | bsec_library_return_t bsec_init(void); 45 | 46 | /** 47 | * @fn bsec_update_subscription 48 | * @brief Subscribe to library virtual sensors outputs 49 | * 50 | * @n Use bsec_update_subscription() to instruct BSEC which of the processed output signals are requested at which sample rates. 51 | * @n See ::bsec_virtual_sensor_t for available library outputs. 52 | * 53 | * @n Based on the requested virtual sensors outputs, BSEC will provide information about the required physical sensor input signals 54 | * @n (see ::bsec_physical_sensor_t) with corresponding sample rates. This information is purely informational as bsec_sensor_control() 55 | * @n will ensure the sensor is operated in the required manner. To disable a virtual sensor, set the sample rate to BSEC_SAMPLE_RATE_DISABLED. 56 | * 57 | * @n The subscription update using bsec_update_subscription() is apart from the signal processing one of the the most 58 | * @n important functions. It allows to enable the desired library outputs. The function determines which physical input 59 | * @n sensor signals are required at which sample rate to produce the virtual output sensor signals requested by the user. 60 | * @n When this function returns with success, the requested outputs are called subscribed. A very important feature is the 61 | * @n retaining of already subscribed outputs. Further outputs can be requested or disabled both individually and 62 | * @n group-wise in addition to already subscribed outputs without changing them unless a change of already subscribed 63 | * @n outputs is requested. 64 | * 65 | * @note The state of the library concerning the subscribed outputs cannot be retained among reboots. 66 | * 67 | * @n The interface of bsec_update_subscription() requires the usage of arrays of sensor configuration structures. 68 | * @n Such a structure has the fields sensor identifier and sample rate. These fields have the properties: 69 | * @n - Output signals of virtual sensors must be requested using unique identifiers (Member of ::bsec_virtual_sensor_t) 70 | * @n - Different sets of identifiers are available for inputs of physical sensors and outputs of virtual sensors 71 | * @n - Identifiers are unique values defined by the library, not from external 72 | * @n - Sample rates must be provided as value of 73 | * @n - An allowed sample rate for continuously sampled signals 74 | * @n - 65535.0f (BSEC_SAMPLE_RATE_DISABLED) to turn off outputs and identify disabled inputs 75 | * 76 | * @note The same sensor identifiers are also used within the functions bsec_do_steps(). 77 | * 78 | * @n The usage principles of bsec_update_subscription() are: 79 | * @n - Differential updates (i.e., only asking for outputs that the user would like to change) is supported. 80 | * @n - Invalid requests of outputs are ignored. Also if one of the requested outputs is unavailable, all the requests are ignored. At the same time, a warning is returned. 81 | * @n - To disable BSEC, all outputs shall be turned off. Only enabled (subscribed) outputs have to be disabled while 82 | * @n already disabled outputs do not have to be disabled explicitly. 83 | * 84 | * @param requested_virtual_sensors Pointer to array of requested virtual sensor (output) configurations for the library 85 | * @param n_requested_virtual_sensors Number of virtual sensor structs pointed by requested_virtual_sensors 86 | * @param required_sensor_settings Pointer to array of required physical sensor configurations for the library 87 | * @param n_required_sensor_settings [in] Size of allocated required_sensor_settings array, [out] number of sensor configurations returned 88 | * 89 | * @return Zero when successful, otherwise an error code 90 | */ 91 | bsec_library_return_t bsec_update_subscription(const bsec_sensor_configuration_t * const requested_virtual_sensors, 92 | const uint8_t n_requested_virtual_sensors, bsec_sensor_configuration_t * required_sensor_settings, 93 | uint8_t * n_required_sensor_settings); 94 | 95 | 96 | /*! 97 | * @brief Main signal processing function of BSEC 98 | * 99 | * 100 | * @n Processing of the input signals and returning of output samples is performed by bsec_do_steps(). 101 | * @n - The samples of all library inputs must be passed with unique identifiers representing the input signals from 102 | * @n physical sensors where the order of these inputs can be chosen arbitrary. However, all input have to be provided 103 | * @n within the same time period as they are read. A sequential provision to the library might result in undefined 104 | * @n behaviour. 105 | * @n - The samples of all library outputs are returned with unique identifiers corresponding to the output signals of 106 | * @n virtual sensors where the order of the returned outputs may be arbitrary. 107 | * @n - The samples of all input as well as output signals of physical as well as virtual sensors use the same 108 | * @n representation in memory with the following fields: 109 | * @n - Sensor identifier: 110 | * @n - For inputs: required to identify the input signal from a physical sensor 111 | * @n - For output: overwritten by bsec_do_steps() to identify the returned signal from a virtual sensor 112 | * @n - Time stamp of the sample 113 | * @n Calling bsec_do_steps() requires the samples of the input signals to be provided along with their time stamp when 114 | * @n they are recorded and only when they are acquired. Repetition of samples with the same time stamp are ignored and 115 | * @n result in a warning. Repetition of values of samples which are not acquired anew by a sensor result in deviations 116 | * @n of the computed output signals. Concerning the returned output samples, an important feature is, that a value is 117 | * @n returned for an output only when a new occurrence has been computed. A sample of an output signal is returned only 118 | * @n once. 119 | * 120 | * 121 | * @param inputs Array of input data samples. Each array element represents a sample of a different physical sensor. 122 | * @param n_inputs Number of passed input data structs. 123 | * @param outputs Array of output data samples. Each array element represents a sample of a different virtual sensor. 124 | * @param n_outputs [in] Number of allocated output structs, [out] number of outputs returned 125 | * 126 | * @return Zero when successful, otherwise an error code 127 | */ 128 | 129 | bsec_library_return_t bsec_do_steps(const bsec_input_t * const inputs, const uint8_t n_inputs, bsec_output_t * outputs, uint8_t * n_outputs); 130 | 131 | 132 | /** 133 | * @fn bsec_reset_output 134 | * @brief Reset a particular virtual sensor output 135 | * 136 | * @n This function allows specific virtual sensor outputs to be reset. The meaning of "reset" depends on the specific 137 | * @n output. In case of the IAQ output, reset means zeroing the output to the current ambient conditions. 138 | * 139 | * @param sensor_id Virtual sensor to be reset 140 | * 141 | * @return Zero when successful, otherwise an error code. 142 | */ 143 | 144 | bsec_library_return_t bsec_reset_output(uint8_t sensor_id); 145 | 146 | 147 | /** 148 | * @brief Update algorithm configuration parameters 149 | * 150 | * @n BSEC uses a default configuration for the modules and common settings. The initial configuration can be customized 151 | * @n by bsec_set_configuration(). This is an optional step. 152 | * 153 | * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose 154 | * @n the serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting 155 | * @n the required size. 156 | * 157 | * @param serialized_settings Settings serialized to a binary blob 158 | * @param n_serialized_settings Size of the settings blob 159 | * @param work_buffer Work buffer used to parse the blob 160 | * @param n_work_buffer_size Length of the work buffer available for parsing the blob 161 | * 162 | * @return Zero when successful, otherwise an error code. 163 | */ 164 | 165 | bsec_library_return_t bsec_set_configuration(const uint8_t * const serialized_settings, 166 | const uint32_t n_serialized_settings, uint8_t * work_buffer, 167 | const uint32_t n_work_buffer_size); 168 | 169 | 170 | /** 171 | * @brief Restore the internal state of the library 172 | * 173 | * @n BSEC uses a default state for all signal processing modules and the BSEC module. To ensure optimal performance, 174 | * @n especially of the gas sensor functionality, it is recommended to retrieve the state using bsec_get_state() 175 | * @n before unloading the library, storing it in some form of non-volatile memory, and setting it using bsec_set_state() 176 | * @n before resuming further operation of the library. 177 | * 178 | * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the 179 | * @n serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the 180 | * @n required size. 181 | * 182 | * @param serialized_state States serialized to a binary blob 183 | * @param n_serialized_state Size of the state blob 184 | * @param work_buffer Work buffer used to parse the blob 185 | * @param n_work_buffer_size Length of the work buffer available for parsing the blob 186 | * 187 | * @return Zero when successful, otherwise an error code 188 | */ 189 | 190 | bsec_library_return_t bsec_set_state(const uint8_t * const serialized_state, const uint32_t n_serialized_state, 191 | uint8_t * work_buffer, const uint32_t n_work_buffer_size); 192 | 193 | 194 | /** 195 | * @fn bsec_get_configuration 196 | * @brief Retrieve the current library configuration 197 | * 198 | * @n BSEC allows to retrieve the current configuration using bsec_get_configuration(). Returns a binary blob encoding 199 | * @n the current configuration parameters of the library in a format compatible with bsec_set_configuration(). 200 | * 201 | * @note The function bsec_get_configuration() is required to be used for debugging purposes only. 202 | * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the 203 | * @n serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the 204 | * @n required size. 205 | * 206 | * 207 | * @param config_id Identifier for a specific set of configuration settings to be returned;shall be zero to retrieve all configuration settings. 208 | * @param serialized_settings Buffer to hold the serialized config blob 209 | * @param n_serialized_settings_max Maximum available size for the serialized settings 210 | * @param work_buffer Work buffer used to parse the binary blob 211 | * @param n_work_buffer Length of the work buffer available for parsing the blob 212 | * @param n_serialized_settings Actual size of the returned serialized configuration blob 213 | * 214 | * @return Zero when successful, otherwise an error code 215 | */ 216 | 217 | bsec_library_return_t bsec_get_configuration(const uint8_t config_id, uint8_t * serialized_settings, const uint32_t n_serialized_settings_max, 218 | uint8_t * work_buffer, const uint32_t n_work_buffer, uint32_t * n_serialized_settings); 219 | 220 | 221 | /** 222 | * @fn bsec_get_state 223 | * @brief Retrieve the current internal library state 224 | * 225 | * @n BSEC allows to retrieve the current states of all signal processing modules and the BSEC module using 226 | * @n bsec_get_state(). This allows a restart of the processing after a reboot of the system by calling bsec_set_state(). 227 | * 228 | * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the 229 | * @n serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the 230 | * @n required size. 231 | * 232 | * 233 | * @param state_set_id Identifier for a specific set of states to be returned; shall be zero to retrieve all states. 234 | * @param serialized_state Buffer to hold the serialized config blob 235 | * @param n_serialized_state_max Maximum available size for the serialized states 236 | * @param work_buffer Work buffer used to parse the blob 237 | * @param n_work_buffer Length of the work buffer available for parsing the blob 238 | * @param n_serialized_state Actual size of the returned serialized blob 239 | * 240 | * @return Zero when successful, otherwise an error code 241 | */ 242 | 243 | bsec_library_return_t bsec_get_state(const uint8_t state_set_id, uint8_t * serialized_state, 244 | const uint32_t n_serialized_state_max, uint8_t * work_buffer, const uint32_t n_work_buffer, 245 | uint32_t * n_serialized_state); 246 | 247 | /** 248 | * @fn bsec_sensor_control 249 | * @brief Retrieve BMExxx sensor instructions 250 | * 251 | * @n The bsec_sensor_control() interface is a key feature of BSEC, as it allows an easy way for the signal processing 252 | * @n library to control the operation of the BME sensor. This is important since gas sensor behaviour is mainly 253 | * @n determined by how the integrated heater is configured. To ensure an easy integration of BSEC into any system, 254 | * @n bsec_sensor_control() will provide the caller with information about the current sensor configuration that is 255 | * @n necessary to fulfill the input requirements derived from the current outputs requested via 256 | * @n bsec_update_subscription(). 257 | * 258 | * @n In practice the use of this function shall be as follows: 259 | * @n - Call bsec_sensor_control() which returns a bsec_bme_settings_t struct. 260 | * @n - Based on the information contained in this struct, the sensor is configured and a forced-mode measurement is 261 | * @n triggered if requested by bsec_sensor_control(). 262 | * @n - Once this forced-mode measurement is complete, the signals specified in this struct shall be passed to 263 | * @n bsec_do_steps() to perform the signal processing. 264 | * @n - After processing, the process should sleep until the bsec_bme_settings_t::next_call timestamp is reached. 265 | * @param time_stamp Current timestamp in [ns] 266 | * @param sensor_settings Settings to be passed to API to operate sensor at this time instance 267 | * 268 | * @return Zero when successful, otherwise an error code 269 | */ 270 | 271 | bsec_library_return_t bsec_sensor_control(const int64_t time_stamp, bsec_bme_settings_t *sensor_settings); 272 | 273 | #ifdef __cplusplus 274 | } 275 | #endif 276 | 277 | #endif 278 | -------------------------------------------------------------------------------- /examples/DFRobot_BME680_I2C/DFRobot_BME680_I2C.ino: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DFRobot_BME680_I2C.ino 3 | * @brief connect bme680 I2C interface with your board (please reference board compatibility) 4 | * @n Temprature, Humidity, pressure, altitude, calibrate altitude and gas resistance data will print on serial window. 5 | * 6 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 7 | * @license The MIT License (MIT) 8 | * @author [Frank](jiehan.guo@dfrobot.com) 9 | * @version V1.0 10 | * @date 2017-12-7 11 | * @url https://github.com/DFRobot/DFRobot_BME680 12 | */ 13 | 14 | #include "DFRobot_BME680_I2C.h" 15 | #include "Wire.h" 16 | 17 | /*use an accurate altitude to calibrate sea level air pressure*/ 18 | #define CALIBRATE_PRESSURE 19 | 20 | DFRobot_BME680_I2C bme(0x77); //0x77 I2C address 21 | 22 | float seaLevel; 23 | void setup() 24 | { 25 | uint8_t rslt = 1; 26 | Serial.begin(9600); 27 | while(!Serial); 28 | delay(1000); 29 | Serial.println(); 30 | while(rslt != 0) { 31 | rslt = bme.begin(); 32 | if(rslt != 0) { 33 | Serial.println("bme begin failure"); 34 | delay(2000); 35 | } 36 | } 37 | Serial.println("bme begin successful"); 38 | #ifdef CALIBRATE_PRESSURE 39 | bme.startConvert(); 40 | delay(1000); 41 | bme.update(); 42 | /*You can use an accurate altitude to calibrate sea level air pressure. 43 | *And then use this calibrated sea level pressure as a reference to obtain the calibrated altitude. 44 | *In this case,525.0m is chendu accurate altitude. 45 | */ 46 | seaLevel = bme.readSeaLevel(525.0); 47 | Serial.print("seaLevel :"); 48 | Serial.println(seaLevel); 49 | #endif 50 | } 51 | 52 | void loop() 53 | { 54 | bme.startConvert(); 55 | delay(1000); 56 | bme.update(); 57 | Serial.println(); 58 | Serial.print("temperature(C) :"); 59 | Serial.println(bme.readTemperature() / 100, 2); 60 | Serial.print("pressure(Pa) :"); 61 | Serial.println(bme.readPressure()); 62 | Serial.print("humidity(%rh) :"); 63 | Serial.println(bme.readHumidity() / 1000, 2); 64 | Serial.print("gas resistance(ohm) :"); 65 | Serial.println(bme.readGasResistance()); 66 | Serial.print("altitude(m) :"); 67 | Serial.println(bme.readAltitude()); 68 | #ifdef CALIBRATE_PRESSURE 69 | Serial.print("calibrated altitude(m) :"); 70 | Serial.println(bme.readCalibratedAltitude(seaLevel)); 71 | #endif 72 | } -------------------------------------------------------------------------------- /examples/DFRobot_BME680_SPI/DFRobot_BME680_SPI.ino: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file DFRobot_BME680_SPI.ino 3 | * @brief Connect bme680 4 wires SPI interface with your board (please reference board compatibility). 4 | * @n BME680 cs pin connect to D3 on esp8266 and esp32 board, on AVR board is IO 3. 5 | * @n Temprature, Humidity, pressure, altitude, calibrate altitude and gas resistance data will print on serial window. 6 | * 7 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 8 | * @license The MIT License (MIT) 9 | * @author [Frank](jiehan.guo@dfrobot.com) 10 | * @version V1.0 11 | * @date 2017-12-7 12 | * @url https://github.com/DFRobot/DFRobot_BME680 13 | */ 14 | 15 | #include "DFRobot_BME680_SPI.h" 16 | #include "SPI.h" 17 | 18 | #ifdef __AVR__ 19 | const uint8_t bme_cs = 3; 20 | #elif ((defined ESP_PLATFORM) || (defined __ets__)) 21 | const uint8_t bme_cs = D3; 22 | #else 23 | #error unknow board 24 | #endif 25 | 26 | /*use an accurate altitude to calibrate sea level air pressure*/ 27 | #define CALIBRATE_PRESSURE 28 | 29 | DFRobot_BME680_SPI bme(bme_cs); 30 | 31 | float seaLevel; 32 | void setup() 33 | { 34 | uint8_t rslt = 1; 35 | Serial.begin(9600); 36 | while(!Serial); 37 | delay(1000); 38 | Serial.println(); 39 | while(rslt != 0) { 40 | rslt = bme.begin(); 41 | if(rslt != 0) { 42 | Serial.println("bme begin failure"); 43 | delay(2000); 44 | } 45 | } 46 | Serial.println("bme begin successful"); 47 | #ifdef CALIBRATE_PRESSURE 48 | bme.startConvert(); 49 | delay(1000); 50 | bme.update(); 51 | /*You can use an accurate altitude to calibrate sea level air pressure. 52 | *And then use this calibrated sea level pressure as a reference to obtain the calibrated altitude. 53 | *In this case,525.0m is chendu accurate altitude. 54 | */ 55 | seaLevel = bme.readSeaLevel(525.0); 56 | Serial.print("seaLevel :"); 57 | Serial.println(seaLevel); 58 | #endif 59 | } 60 | 61 | void loop() 62 | { 63 | bme.startConvert(); 64 | delay(1000); 65 | bme.update(); 66 | Serial.println(); 67 | Serial.print("temperature(C) :"); 68 | Serial.println(bme.readTemperature() / 100, 2); 69 | Serial.print("pressure(Pa) :"); 70 | Serial.println(bme.readPressure()); 71 | Serial.print("humidity(%rh) :"); 72 | Serial.println(bme.readHumidity() / 1000, 2); 73 | Serial.print("gas resistance(ohm) :"); 74 | Serial.println(bme.readGasResistance()); 75 | Serial.print("altitude(m) :"); 76 | Serial.println(bme.readAltitude()); 77 | #ifdef CALIBRATE_PRESSURE 78 | Serial.print("calibrated altitude(m) :"); 79 | Serial.println(bme.readCalibratedAltitude(seaLevel)); 80 | #endif 81 | } 82 | -------------------------------------------------------------------------------- /examples/IAQ_I2C/IAQ_I2C.ino: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IAQ_I2C.ino 3 | * @brief connect bme680 I2C interface with your board (please reference board compatibility) 4 | * @n Temprature, Humidity, pressure, altitude, calibrated altitude, gas resistance and IAQ data will be printed via serial. 5 | * @note This demo only support ESP8266 MCU 6 | * 7 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 8 | * @license The MIT License (MIT) 9 | * @author [Frank](jiehan.guo@dfrobot.com) 10 | * @version V1.0 11 | * @date 2017-12-7 12 | * @url https://github.com/DFRobot/DFRobot_BME680 13 | */ 14 | 15 | #include "DFRobot_BME680_I2C.h" 16 | #include "Wire.h" 17 | 18 | /*use an accurate altitude to calibrate sea level air pressure*/ 19 | #define CALIBRATE_PRESSURE 20 | 21 | DFRobot_BME680_I2C bme(0x77); //0x77 I2C address 22 | 23 | 24 | float seaLevel; 25 | void setup() 26 | { 27 | uint8_t rslt = 1; 28 | Serial.begin(115200); 29 | while(!Serial); 30 | delay(1000); 31 | Serial.println(); 32 | while(rslt != 0) { 33 | rslt = bme.begin(); 34 | if(rslt != 0) { 35 | Serial.println("bme begin failure"); 36 | delay(2000); 37 | } 38 | } 39 | Serial.println("bme begin successful"); 40 | bme.supportIAQ(); 41 | } 42 | 43 | void loop() 44 | { 45 | static uint8_t calibrated = 0; 46 | 47 | #ifdef CALIBRATE_PRESSURE 48 | if(calibrated == 0) { 49 | if(bme.iaqUpdate() == 0) { 50 | /*You can use an accurate altitude to calibrate sea level air pressure. 51 | *And then use this calibrated sea level pressure as a reference to obtain the calibrated altitude. 52 | *In this case,525.0m is chendu accurate altitude. 53 | */ 54 | seaLevel = bme.readSeaLevel(525.0); 55 | Serial.print("seaLevel :"); 56 | Serial.println(seaLevel); 57 | calibrated = 1; 58 | } 59 | } 60 | #else 61 | calibrated = 1; 62 | #endif 63 | 64 | if(calibrated) { 65 | uint8_t rslt = bme.iaqUpdate(); 66 | if(rslt == 0) { 67 | Serial.println(); 68 | Serial.print("timestamp(ms) :"); 69 | Serial.println(millis()); 70 | Serial.print("temperature(C) :"); 71 | Serial.println(bme.readTemperature(), 2); 72 | Serial.print("pressure(Pa) :"); 73 | Serial.println(bme.readPressure()); 74 | Serial.print("humidity(%rh) :"); 75 | Serial.println(bme.readHumidity(), 2); 76 | Serial.print("altitude(m) :"); 77 | Serial.println(bme.readAltitude()); 78 | #ifdef CALIBRATE_PRESSURE 79 | Serial.print("calibrated altitude(m) :"); 80 | Serial.println(bme.readCalibratedAltitude(seaLevel)); 81 | #endif 82 | Serial.print("gas resistance :"); 83 | Serial.println(bme.readGasResistance()); 84 | if(bme.isIAQReady()) { 85 | Serial.print("IAQ :"); 86 | float iaq = bme.readIAQ(); 87 | Serial.print(iaq); 88 | if(iaq < 50) Serial.println(" good"); 89 | else if(iaq < 100) Serial.println(" average"); 90 | else if(iaq < 150) Serial.println(" little bad"); 91 | else if(iaq < 200) Serial.println(" bad"); 92 | else if(iaq < 300) Serial.println(" worse"); 93 | else Serial.println(" very bad"); 94 | } else { 95 | Serial.print("IAQ not ready, please wait about "); 96 | Serial.print((int)(305000-millis())/1000); 97 | Serial.println(" seconds"); 98 | } 99 | } 100 | } 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /examples/IAQ_SPI/IAQ_SPI.ino: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file IAQ_SPI.ino 3 | * @brief Connect bme680 4 wires SPI interface with your board (please reference board compatibility). 4 | * @n BME680 cs pin connect to D3 on esp8266 and esp32 board, on AVR board is IO 3. 5 | * @n Temprature, Humidity, pressure, altitude, calibrated altitude, gas resistance and IAQ data will be printed via serial. 6 | * @note This demo only support ESP8266 MCU 7 | * 8 | * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) 9 | * @license The MIT License (MIT) 10 | * @author [Frank](jiehan.guo@dfrobot.com) 11 | * @version V1.0 12 | * @date 2017-12-7 13 | * @url https://github.com/DFRobot/DFRobot_BME680 14 | */ 15 | 16 | #include "DFRobot_BME680_SPI.h" 17 | #include "SPI.h" 18 | 19 | /*use an accurate altitude to calibrate sea level air pressure*/ 20 | #define CALIBRATE_PRESSURE 21 | 22 | DFRobot_BME680_SPI bme(D3); 23 | 24 | float seaLevel; 25 | void setup() 26 | { 27 | uint8_t rslt = 1; 28 | Serial.begin(115200); 29 | while(!Serial); 30 | delay(1000); 31 | Serial.println(); 32 | while(rslt != 0) { 33 | rslt = bme.begin(); 34 | if(rslt != 0) { 35 | Serial.println("bme begin failure"); 36 | delay(2000); 37 | } 38 | } 39 | Serial.println("bme begin successful"); 40 | bme.supportIAQ(); 41 | } 42 | 43 | void loop() 44 | { 45 | static uint8_t calibrated = 0; 46 | 47 | #ifdef CALIBRATE_PRESSURE 48 | if(calibrated == 0) { 49 | if(bme.iaqUpdate() == 0) { 50 | /*You can use an accurate altitude to calibrate sea level air pressure. 51 | *And then use this calibrated sea level pressure as a reference to obtain the calibrated altitude. 52 | *In this case,525.0m is chendu accurate altitude. 53 | */ 54 | seaLevel = bme.readSeaLevel(525.0); 55 | Serial.print("seaLevel :"); 56 | Serial.println(seaLevel); 57 | calibrated = 1; 58 | } 59 | } 60 | #else 61 | calibrated = 1; 62 | #endif 63 | 64 | if(calibrated) { 65 | uint8_t rslt = bme.iaqUpdate(); 66 | if(rslt == 0) { 67 | Serial.println(); 68 | Serial.print("timestamp(ms) :"); 69 | Serial.println(millis()); 70 | Serial.print("temperature(C) :"); 71 | Serial.println(bme.readTemperature(), 2); 72 | Serial.print("pressure(Pa) :"); 73 | Serial.println(bme.readPressure()); 74 | Serial.print("humidity(%rh) :"); 75 | Serial.println(bme.readHumidity(), 2); 76 | Serial.print("altitude(m) :"); 77 | Serial.println(bme.readAltitude()); 78 | #ifdef CALIBRATE_PRESSURE 79 | Serial.print("calibrated altitude(m) :"); 80 | Serial.println(bme.readCalibratedAltitude(seaLevel)); 81 | #endif 82 | Serial.print("gas resistance :"); 83 | Serial.println(bme.readGasResistance()); 84 | if(bme.isIAQReady()) { 85 | Serial.print("IAQ :"); 86 | float iaq = bme.readIAQ(); 87 | Serial.print(iaq); 88 | if(iaq < 50) Serial.println(" good"); 89 | else if(iaq < 100) Serial.println(" average"); 90 | else if(iaq < 150) Serial.println(" little bad"); 91 | else if(iaq < 200) Serial.println(" bad"); 92 | else if(iaq < 300) Serial.println(" worse"); 93 | else Serial.println(" very bad"); 94 | } else Serial.println("IAQ not ready, please wait about 5 minutes"); 95 | } else { 96 | Serial.print("IAQ not ready, please wait about "); 97 | Serial.print((int)(305000-millis())/1000); 98 | Serial.println(" seconds"); 99 | } 100 | } 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Attention: 2 | 3 | IAQ process is for experienced people. 4 | Wait about 5 minutes to get correct IAQ data. 5 | 6 | IAQ example compatibility 7 | 8 | platform | Work Well | Work Wrong | Untested | Remarks 9 | ------------------ | :----------: | :----------: | :---------: | ----- 10 | ESP8266 | √ | | | SDK -V 2.3.0 11 | 12 | Others can't work now. 13 | 14 | ## How to get IAQ? 15 | 16 | Processing.(Reference in docs_for_iaq\BST-BME680-AN008-45.pdf chapter 2.4, page 15) 17 | 18 | ### Platform 19 | 20 | #### esp8266 21 | 22 | 1.We need to copy the file docs_for_iaq\esp8266\libalgobsec.a and paste the file into the hardware\esp8266\2.3.0\tools\sdk\lib folder. 23 | 24 | 2.Find eagle.app.v6.common.ld in your esp8266 SDK folder. 25 | 26 | (if you do't modify it before, you can copy docs_for_iaq/esp8266/platform.txt to replace) 27 | 28 | The linker file found at hardware\esp8266\2.3.0\tools\sdk\ld\eagle.app.v6.common.ld needs to be modifed. 29 | Inserting the line *libalgobsec.a:(.literal .text .literal.* .text.*) after the line *libm.a:(.literal .text .literal.* .text.*). 30 | 31 | 3.Find platform.txt in your esp8266 SDK folder. 32 | 33 | (if you do't modify it before, you can copy docs_for_iaq/esp8266/platform.txt to replace) 34 | 35 | Finally, we need to change the linker argument, telling the linker to include BSEC file. This is achieved by adding the 36 | argument -lalgobsec to the line compiler.c.elf.libs=-lm -lgcc ... found in hardware\esp8266\2.3.0\platform.txt. 37 | -------------------------------------------------------------------------------- /examples/docs_for_iaq/BST-BME680-AN008-45.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/DFRobot_BME680/fcd2a6496ba574e053e03cfe15f320e7ca2fe6fb/examples/docs_for_iaq/BST-BME680-AN008-45.pdf -------------------------------------------------------------------------------- /examples/docs_for_iaq/esp8266/eagle.app.v6.common.ld: -------------------------------------------------------------------------------- 1 | /* This linker script generated from xt-genldscripts.tpp for LSP . */ 2 | /* Linker Script for ld -N */ 3 | 4 | PHDRS 5 | { 6 | dport0_0_phdr PT_LOAD; 7 | dram0_0_phdr PT_LOAD; 8 | dram0_0_bss_phdr PT_LOAD; 9 | iram1_0_phdr PT_LOAD; 10 | irom0_0_phdr PT_LOAD; 11 | } 12 | 13 | 14 | /* Default entry point: */ 15 | ENTRY(call_user_start) 16 | EXTERN(_DebugExceptionVector) 17 | EXTERN(_DoubleExceptionVector) 18 | EXTERN(_KernelExceptionVector) 19 | EXTERN(_NMIExceptionVector) 20 | EXTERN(_UserExceptionVector) 21 | PROVIDE(_memmap_vecbase_reset = 0x40000000); 22 | /* Various memory-map dependent cache attribute settings: */ 23 | _memmap_cacheattr_wb_base = 0x00000110; 24 | _memmap_cacheattr_wt_base = 0x00000110; 25 | _memmap_cacheattr_bp_base = 0x00000220; 26 | _memmap_cacheattr_unused_mask = 0xFFFFF00F; 27 | _memmap_cacheattr_wb_trapnull = 0x2222211F; 28 | _memmap_cacheattr_wba_trapnull = 0x2222211F; 29 | _memmap_cacheattr_wbna_trapnull = 0x2222211F; 30 | _memmap_cacheattr_wt_trapnull = 0x2222211F; 31 | _memmap_cacheattr_bp_trapnull = 0x2222222F; 32 | _memmap_cacheattr_wb_strict = 0xFFFFF11F; 33 | _memmap_cacheattr_wt_strict = 0xFFFFF11F; 34 | _memmap_cacheattr_bp_strict = 0xFFFFF22F; 35 | _memmap_cacheattr_wb_allvalid = 0x22222112; 36 | _memmap_cacheattr_wt_allvalid = 0x22222112; 37 | _memmap_cacheattr_bp_allvalid = 0x22222222; 38 | PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); 39 | 40 | SECTIONS 41 | { 42 | 43 | .dport0.rodata : ALIGN(4) 44 | { 45 | _dport0_rodata_start = ABSOLUTE(.); 46 | *(.dport0.rodata) 47 | *(.dport.rodata) 48 | _dport0_rodata_end = ABSOLUTE(.); 49 | } >dport0_0_seg :dport0_0_phdr 50 | 51 | .dport0.literal : ALIGN(4) 52 | { 53 | _dport0_literal_start = ABSOLUTE(.); 54 | *(.dport0.literal) 55 | *(.dport.literal) 56 | _dport0_literal_end = ABSOLUTE(.); 57 | } >dport0_0_seg :dport0_0_phdr 58 | 59 | .dport0.data : ALIGN(4) 60 | { 61 | _dport0_data_start = ABSOLUTE(.); 62 | *(.dport0.data) 63 | *(.dport.data) 64 | _dport0_data_end = ABSOLUTE(.); 65 | } >dport0_0_seg :dport0_0_phdr 66 | 67 | .data : ALIGN(4) 68 | { 69 | _data_start = ABSOLUTE(.); 70 | *(.data) 71 | *(.data.*) 72 | *(.gnu.linkonce.d.*) 73 | *(.data1) 74 | *(.sdata) 75 | *(.sdata.*) 76 | *(.gnu.linkonce.s.*) 77 | *(.sdata2) 78 | *(.sdata2.*) 79 | *(.gnu.linkonce.s2.*) 80 | *(.jcr) 81 | . = ALIGN(4); 82 | _Pri_3_HandlerAddress = ABSOLUTE(.); 83 | _data_end = ABSOLUTE(.); 84 | } >dram0_0_seg :dram0_0_phdr 85 | 86 | .rodata : ALIGN(4) 87 | { 88 | _rodata_start = ABSOLUTE(.); 89 | *(.sdk.version) 90 | *(.rodata) 91 | *(.rodata.*) 92 | *(.gnu.linkonce.r.*) 93 | *(.rodata1) 94 | __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); 95 | *(.xt_except_table) 96 | *(.gcc_except_table) 97 | *(.gnu.linkonce.e.*) 98 | *(.gnu.version_r) 99 | *(.eh_frame) 100 | . = (. + 3) & ~ 3; 101 | /* C++ constructor and destructor tables, properly ordered: */ 102 | __init_array_start = ABSOLUTE(.); 103 | KEEP (*crtbegin.o(.ctors)) 104 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 105 | KEEP (*(SORT(.ctors.*))) 106 | KEEP (*(.ctors)) 107 | __init_array_end = ABSOLUTE(.); 108 | KEEP (*crtbegin.o(.dtors)) 109 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 110 | KEEP (*(SORT(.dtors.*))) 111 | KEEP (*(.dtors)) 112 | /* C++ exception handlers table: */ 113 | __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); 114 | *(.xt_except_desc) 115 | *(.gnu.linkonce.h.*) 116 | __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); 117 | *(.xt_except_desc_end) 118 | *(.dynamic) 119 | *(.gnu.version_d) 120 | . = ALIGN(4); /* this table MUST be 4-byte aligned */ 121 | _bss_table_start = ABSOLUTE(.); 122 | LONG(_bss_start) 123 | LONG(_bss_end) 124 | _bss_table_end = ABSOLUTE(.); 125 | _rodata_end = ABSOLUTE(.); 126 | } >dram0_0_seg :dram0_0_phdr 127 | 128 | .bss ALIGN(8) (NOLOAD) : ALIGN(4) 129 | { 130 | . = ALIGN (8); 131 | _bss_start = ABSOLUTE(.); 132 | *(.dynsbss) 133 | *(.sbss) 134 | *(.sbss.*) 135 | *(.gnu.linkonce.sb.*) 136 | *(.scommon) 137 | *(.sbss2) 138 | *(.sbss2.*) 139 | *(.gnu.linkonce.sb2.*) 140 | *(.dynbss) 141 | *(.bss) 142 | *(.bss.*) 143 | *(.gnu.linkonce.b.*) 144 | *(COMMON) 145 | . = ALIGN (8); 146 | _bss_end = ABSOLUTE(.); 147 | _heap_start = ABSOLUTE(.); 148 | /* _stack_sentry = ALIGN(0x8); */ 149 | } >dram0_0_seg :dram0_0_bss_phdr 150 | /* __stack = 0x3ffc8000; */ 151 | 152 | .irom0.text : ALIGN(4) 153 | { 154 | _irom0_text_start = ABSOLUTE(.); 155 | *(.ver_number) 156 | *.c.o( EXCLUDE_FILE (umm_malloc.c.o) .literal*, \ 157 | EXCLUDE_FILE (umm_malloc.c.o) .text*) 158 | *.cpp.o(.literal*, .text*) 159 | *libm.a:(.literal .text .literal.* .text.*) 160 | *libalgobsec.a:(.literal .text .literal.* .text.*) 161 | *libgcc.a:_umoddi3.o(.literal .text) 162 | *libgcc.a:_udivdi3.o(.literal .text) 163 | *libsmartconfig.a:(.literal .text .literal.* .text.*) 164 | *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text .irom.text.*) 165 | _irom0_text_end = ABSOLUTE(.); 166 | _flash_code_end = ABSOLUTE(.); 167 | } >irom0_0_seg :irom0_0_phdr 168 | 169 | .text : ALIGN(4) 170 | { 171 | _stext = .; 172 | _text_start = ABSOLUTE(.); 173 | *(.UserEnter.text) 174 | . = ALIGN(16); 175 | *(.DebugExceptionVector.text) 176 | . = ALIGN(16); 177 | *(.NMIExceptionVector.text) 178 | . = ALIGN(16); 179 | *(.KernelExceptionVector.text) 180 | LONG(0) 181 | LONG(0) 182 | LONG(0) 183 | LONG(0) 184 | . = ALIGN(16); 185 | *(.UserExceptionVector.text) 186 | LONG(0) 187 | LONG(0) 188 | LONG(0) 189 | LONG(0) 190 | . = ALIGN(16); 191 | *(.DoubleExceptionVector.text) 192 | LONG(0) 193 | LONG(0) 194 | LONG(0) 195 | LONG(0) 196 | . = ALIGN (16); 197 | *(.entry.text) 198 | *(.init.literal) 199 | *(.init) 200 | *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) 201 | *.cpp.o(.iram.text) 202 | *.c.o(.iram.text) 203 | *(.fini.literal) 204 | *(.fini) 205 | *(.gnu.version) 206 | _text_end = ABSOLUTE(.); 207 | _etext = .; 208 | } >iram1_0_seg :iram1_0_phdr 209 | 210 | .lit4 : ALIGN(4) 211 | { 212 | _lit4_start = ABSOLUTE(.); 213 | *(*.lit4) 214 | *(.lit4.*) 215 | *(.gnu.linkonce.lit4.*) 216 | _lit4_end = ABSOLUTE(.); 217 | } >iram1_0_seg :iram1_0_phdr 218 | 219 | 220 | } 221 | 222 | /* get ROM code address */ 223 | INCLUDE "../ld/eagle.rom.addr.v6.ld" 224 | -------------------------------------------------------------------------------- /examples/docs_for_iaq/esp8266/libalgobsec.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/DFRobot_BME680/fcd2a6496ba574e053e03cfe15f320e7ca2fe6fb/examples/docs_for_iaq/esp8266/libalgobsec.a -------------------------------------------------------------------------------- /examples/docs_for_iaq/esp8266/platform.txt: -------------------------------------------------------------------------------- 1 | 2 | # ESP8266 platform 3 | # ------------------------------ 4 | 5 | # For more info: 6 | # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification 7 | 8 | name=ESP8266 Modules 9 | version=2.2.0 10 | 11 | 12 | 13 | 14 | compiler.warning_flags=-w 15 | compiler.warning_flags.none=-w 16 | compiler.warning_flags.default= 17 | compiler.warning_flags.more=-Wall 18 | compiler.warning_flags.all=-Wall -Wextra 19 | 20 | build.lwip_lib=-llwip_gcc 21 | build.lwip_flags=-DLWIP_OPEN_SRC 22 | 23 | compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/ 24 | compiler.sdk.path={runtime.platform.path}/tools/sdk 25 | compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" "-I{compiler.sdk.path}/lwip/include" "-I{build.path}/core" 26 | 27 | compiler.c.cmd=xtensa-lx106-elf-gcc 28 | compiler.c.flags=-c {compiler.warning_flags} -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=gnu99 -ffunction-sections -fdata-sections 29 | 30 | compiler.S.cmd=xtensa-lx106-elf-gcc 31 | compiler.S.flags=-c -g -x assembler-with-cpp -MMD -mlongcalls 32 | 33 | compiler.c.elf.flags=-g {compiler.warning_flags} -Os -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" -Wl,--gc-sections -Wl,-wrap,system_restart_local -Wl,-wrap,register_chipv6_phy 34 | 35 | compiler.c.elf.cmd=xtensa-lx106-elf-gcc 36 | compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lpp -lnet80211 -lwpa -lcrypto -lmain -lwps -laxtls -lsmartconfig -lmesh -lwpa2 {build.lwip_lib} -lstdc++ -lalgobsec 37 | 38 | compiler.cpp.cmd=xtensa-lx106-elf-g++ 39 | compiler.cpp.flags=-c {compiler.warning_flags} -Os -g -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD -ffunction-sections -fdata-sections 40 | 41 | compiler.as.cmd=xtensa-lx106-elf-as 42 | 43 | compiler.ar.cmd=xtensa-lx106-elf-ar 44 | compiler.ar.flags=cru 45 | 46 | compiler.elf2hex.cmd=esptool 47 | compiler.elf2hex.flags= 48 | 49 | compiler.size.cmd=xtensa-lx106-elf-size 50 | 51 | compiler.esptool.cmd=esptool 52 | compiler.esptool.cmd.windows=esptool.exe 53 | 54 | # This can be overriden in boards.txt 55 | build.extra_flags=-DESP8266 56 | 57 | # These can be overridden in platform.local.txt 58 | compiler.c.extra_flags= 59 | compiler.c.elf.extra_flags= 60 | compiler.S.extra_flags= 61 | compiler.cpp.extra_flags= 62 | compiler.ar.extra_flags= 63 | compiler.objcopy.eep.extra_flags= 64 | compiler.elf2hex.extra_flags= 65 | 66 | ## generate file with git version number 67 | ## needs bash, git, and echo 68 | 69 | ## windows-compatible version may be added later 70 | 71 | 72 | ## Compile c files 73 | recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" 74 | 75 | ## Compile c++ files 76 | recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" 77 | 78 | ## Compile S files 79 | recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} {build.lwip_flags} {build.debug_port} {build.debug_level} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" 80 | 81 | ## Create archives 82 | recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/arduino.ar" "{object_file}" 83 | 84 | ## Combine gc-sections, archives, and objects 85 | recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" -Wl,--start-group {object_files} "{build.path}/arduino.ar" {compiler.c.elf.libs} -Wl,--end-group "-L{build.path}" 86 | 87 | ## Create eeprom 88 | recipe.objcopy.eep.pattern= 89 | 90 | ## Create hex 91 | #recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" 92 | 93 | recipe.objcopy.hex.pattern="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{runtime.platform.path}/bootloaders/eboot/eboot.elf" -bo "{build.path}/{build.project_name}.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bp 4096 -ec -eo "{build.path}/{build.project_name}.elf" -bs .irom0.text -bs .text -bs .data -bs .rodata -bc -ec 94 | 95 | ## Save hex 96 | recipe.output.tmp_file={build.project_name}.bin 97 | recipe.output.save_file={build.project_name}.{build.variant}.bin 98 | 99 | ## Compute size 100 | recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" 101 | recipe.size.regex=^(?:\.irom0\.text|\.text|\.data|\.rodata|)\s+([0-9]+).* 102 | recipe.size.regex.data=^(?:\.data|\.rodata|\.bss)\s+([0-9]+).* 103 | #recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).* 104 | 105 | # ------------------------------ 106 | 107 | tools.esptool.cmd=esptool 108 | tools.esptool.cmd.windows=esptool.exe 109 | tools.esptool.path={runtime.tools.esptool.path} 110 | tools.esptool.network_cmd=python 111 | tools.esptool.network_cmd.windows=python.exe 112 | 113 | tools.esptool.upload.protocol=esp 114 | tools.esptool.upload.params.verbose=-vv 115 | tools.esptool.upload.params.quiet= 116 | tools.esptool.upload.pattern="{path}/{cmd}" {upload.verbose} -cd {upload.resetmethod} -cb {upload.speed} -cp "{serial.port}" -ca 0x00000 -cf "{build.path}/{build.project_name}.bin" 117 | tools.esptool.upload.network_pattern="{network_cmd}" "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin" 118 | 119 | tools.mkspiffs.cmd=mkspiffs 120 | tools.mkspiffs.cmd.windows=mkspiffs.exe 121 | tools.mkspiffs.path={runtime.tools.mkspiffs.path} 122 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring BME680 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | DFRobot_BME680_SPI KEYWORD1 10 | DFRobot_BME680_I2C KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | begin KEYWORD2 17 | startConvert KEYWORD2 18 | update KEYWORD2 19 | supportIAQ KEYWORD2 20 | iaqUpdate KEYWORD2 21 | isIAQReady KEYWORD2 22 | setParam KEYWORD2 23 | setGasHeater KEYWORD2 24 | readTempture KEYWORD2 25 | readHumidity KEYWORD2 26 | readPressure KEYWORD2 27 | readGas KEYWORD2 28 | readAltitude KEYWORD2 29 | readGasResistance KEYWORD2 30 | reaCalibratedAltitude KEYWORD2 -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=DFRobot_BME680 2 | version=2.0.0 3 | author=DFRobot 4 | maintainer=Frank(jiehan.guo@dfrobot.com) 5 | sentence=DFRobot Standard library(SKU:SEN0248). 6 | paragraph=BME680 is an integrated environmental sensor. 7 | category=Sensor 8 | url=https://github.com/DFRobot/DFRobot_BME680 9 | architectures=* 10 | -------------------------------------------------------------------------------- /resources/images/SEN0248.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DFRobot/DFRobot_BME680/fcd2a6496ba574e053e03cfe15f320e7ca2fe6fb/resources/images/SEN0248.png --------------------------------------------------------------------------------