├── 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 | 
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 | 
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 | 
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 | 
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
--------------------------------------------------------------------------------