BME680 driver interface changes
- function bme680_force_measurement returns now a boolean - function bme680_is_measuring returns now boolean - function bme680_get_measurement_duration added - heating profiles implemented - example for heating profiles added
This commit is contained in:
parent
1bd9364ebb
commit
5b90f0ef58
9 changed files with 831 additions and 422 deletions
|
|
@ -19,6 +19,7 @@ For examples using BME680 sensor as I2C slave, just use GPIO5 (SCL) and GPIO4 (S
|
|||
|
||||
For examples that are using SPI, BME680 sensor has to be connected to SPI bus 1. Since GPIO15 used as default CS signal of SPI bus 1 does not work correctly together with BME680, you have to connect CS to another GPIO pin, e.g., GPIO2.
|
||||
|
||||
```
|
||||
+-------------------------+ +----------+
|
||||
| ESP8266 Bus 1 | | BME680 |
|
||||
| GPIO 12 (MISO) <-----< SDO |
|
||||
|
|
@ -26,6 +27,7 @@ For examples that are using SPI, BME680 sensor has to be connected to SPI bus 1.
|
|||
| GPIO 14 (SCK) >-----> SCK |
|
||||
| GPIO 2 (CS) >-----> CS |
|
||||
+-------------------------+ +----------+
|
||||
```
|
||||
|
||||
The example with two sensors use the combination of I2C and SPI.
|
||||
|
||||
|
|
@ -33,8 +35,12 @@ The example with two sensors use the combination of I2C and SPI.
|
|||
|
||||
__*bme680_one_sensor*__
|
||||
|
||||
In this simple example, only **one sensor** connected either to **I2C** or to **SPI** is used. Constant **SPI_USED** defines which interface is used.
|
||||
This simple example uses only **one sensor** connected either to **I2C** or to **SPI**. Which of these interfaces is used is defined by constant **SPI_USED**. The user task triggers a measurement every second and uses function ```vTaskDelay``` to wait for the measurement results.
|
||||
|
||||
__*bme680_two_sensors*__
|
||||
|
||||
Simple example with two sensors, one sensor connected to **I2C** bus 0 and one sensor connected to **SPI**. It defines two different user tasks that use the sensors as well as different approaches for the implementation of waiting for measurement results, one as busy waiting using **_bme680_is_measuring_** and one as passive waiting using *vTaskDelay*.
|
||||
This example uses **two sensors**. One sensor is connected to **I2C** bus 0 and one sensor is connected to **SPI**. It defines two different user tasks, one for each sensor. It demonstrate the possible approaches to wait for measurement results, active busy waiting using ```bme680_is_measuring``` and passive waiting using *vTaskDelay*.
|
||||
|
||||
__*bme680_heating_profiles*__
|
||||
|
||||
This simple example uses one **only sensor** connected to **I2C** bus 0 and a sequence of heating profiles. The heating profile is changed with each cycle.
|
||||
|
|
|
|||
3
examples/bme680/bme680_heating_profiles/Makefile
Normal file
3
examples/bme680/bme680_heating_profiles/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=BME680_heating_profiles
|
||||
EXTRA_COMPONENTS = extras/i2c extras/bme680
|
||||
include ../../../common.mk
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* Simple example with one sensor connected to I2C bus 0 and a sequence of
|
||||
* heating profiles. The heating profile is changed with each cycle.
|
||||
*
|
||||
* Harware configuration:
|
||||
*
|
||||
* I2C +-------------------------+ +----------+
|
||||
* | ESP8266 Bus 0 | | BME680 |
|
||||
* | GPIO 5 (SCL) ------> SCL |
|
||||
* | GPIO 4 (SDA) ------- SDA |
|
||||
* +-------------------------+ +----------+
|
||||
*/
|
||||
|
||||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
// include communication interface driver
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
// include BME680 driver
|
||||
#include "bme680/bme680.h"
|
||||
|
||||
// define I2C interface for BME680 sensors
|
||||
#define I2C_BUS 0
|
||||
#define I2C_SCL_PIN GPIO_ID_PIN((5))
|
||||
#define I2C_SDA_PIN GPIO_ID_PIN((4))
|
||||
|
||||
static bme680_sensor_t* sensor;
|
||||
|
||||
/*
|
||||
* User task that triggers measurements of sensor every seconds. It uses
|
||||
* function *vTaskDelay* to wait for measurement results and changes the
|
||||
* heating profile in each cycle.
|
||||
*/
|
||||
void user_task(void *pvParameters)
|
||||
{
|
||||
bme680_values_float_t values;
|
||||
|
||||
TickType_t last_wakeup = xTaskGetTickCount();
|
||||
|
||||
uint32_t count = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (count++ < 60)
|
||||
// disable gas measurement for cycle counter < 60
|
||||
bme680_use_heater_profile (sensor, BME680_HEATER_NOT_USED);
|
||||
else
|
||||
// change heating profile in each cycle
|
||||
switch (count % 5)
|
||||
{
|
||||
case 0: bme680_use_heater_profile (sensor, 0); break;
|
||||
case 1: bme680_use_heater_profile (sensor, 1); break;
|
||||
case 2: bme680_use_heater_profile (sensor, 2); break;
|
||||
case 3: bme680_use_heater_profile (sensor, 3); break;
|
||||
case 4: bme680_use_heater_profile (sensor, 4); break;
|
||||
}
|
||||
|
||||
// measurement duration changes in each cycle
|
||||
uint32_t duration = bme680_get_measurement_duration(sensor);
|
||||
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
if (bme680_force_measurement (sensor))
|
||||
{
|
||||
// passive waiting until measurement results are available
|
||||
vTaskDelay (duration);
|
||||
|
||||
// get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
printf("%.3f BME680 Sensor: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
}
|
||||
// passive waiting until 1 second is over
|
||||
vTaskDelayUntil(&last_wakeup, 1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
// Set UART Parameter
|
||||
uart_set_baud(0, 115200);
|
||||
// Give the UART some time to settle
|
||||
sdk_os_delay_us(500);
|
||||
|
||||
/** -- MANDATORY PART -- */
|
||||
|
||||
#ifdef SPI_USED
|
||||
// Init the sensor connected either to SPI.
|
||||
sensor = bme680_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
|
||||
#else
|
||||
// Init all I2C bus interfaces at which BME680 sensors are connected
|
||||
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K);
|
||||
|
||||
// Init the sensor connected either to I2C.
|
||||
sensor = bme680_init_sensor (I2C_BUS, BME680_I2C_ADDRESS_2, 0);
|
||||
#endif
|
||||
|
||||
if (sensor)
|
||||
{
|
||||
// Create a task that uses the sensor
|
||||
xTaskCreate(user_task, "user_task", 256, NULL, 2, NULL);
|
||||
|
||||
/** -- OPTIONAL PART -- */
|
||||
|
||||
// Changes the oversampling rates to 4x oversampling for temperature
|
||||
// and 2x oversampling for humidity. Pressure measurement is skipped.
|
||||
bme680_set_oversampling_rates(sensor, osr_4x, osr_none, osr_2x);
|
||||
|
||||
// Change the IIR filter size for temperature and pressure to 7.
|
||||
bme680_set_filter_size(sensor, iir_size_7);
|
||||
|
||||
// Define a number of different heating profiles
|
||||
bme680_set_heater_profile (sensor, 0, 200, 100);
|
||||
bme680_set_heater_profile (sensor, 1, 250, 120);
|
||||
bme680_set_heater_profile (sensor, 2, 300, 140);
|
||||
bme680_set_heater_profile (sensor, 3, 350, 160);
|
||||
bme680_set_heater_profile (sensor, 4, 400, 180);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,28 +56,30 @@ static bme680_sensor_t* sensor;
|
|||
void user_task(void *pvParameters)
|
||||
{
|
||||
bme680_values_float_t values;
|
||||
int32_t duration;
|
||||
|
||||
TickType_t last_wakeup = xTaskGetTickCount();
|
||||
|
||||
// as long as sensor configuration isn't changed, duration is constant
|
||||
uint32_t duration = bme680_get_measurement_duration(sensor);
|
||||
|
||||
while (1)
|
||||
{
|
||||
{
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
duration = bme680_force_measurement (sensor);
|
||||
if (bme680_force_measurement (sensor))
|
||||
{
|
||||
// passive waiting until measurement results are available
|
||||
vTaskDelay (duration);
|
||||
|
||||
// passive waiting until measurement results are available
|
||||
if (duration > 0) vTaskDelay (duration);
|
||||
|
||||
// busy waiting until measurement results are available
|
||||
// while (bme680_is_measuring (sensor) > 0) ;
|
||||
|
||||
// get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
printf("%.3f BME680 Sensor: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
// alternatively: busy waiting until measurement results are available
|
||||
// while (bme680_is_measuring (sensor)) ;
|
||||
|
||||
// get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
printf("%.3f BME680 Sensor: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
}
|
||||
// passive waiting until 1 second is over
|
||||
vTaskDelayUntil(&last_wakeup, 1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
|
@ -93,7 +95,6 @@ void user_init(void)
|
|||
|
||||
/** -- MANDATORY PART -- */
|
||||
|
||||
|
||||
#ifdef SPI_USED
|
||||
// Init the sensor connected either to SPI.
|
||||
sensor = bme680_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
|
||||
|
|
@ -112,18 +113,19 @@ void user_init(void)
|
|||
|
||||
/** -- OPTIONAL PART -- */
|
||||
|
||||
// Changes the oversampling rates (default os_1x) to 4x oversampling
|
||||
// for temperature and 2x oversampling for humidity. Pressure
|
||||
// measurement is skipped in this example.
|
||||
// Changes the oversampling rates to 4x oversampling for temperature
|
||||
// and 2x oversampling for humidity. Pressure measurement is skipped.
|
||||
bme680_set_oversampling_rates(sensor, osr_4x, osr_none, osr_2x);
|
||||
|
||||
// Change the IIR filter size (default iir_size_3) for temperature and
|
||||
// and pressure to 7.
|
||||
// Change the IIR filter size for temperature and pressure to 7.
|
||||
bme680_set_filter_size(sensor, iir_size_7);
|
||||
|
||||
// Change the heaeter profile (default 320 degree Celcius for 150 ms)
|
||||
// to 200 degree Celcius for 100 ms.
|
||||
bme680_set_heater_profile (sensor, 320, 150);
|
||||
// Change the heater profile 0 to 200 degree Celcius for 100 ms.
|
||||
bme680_set_heater_profile (sensor, 0, 200, 100);
|
||||
bme680_use_heater_profile (sensor, 0);
|
||||
|
||||
// Set ambient temperature to 10 degree Celsius
|
||||
bme680_set_ambient_temperature (sensor, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* Simple example with two sensors, one sensor connected to I2C bus 0 and
|
||||
* one sensor connected to SPI. It also shows both approaches for the
|
||||
* implementation of waiting for measurement results, one as busy waiting
|
||||
* and one as passive waiting using *vTaskDelay*.
|
||||
* one sensor connected to SPI. It defines two different user tasks, one for
|
||||
* each sensor. It demonstrate the possible approaches to wait for measurement
|
||||
* results, active busy waiting using ```bme680_is_measuring``` and passive
|
||||
* waiting using *vTaskDelay*.
|
||||
*
|
||||
* Harware configuration:
|
||||
*
|
||||
|
|
@ -44,30 +45,33 @@ static bme680_sensor_t* sensor1;
|
|||
static bme680_sensor_t* sensor2;
|
||||
|
||||
/*
|
||||
* User task that triggers measurements of sensor1 every 5 seconds. It
|
||||
* User task that triggers measurements of sensor1 every 5 seconds and
|
||||
* uses *vTaskDelay* to wait for measurement results.
|
||||
*/
|
||||
void user_task_sensor1(void *pvParameters)
|
||||
{
|
||||
bme680_values_float_t values;
|
||||
int32_t duration;
|
||||
|
||||
TickType_t last_wakeup = xTaskGetTickCount();
|
||||
|
||||
uint32_t duration = bme680_get_measurement_duration (sensor1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
duration = bme680_force_measurement (sensor1);
|
||||
if (bme680_force_measurement (sensor1))
|
||||
{
|
||||
|
||||
// passive waiting until measurement results are available
|
||||
if (duration > 0) vTaskDelay (duration);
|
||||
// passive waiting until measurement results are available
|
||||
vTaskDelay (duration);
|
||||
|
||||
// get the results and so something with them
|
||||
if (bme680_get_results_float (sensor1, &values))
|
||||
printf("%.3f BME680 Sensor1: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
// get the results and so something with them
|
||||
if (bme680_get_results_float (sensor1, &values))
|
||||
printf("%.3f BME680 Sensor1: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
}
|
||||
|
||||
// passive waiting until 5 seconds are over
|
||||
vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS);
|
||||
|
|
@ -75,8 +79,8 @@ void user_task_sensor1(void *pvParameters)
|
|||
}
|
||||
|
||||
/*
|
||||
* User task that triggers measurements of sensor1 every 2 seconds. It
|
||||
* uses *vTaskDelay* to wait for measurement results.
|
||||
* User task that triggers measurements of sensor1 every 2 seconds and
|
||||
* uses *bme680_is_measuring* to wait for measurement results.
|
||||
*/
|
||||
void user_task_sensor2(void *pvParameters)
|
||||
{
|
||||
|
|
@ -87,17 +91,18 @@ void user_task_sensor2(void *pvParameters)
|
|||
while (1)
|
||||
{
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
bme680_force_measurement (sensor2);
|
||||
|
||||
// busy waiting until measurement results are available
|
||||
while (bme680_is_measuring (sensor2) > 0) ;
|
||||
if (bme680_force_measurement (sensor2))
|
||||
{
|
||||
// busy waiting until measurement results are available
|
||||
while (bme680_is_measuring (sensor2)) ;
|
||||
|
||||
// get the results and so something with them
|
||||
if (bme680_get_results_float (sensor2, &values))
|
||||
printf("%.3f BME680 Sensor2: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
// get the results and so something with them
|
||||
if (bme680_get_results_float (sensor2, &values))
|
||||
printf("%.3f BME680 Sensor2: %.2f °C, %.2f %%, %.2f hPa, %.2f Ohm\n",
|
||||
(double)sdk_system_get_time()*1e-3,
|
||||
values.temperature, values.humidity,
|
||||
values.pressure, values.gas_resistance);
|
||||
}
|
||||
|
||||
// passive waiting until 2 seconds are over
|
||||
vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS);
|
||||
|
|
@ -132,18 +137,20 @@ void user_init(void)
|
|||
/** -- OPTIONAL PART -- */
|
||||
|
||||
// Changes the oversampling rates for both sensor to different values
|
||||
bme680_set_oversampling_rates(sensor1, osr_1x, osr_1x, osr_1x);
|
||||
bme680_set_oversampling_rates(sensor2, osr_16x, osr_16x, osr_16x);
|
||||
bme680_set_oversampling_rates(sensor1, osr_4x, osr_2x, osr_1x);
|
||||
bme680_set_oversampling_rates(sensor2, osr_8x, osr_8x, osr_8x);
|
||||
|
||||
// Change the IIR filter size (default iir_size_3) for temperature and
|
||||
// and pressure to 7.
|
||||
// Change the IIR filter size for temperature and and pressure to 7.
|
||||
bme680_set_filter_size(sensor1, iir_size_7);
|
||||
bme680_set_filter_size(sensor2, iir_size_7);
|
||||
|
||||
// Change the heaeter profile (default 20 degree Celcius for 150 ms) to
|
||||
// 200 degree Celcius for 100 ms.
|
||||
bme680_set_heater_profile (sensor1, 200, 100);
|
||||
bme680_set_heater_profile (sensor2, 200, 100);
|
||||
// Change the heater profile 0 to 200 degree Celcius for 150 ms.
|
||||
bme680_set_heater_profile (sensor1, 0, 200, 150);
|
||||
bme680_set_heater_profile (sensor2, 0, 200, 150);
|
||||
|
||||
// Activate the heater profile 0
|
||||
bme680_use_heater_profile (sensor1, 0);
|
||||
bme680_use_heater_profile (sensor2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,96 +1,255 @@
|
|||
# Driver for **BME680** digital **environmental sensor**
|
||||
|
||||
This driver is written for usage with the ESP8266 and FreeRTOS. It supports multiple sensors that are either connected to the SPI or to different I2C interfaces with different addresses.
|
||||
This driver is written for usage with the ESP8266 and FreeRTOS. It supports multiple BME680 sensors which are either connected to the SPI or to different I2C interfaces with different addresses.
|
||||
|
||||
## About the sensor
|
||||
|
||||
BME680 is an ulta-low-power environmental sensor that integrates temperature, pressure, humidity and gas sensors in only one unit.
|
||||
BME680 is an ultra-low-power environmental sensor that integrates temperature, pressure, humidity and gas sensors in only one unit.
|
||||
|
||||
## Communication interfaces
|
||||
|
||||
The BME680 sensor can be connected using I2C or SPI. The driver supports both communication interfaces.
|
||||
The BME680 sensor can be connected using I2C or SPI.
|
||||
|
||||
The I2C interface supports data rates up to 3.4 Mbps. It is possible to connect multiple BME680 sensors with different I2C slave addresses to the same I2C bus or to different I2C buses. Possible I2C slave addresses are 0x76 and 0x77.
|
||||
|
||||
The SPI interface allows clock rates up to 10 MHz and the SPI modes '00' (CPOL=CPHA=0) and '11' (CPOL=CPHA=1).
|
||||
|
||||
Interface selection is done automatically using the SPI CS signal. As long as the CS signal keeps high after power-on reset, the I2C interface is used. Once the CS signal has been pulled down, SPI interface is used until next power-on reset.
|
||||
Interface selection is done automatically by the sensor using the SPI CS signal. As long as the CS signal keeps high after power-on reset, the I2C interface is used. Once the CS signal has been pulled down, SPI interface is used until next power-on reset.
|
||||
|
||||
## Measurement process
|
||||
|
||||
Once the BME680 has been initialized, it can be used for measurements. The BME680 operates in two different low-level power modes, the **sleep mode** and the **forced mode**.
|
||||
Once the BME680 has been initialized, it can be used for measurements. The BME680 operates in two different modes, the **sleep mode** and the **forced mode**.
|
||||
|
||||
The *sleep mode* is the default mode. The sensor starts automatically in this mode after power-up sequence. It does not perform any measurement in this mode and therefore just consumes 0.15 μA.
|
||||
The sensor starts after power-up automatically in the *sleep mode* where it does not perform any measurement and consumes only 0.15 μA. Measurements are only done in *forced mode*.
|
||||
|
||||
**Please note:** There are two further undocumented modes, the *parallel* and the *sequential* mode. They can't be supported by the driver, since it is not clear what they do and how to use them.
|
||||
|
||||
#### Measurement cylce
|
||||
|
||||
To perform measurements, the BME680 sensor has to be triggered to switch to the **forced mode**. In this mode, it performs exactly one measurement of temperature, pressure, humidity, and gas in that order, the so-called **TPHG measurement cycle**. After the execution of this TPHG measurement cylce, the **raw sensor data** become available and the sensor returns automatically back to sleep mode.
|
||||
To perform measurements, the BME680 sensor has to be triggered to switch to the **forced mode**. In this mode, it performs exactly one measurement of temperature, pressure, humidity, and gas in that order, the so-called **TPHG measurement cycle**. After the execution of this TPHG measurement cycle, **raw sensor data** become available and the sensor returns automatically back to sleep mode.
|
||||
|
||||
Each of the individual measurements can be configured or skipped separately via the sensor settings, see section **Measurement settings**. Dependent on the configuration, the **duration of a TPHG measurement cycle** can vary from some milliseconds up to about 4.5 seconds, escpecially if gas measurement is enabled.
|
||||
Each of the individual measurements can be configured or skipped separately via the sensor settings, see section **Measurement settings**. Dependent on the configuration, the **duration of a TPHG measurement cycle** can vary from some milliseconds up to about 4.5 seconds, especially if gas measurement is enabled.
|
||||
|
||||
Therefore, the measurement process is separated into the following steps:
|
||||
To avoid the blocking of the user task during measurements, the measurement process is therefore separated into the following steps:
|
||||
|
||||
1. Trigger the sensor with function **_bme680_force_measurement_** to switch to *forced mode* in which it performs exactly one THPG measurement cycle.
|
||||
1. Trigger the sensor with function ```bme680_force_measurement``` to switch to *forced mode* in which it performs exactly one THPG measurement cycle.
|
||||
|
||||
2. Wait the measurement duration using either passive waiting with function **_vTaskDelay_** or busy waiting with function **_bme680_is_measuring_** until the results are available.
|
||||
2. Wait the measurement duration using function ```vTaskDelay``` and the value returned from function ```bme680_get_measurement_duration``` or wait as long as function ```bme680_is_measuring``` returns true.
|
||||
|
||||
3. Fetch the results as fixed point values with function **_bme680_get_results_fixed_** or as floating point values with function **_bme680_get_results_float_**.
|
||||
3. Fetch the results as fixed point values with function ```bme680_get_results_fixed``` or as floating point values with function ```bme680_get_results_float```.
|
||||
|
||||
For convenience reasons, it is also possible to use either function **_bme680_measure_float_** or function **_bme680_measure_fixed_**, which combine all 3 steps above within a single function. **Please note**, these functions must not be used when the are called from a software timer callback function since the calling task is delayed using function *vTaskDelay*.
|
||||
```
|
||||
...
|
||||
// as long as sensor configuration isn't changed, the duration can be considered as constant
|
||||
uint32_t duration = bme680_get_measurement_duration(sensor);
|
||||
...
|
||||
if (bme680_force_measurement (sensor)) // STEP 1
|
||||
{
|
||||
// STEP 2: passive waiting until measurement results are available
|
||||
vTaskDelay (duration);
|
||||
|
||||
// STEP 3: get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
...
|
||||
}
|
||||
...
|
||||
```
|
||||
Alternatively, busy waiting can be realized using function ```bme680_is_measuring```.
|
||||
```
|
||||
...
|
||||
if (bme680_force_measurement (sensor)) // STEP 1
|
||||
{
|
||||
// STEP 2: busy waiting until measurement results are available
|
||||
while (bme680_is_measuring (sensor)) ;
|
||||
|
||||
// STEP 3: get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
...
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
For convenience, it is also possible to use the high-level functions ```bme680_measure_float``` or ```bme680_measure_fixed```. These functions combine all 3 steps above within a single function and are therefore very easy to use. **Please note** that these functions must not be used when they are called from a software timer callback function since the calling task is delayed using function *vTaskDelay*.
|
||||
|
||||
```
|
||||
...
|
||||
// ONE STEP: measure, wait, get the results and do something with them
|
||||
if (bme680_measure_float (sensor, &values))
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
#### Measurement results
|
||||
|
||||
Once the sensor has finished the measurement, either function **_bme680_get_results_fixed_** or function **_bme680_get_results_float_** can be used to fetch the results. These functions read the raw data from the sensor and converts them into fixed point or floating point sensor values. This conversion process bases in very complex calculations using a large number of calibration parameters.
|
||||
Once the sensor has finished the measurement raw data are available at the sensor. Either function ```bme680_get_results_fixed``` or function ```bme680_get_results_float``` can be used to fetch the results. Both functions read raw data from the sensor and converts them into utilizable fixed point or floating point sensor values.
|
||||
|
||||
**Please note:** Conversion of raw sensor data into the final sensor values is based on very complex calculations that use a large number of calibration parameters. Therefore, the driver does not provide functions that only return the raw sensor data.
|
||||
|
||||
Dependent on sensor value representation, measurement results contain different dimensions:
|
||||
|
||||
| Value | Fixed Point | Floating Point | Conversion
|
||||
| ----- | ----------- | -------------- |-----------
|
||||
| ----------- | ------------- | -------- |-----------
|
||||
| temperature | 1/100 °C | °C | float = fixed / 100
|
||||
| pressure | Pascal | hPascal | float = fixed / 100
|
||||
| humdidity | 1/1000 % | % | float = fixed / 1000
|
||||
| humidity | 1/1000 % | % | float = fixed / 1000
|
||||
| gas_resistance | Ohm | Ohm | float = fixed
|
||||
|
||||
The gas resistance value in Ohm represents the resistance of sensor's gas sensitive layer.
|
||||
|
||||
If the TPHG measurement cycle or fetching the results fails, invalid sensor values are returned:
|
||||
|
||||
| Invalid Value | Fixed Point | Floating Point |
|
||||
| ----------- | ------------- | -------- |
|
||||
| temperature | INT16_MIN | -327.68 |
|
||||
| pressure | 0 | 0.0 |
|
||||
| humidity | 0 | 0.0 |
|
||||
| gas_resistance | 0 | 0.0 |
|
||||
|
||||
|
||||
## Measurement settings
|
||||
|
||||
The sensor allows to change different measurement parameters.
|
||||
The sensor allows to change a lot of measurement parameters.
|
||||
|
||||
#### Oversampling rates
|
||||
|
||||
Using function **_bme680_set_oversampling_rates_**, it is possible to define individual oversampling rates for the measurements of temperature, pressure, and humidity. Possible oversampling rates are 1x (default by the driver) 2x, 4x, 8x and 16x. Using an oversampling rate *osr*, the resolution of raw sensor data can be increased from 16 bit to 16+ld(*osr*) bit.
|
||||
To increase the resolution of raw sensor data, the sensor supports oversampling for temperature, pressure, and humidity measurements. Using function ```bme680_set_oversampling_rates```, individual **oversampling rates** can be defined for these measurements. With an oversampling rate *osr*, the resolution of the according raw sensor data can be increased from 16 bit to 16+ld(*osr*) bit.
|
||||
|
||||
It is also possible to define an oversampling rate of 0. This **deactivates** the corresponding measurement and the output values become invalid.
|
||||
Possible oversampling rates are 1x (default by the driver) 2x, 4x, 8x and 16x. It is also possible to define an oversampling rate of 0. This **deactivates** the corresponding measurement and the output values become invalid.
|
||||
|
||||
```
|
||||
...
|
||||
// Changes the oversampling rate for temperature to 4x and for pressure to 2x. Humidity measurement is skipped.
|
||||
bme680_set_oversampling_rates(sensor, osr_4x, osr_2x, osr_none);
|
||||
...
|
||||
```
|
||||
|
||||
#### IIR Filter
|
||||
|
||||
The sensor integrates an internal IIR filter (low pass filter) to reduce short-term changes in sensor output values caused by external disturbances. It effectively reduces the bandwidth of the sensor output values.
|
||||
The sensor also integrates an internal IIR filter (low pass filter) to reduce short-term changes in sensor output values caused by external disturbances. It effectively reduces the bandwidth of the sensor output values.
|
||||
|
||||
The filter can optionally be used for pressure and temperature data that are subject to many short-term changes. Using the IIR filter, increases the resolution of pressure and temperature data to 20 bit. Humidity and gas inside the sensor does not fluctuate rapidly and does not require such a low pass filtering.
|
||||
The filter can optionally be used for pressure and temperature data that are subject to many short-term changes. With the IIR filter the resolution of pressure and temperature data increases to 20 bit. Humidity and gas inside the sensor does not fluctuate rapidly and does not require such a low pass filtering.
|
||||
|
||||
Using function **_bme680_set_filter_size_**, the user task can change the **size of the filter**. The default size is 3. If the size of the filter becomes 0, the filter is **not used**.
|
||||
Using function ```bme680_set_filter_size```, the user task can change the **size of the filter**. The default size is 3. If the size of the filter becomes 0, the filter is **not used**.
|
||||
|
||||
```
|
||||
...
|
||||
// Change the IIR filter size for temperature and pressure to 7.
|
||||
bme680_set_filter_size(sensor, iir_size_7);
|
||||
...
|
||||
// Don't use IIR filter
|
||||
bme680_set_filter_size(sensor, iir_size_0);
|
||||
...
|
||||
```
|
||||
|
||||
#### Heater profile
|
||||
|
||||
For gas measurement the sensor integrates a heater. The paremeters for this heater are defined by a heater profile. Such a heater profile consists of a temperature setting point (the target temperature) and the heating duration.
|
||||
For the gas measurement, the sensor integrates a heater. Parameters for this heater are defined by **heater profiles**. The sensor supports up to 10 such heater profiles, which are numbered from 0 to 9. Each profile consists of a temperature set-point (the target temperature) and a heating duration. By default, only the heater profile 0 with 320 degree Celsius as target temperature and 150 ms heating duration is defined.
|
||||
|
||||
**Please note:** According to the data sheet, target temperatures between 200 and 400 degrees Celsius are typical and about 20 to 30 ms are necessary for the heater to reach the desired target temperature.
|
||||
|
||||
Even though the sensor supports up to 10 different such profiles at them same time, only one profile is used by the driver for simplicity reasons. The **temperature setting point** and the **heating duration** of this one profile can be defined by the user task using function **_bme680_set_heater_profile_**. Default values used by the driver are 320 degree Celsius as target temperature and 150 ms heating duration.
|
||||
Function ```bme680_set_heater_profile``` can be used to set the parameters for one of the heater profiles 0 ... 9. Once the parameters of a heater profile are defined, the gas measurement can be activated with that heater profile using function ```bme680_use_heater_profile```. If -1 or ```BME680_HEATER_NOT_USED``` is used as heater profile, gas measurement is deactivated completely.
|
||||
|
||||
According to the datasheet, target temperatures between 200 and 400 degrees Celsius are typical and about 20 to 30 ms are necessary for the heater to reach the desired target temperature.
|
||||
```
|
||||
...
|
||||
// Change the heater profile 1 to 300 degree Celsius for 100 ms and activate it
|
||||
bme680_set_heater_profile (sensor, 1, 300, 100);
|
||||
bme680_use_heater_profile (sensor, 1);
|
||||
...
|
||||
// Deactivate gas measurement completely
|
||||
bme680_use_heater_profile (sensor, BME680_HEATER_NOT_USED);
|
||||
...
|
||||
|
||||
If heating duration is 0 ms, the gas measurement **is skipped** and output values become invalid.
|
||||
```
|
||||
|
||||
If several heater profiles have been defined with function ```bme680_set_heater_profile```, a sequence of gas measurements with different heater parameters can be realized by a sequence of activations of different heater profiles for successive TPHG measurements using function ```bme680_use_heater_profile```.
|
||||
|
||||
For example, if there were 5 heater profiles defined with following code during the setup
|
||||
```
|
||||
bme680_set_heater_profile (sensor, 0, 200, 100);
|
||||
bme680_set_heater_profile (sensor, 1, 250, 120);
|
||||
bme680_set_heater_profile (sensor, 2, 300, 140);
|
||||
bme680_set_heater_profile (sensor, 3, 350, 160);
|
||||
bme680_set_heater_profile (sensor, 4, 400, 180);
|
||||
```
|
||||
|
||||
the user task could use them as a sequence like following:
|
||||
|
||||
```
|
||||
...
|
||||
while (1)
|
||||
{
|
||||
switch (count++ % 5)
|
||||
{
|
||||
case 0: bme680_use_heater_profile (sensor, 0); break;
|
||||
case 1: bme680_use_heater_profile (sensor, 1); break;
|
||||
case 2: bme680_use_heater_profile (sensor, 2); break;
|
||||
case 3: bme680_use_heater_profile (sensor, 3); break;
|
||||
case 4: bme680_use_heater_profile (sensor, 4); break;
|
||||
}
|
||||
|
||||
// measurement duration changes in each cycle
|
||||
uint32_t duration = bme680_get_measurement_duration(sensor);
|
||||
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
if (bme680_force_measurement (sensor))
|
||||
{
|
||||
vTaskDelay (duration);
|
||||
|
||||
// get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### Ambient temperature
|
||||
|
||||
The heater resistance calculation algorithm takes into account the ambient temperature of the sensor. Using function ```bme680_set_ambient_temperature```, the ambient temperature either determined from the sensor itself or from another temperature sensor can be set.
|
||||
|
||||
```
|
||||
...
|
||||
bme680_set_ambient_temperature (sensor, ambient);
|
||||
...
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In the latter case, the member **_error_code_** of the sensor device data structure is set which indicates what error happened.
|
||||
Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In the latter case, the member ```error_code``` of the sensor device data structure is set which indicates what error happened.
|
||||
|
||||
There are two different error levels that are ORed into one single *error_code*, errors in the I2C or SPI communication and errors with the BME680 sensor itself. To test for a certain error, you can AND the *error_code* with one of the error masks, **_BME680_INT_ERROR_MASK_** for I2C or SPI errors and **_BME680_DRV_ERROR_MASK_** for other errors and then test for a certain error code.
|
||||
There are two different error levels that are ORed into one single *error_code*, errors in the I2C or SPI communication and errors of the BME680 sensor itself. To test for a certain error, first you can AND the *error_code* with one of the error masks, ```BME680_INT_ERROR_MASK``` for I2C or SPI errors and ```BME680_DRV_ERROR_MASK``` for other errors. Then you can test the result for a certain error code.
|
||||
|
||||
For example, error handling for ```bme680_get_results_float``` could look like:
|
||||
|
||||
```
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
{
|
||||
// no error happened
|
||||
...
|
||||
}
|
||||
else
|
||||
{
|
||||
// error happened
|
||||
|
||||
switch (sensor->error_code & BME680_INT_ERROR_MASK)
|
||||
{
|
||||
case BME680_I2C_BUSY: ...
|
||||
case BME680_I2C_READ_FAILED: ...
|
||||
...
|
||||
}
|
||||
switch (sensor->error_code & BME680_DRV_ERROR_MASK)
|
||||
{
|
||||
case BME680_MEAS_STILL_RUNNING: ...
|
||||
case BME680_NO_NEW_DATA: ...
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
First, the hardware configuration has to be establisch. This can differ dependent on the communication interface used and the number of sensors.
|
||||
First, the hardware configuration has to be established. This can differ dependent on the communication interface and the number of sensors used.
|
||||
|
||||
### Hardware configurations
|
||||
|
||||
|
|
@ -106,7 +265,25 @@ First figure shows the configuration with only one sensor at I2C bus 0.
|
|||
| | +--------+
|
||||
+-------------------------+
|
||||
```
|
||||
Next figure shows a possible configuration with two I2C buses. In that case, the sensors can have same or different I2C slave adresses.
|
||||
|
||||
Next figure shows the configuration with only one sensor at SPI bus using GPIO2 as CS signal.
|
||||
|
||||
```
|
||||
+-------------------------+ +--------+
|
||||
| Bus 1 | | BME680 |
|
||||
| GPIO 12 (MISO) <------ SDO |
|
||||
| GPIO 13 (MOSI) >-----> SDI |
|
||||
| GPIO 14 (SCK) >-----> SCK |
|
||||
| GPIO 2 (CS) >-----> CS |
|
||||
+-------------------------+ +--------+
|
||||
```
|
||||
|
||||
**Please note:**
|
||||
|
||||
1. Since the system flash memory is connected to SPI bus 0, the sensor has to be connected to SPI bus 1.
|
||||
|
||||
2. GPIO15 which is used as CS signal of SPI bus 1 does not work correctly together with the BME680. Therefore, the user has to specify another GPIO pin as CS signal, e.g., GPIO2.
|
||||
Next figure shows a possible configuration with two I2C buses. In that case, the sensors can have same or different I2C slave addresses.
|
||||
|
||||
```
|
||||
+-------------------------+ +----------+
|
||||
|
|
@ -134,11 +311,6 @@ Last figure shows a possible configuration using I2C bus 0 and SPI bus 1 at the
|
|||
| GPIO 2 (CS) >-----> CS |
|
||||
+-------------------------+ +----------+
|
||||
```
|
||||
**Please note:**
|
||||
|
||||
1. Since the system flash memory is connected to SPI bus 0, the sensor has to be connected to SPI bus 1.
|
||||
|
||||
2. GPIO15 used as CS signal of SPI bus 1 by default, does not work correctly together with BME680. Therefore, the user has to specify another GPIO pin as CS signal when the sensor is initialized, e.g., GPIO2.
|
||||
|
||||
Further configurations are possible, e.g., two sensors that are connected at the same I2C bus with different slave addresses.
|
||||
|
||||
|
|
@ -168,9 +340,11 @@ If I2C interfaces are used, they have to be initialized first.
|
|||
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K))
|
||||
```
|
||||
|
||||
Once I2C interfaces are initialized, function **_bme680_init_sensor_** has to be called for each BME680 sensor to initialize the sensor and to check its availability as well as its error state. This function returns a pointer to the sensor device data structure or NULL in case of error.
|
||||
SPI interface has not to be initialized explicitly.
|
||||
|
||||
The parameters *bus* specifies the ID of the I2C or SPI bus to which the sensor is connected.
|
||||
Once the I2C interfaces are initialized, function ```bme680_init_sensor``` has to be called for each BME680 sensor in order to initialize the sensor and to check its availability as well as its error state. This function returns a pointer to a sensor device data structure or NULL in case of error.
|
||||
|
||||
The parameter *bus* specifies the ID of the I2C or SPI bus to which the sensor is connected.
|
||||
|
||||
```
|
||||
static bme680_sensor_t* sensor;
|
||||
|
|
@ -192,24 +366,27 @@ sensor = bme680_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
|
|||
|
||||
The remaining part of the program is independent on the communication interface.
|
||||
|
||||
Optionally, you could wish to set some measurement parameters. For details see the section **Measurement settings** above, the header file of the driver **bme680.h**, and of course the datasheet of the sensor.
|
||||
Optionally, you could wish to set some measurement parameters. For details see the section **Measurement settings** above, the header file of the driver ```bme680.h```, and of course the data sheet of the sensor.
|
||||
|
||||
```
|
||||
if (sensor)
|
||||
{
|
||||
// Changes the oversampling rates (default os_1x) to 4x oversampling
|
||||
// for temperature and 2x oversampling for humidity. Pressure
|
||||
// measurement is skipped in this example.
|
||||
// Create a task that uses the sensor
|
||||
xTaskCreate(user_task, "user_task", 256, NULL, 2, NULL);
|
||||
|
||||
/** -- OPTIONAL PART -- */
|
||||
|
||||
// Changes the oversampling rates to 4x oversampling for temperature
|
||||
// and 2x oversampling for humidity. Pressure measurement is skipped.
|
||||
bme680_set_oversampling_rates(sensor, osr_4x, osr_none, osr_2x);
|
||||
|
||||
// Change the IIR filter size (default iir_size_3) for temperature and
|
||||
// and pressure to 7.
|
||||
// Change the IIR filter size for temperature and pressure to 7.
|
||||
bme680_set_filter_size(sensor, iir_size_7);
|
||||
|
||||
// Change the heaeter profile (default 320 degree Celcius for 150 ms)
|
||||
// to 200 degree Celcius for 100 ms.
|
||||
bme680_set_heater_profile (sensor, 320, 150);
|
||||
|
||||
// Change the heater profile 0 to 200 degree Celsius for 100 ms.
|
||||
bme680_set_heater_profile (sensor, 0, 200, 100);
|
||||
bme680_use_heater_profile (sensor, 0);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
|
@ -219,7 +396,7 @@ Last, the user task that uses the sensor has to be created.
|
|||
|
||||
### User task
|
||||
|
||||
BME680 supports only the *forced mode* that performs exactly one measuerement. Therefore, the measurement has to be triggered in each cycle. The waiting for measurement results is also required in each cylce, before the results can be fetched.
|
||||
BME680 supports only the *forced mode* that performs exactly one measurement. Therefore, the measurement has to be triggered in each cycle. The waiting for measurement results is also required in each cycle, before the results can be fetched.
|
||||
|
||||
Thus the user task could look like the following:
|
||||
|
||||
|
|
@ -228,20 +405,22 @@ Thus the user task could look like the following:
|
|||
void user_task(void *pvParameters)
|
||||
{
|
||||
bme680_values_float_t values;
|
||||
int32_t duration;
|
||||
|
||||
TickType_t last_wakeup = xTaskGetTickCount();
|
||||
|
||||
// as long as sensor configuration isn't changed, duration is constant
|
||||
uint32_t duration = bme680_get_measurement_duration(sensor);
|
||||
|
||||
while (1)
|
||||
{
|
||||
{
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
duration = bme680_force_measurement (sensor);
|
||||
bme680_force_measurement (sensor);
|
||||
|
||||
// passive waiting until measurement results are available
|
||||
if (duration > 0) vTaskDelay (duration);
|
||||
vTaskDelay (duration);
|
||||
|
||||
// busy waiting until measurement results are available
|
||||
// while (bme680_is_measuring (sensor) > 0) ;
|
||||
// alternatively: busy waiting until measurement results are available
|
||||
// while (bme680_is_measuring (sensor)) ;
|
||||
|
||||
// get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
|
|
@ -256,38 +435,13 @@ void user_task(void *pvParameters)
|
|||
}
|
||||
```
|
||||
|
||||
Function **_bme680_force_measurement_** is called inside the task loop to start exactly one measurement in each cycle. It returns the estimated duration of the measurement dependent on the measurement settings. The task is then delayed by this duration using function **_vTaskDelay_** to wait passively before the results are fetched with function **_bme680_get_results_float**. The busy waiting alternative is shown in comments.
|
||||
Function ```bme680_force_measurement``` is called inside the task loop to perform exactly one measurement in each cycle.
|
||||
|
||||
### Error Handling
|
||||
The task is then delayed using function ```vTaskDelay``` and the value returned from function ```bme680_get_measurement_duration``` or as long as function ```bme680_is_measuring``` returns true.
|
||||
|
||||
The code could be extended by an error handling. In the event of an error, most driver functions set member **_error_code_** of the sensor device data structure. This indicates which error has occurred. Error codes are a combination of I2C and SPI communication error codes as well as BME680 sensor error codes. To test a particular error, the *error code* can be AND with one of the error masks **_BME680_INT_ERROR_MASK_** or **_BME680_DRV_ERROR_MASK_**.
|
||||
Since the measurement duration only depends on the current sensor configuration, it changes only when sensor configuration is changed. Therefore, it can be considered as constant as long as the sensor configuration isn't changed and can be determined with function ```bme680_get_measurement_duration``` outside the task loop. If the sensor configuration changes, the function has to be executed again.
|
||||
|
||||
For example, error handling for **_bme680_get_results_** could look like:
|
||||
```
|
||||
|
||||
if (bme680_get_results (sensor, &values))
|
||||
{
|
||||
// no error happened
|
||||
...
|
||||
}
|
||||
else
|
||||
{
|
||||
// error happened
|
||||
|
||||
switch (sensor->error_code & BME680_INT_ERROR_MASK)
|
||||
{
|
||||
case BME680_I2C_BUSY: ...
|
||||
case BME680_I2C_READ_FAILED: ...
|
||||
...
|
||||
}
|
||||
switch (sensor->error_code & BME680_DRV_ERROR_MASK)
|
||||
{
|
||||
case BME680_MEAS_NOT_RUNNING: ...
|
||||
case BME680_NO_NEW_DATA: ...
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
Once the measurement results are available, they can be fetched as fixed point oder floating point sensor values using function ```bme680_get_results_float``` and ```bme680_get_results_fixed```, respectively.
|
||||
|
||||
## Full Example
|
||||
|
||||
|
|
@ -298,6 +452,9 @@ else
|
|||
#include "espressif/esp_common.h"
|
||||
#include "esp/uart.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
// include communication interface driver
|
||||
#include "esp/spi.h"
|
||||
#include "i2c/i2c.h"
|
||||
|
|
@ -320,26 +477,28 @@ static bme680_sensor_t* sensor;
|
|||
|
||||
/*
|
||||
* User task that triggers measurements of sensor every seconds. It uses
|
||||
* function *vTaskDelay* to wait for measurement results. Busy wating
|
||||
* function *vTaskDelay* to wait for measurement results. Busy waiting
|
||||
* alternative is shown in comments
|
||||
*/
|
||||
void user_task(void *pvParameters)
|
||||
{
|
||||
bme680_values_float_t values;
|
||||
int32_t duration;
|
||||
|
||||
TickType_t last_wakeup = xTaskGetTickCount();
|
||||
|
||||
// as long as sensor configuration isn't changed, duration is constant
|
||||
uint32_t duration = bme680_get_measurement_duration(sensor);
|
||||
|
||||
while (1)
|
||||
{
|
||||
{
|
||||
// trigger the sensor to start one TPHG measurement cycle
|
||||
duration = bme680_force_measurement (sensor);
|
||||
bme680_force_measurement (sensor);
|
||||
|
||||
// passive waiting until measurement results are available
|
||||
if (duration > 0) vTaskDelay (duration);
|
||||
vTaskDelay (duration);
|
||||
|
||||
// busy waiting until measurement results are available
|
||||
// while (bme680_is_measuring (sensor) > 0) ;
|
||||
// alternatively: busy waiting until measurement results are available
|
||||
// while (bme680_is_measuring (sensor)) ;
|
||||
|
||||
// get the results and do something with them
|
||||
if (bme680_get_results_float (sensor, &values))
|
||||
|
|
@ -363,7 +522,6 @@ void user_init(void)
|
|||
|
||||
/** -- MANDATORY PART -- */
|
||||
|
||||
|
||||
#ifdef SPI_USED
|
||||
// Init the sensor connected either to SPI.
|
||||
sensor = bme680_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
|
||||
|
|
@ -382,24 +540,17 @@ void user_init(void)
|
|||
|
||||
/** -- OPTIONAL PART -- */
|
||||
|
||||
// Changes the oversampling rates (default os_1x) to 4x oversampling
|
||||
// for temperature and 2x oversampling for humidity. Pressure
|
||||
// measurement is skipped in this example.
|
||||
// Changes the oversampling rates to 4x oversampling for temperature
|
||||
// and 2x oversampling for humidity. Pressure measurement is skipped.
|
||||
bme680_set_oversampling_rates(sensor, osr_4x, osr_none, osr_2x);
|
||||
|
||||
// Change the IIR filter size (default iir_size_3) for temperature and
|
||||
// and pressure to 7.
|
||||
// Change the IIR filter size for temperature and pressure to 7.
|
||||
bme680_set_filter_size(sensor, iir_size_7);
|
||||
|
||||
// Change the heaeter profile (default 320 degree Celcius for 150 ms)
|
||||
// to 200 degree Celcius for 100 ms.
|
||||
bme680_set_heater_profile (sensor, 320, 150);
|
||||
// Change the heater profile 0 to 200 degree Celcius for 100 ms.
|
||||
bme680_set_heater_profile (sensor, 0, 200, 100);
|
||||
bme680_use_heater_profile (sensor, 0);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Further Examples
|
||||
|
||||
For further examples see [examples directory](../../examples/bme680/README.md)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* The BSD License (3-clause license)
|
||||
*
|
||||
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht]
|
||||
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -74,21 +74,17 @@
|
|||
#define error_dev(s, f, d, ...)
|
||||
#endif
|
||||
|
||||
// modes: unfortunatly, only SLEEP_MODE and FORCED_MODE are documented
|
||||
#define BME680_SLEEP_MODE 0x00 // low power sleeping
|
||||
#define BME680_FORCED_MODE 0x01 // perform one TPHG cycle (field data 0 filled)
|
||||
#define BME680_PARALLEL_MODE 0x02 // no information what it does :-(
|
||||
#define BME680_SQUENTUAL_MODE 0x02 // no information what it does (field data 0+1+2 filled)
|
||||
|
||||
// register addresses
|
||||
#define BME680_REG_RES_HEAT_VAL 0x00
|
||||
#define BME680_REG_RES_HEAT_RANGE 0x02
|
||||
#define BME680_REG_RANGE_SW_ERROR 0x06
|
||||
#define BME680_REG_MEAS_STATUS_0 0x1d
|
||||
#define BME680_REG_PRESS_MSB 0x1F
|
||||
#define BME680_REG_PRESS_LSB 0x20
|
||||
#define BME680_REG_PRESS_XLSB 0x21
|
||||
#define BME680_REG_TEMP_MSB 0x22
|
||||
#define BME680_REG_TEMP_LSB 0x23
|
||||
#define BME680_REG_TEMP_XLSB 0x24
|
||||
#define BME680_REG_HUM_MSB 0x25
|
||||
#define BME680_REG_HUM_LSB 0x26
|
||||
#define BME680_REG_GAS_R_MSB 0x2a
|
||||
#define BME680_REG_GAS_R_LSB 0x2b
|
||||
|
||||
#define BME680_REG_IDAC_HEAT_BASE 0x50 // 10 regsrs idac_heat_0 ... idac_heat_9
|
||||
#define BME680_REG_RES_HEAT_BASE 0x5a // 10 registers res_heat_0 ... res_heat_9
|
||||
#define BME680_REG_GAS_WAIT_BASE 0x64 // 10 registers gas_wait_0 ... gas_wait_9
|
||||
|
|
@ -101,9 +97,33 @@
|
|||
#define BME680_REG_ID 0xd0
|
||||
#define BME680_REG_RESET 0xe0
|
||||
|
||||
// field data registers 0x1f ... 0x2b
|
||||
#define BME680_REG_RAW_DATA BME680_REG_PRESS_MSB
|
||||
#define BME680_REG_RAW_DATA_LEN (BME680_REG_GAS_R_LSB - BME680_REG_PRESS_MSB + 1)
|
||||
// field data 0 registers
|
||||
#define BME680_REG_MEAS_STATUS_0 0x1d
|
||||
#define BME680_REG_MEAS_INDEX_0 0x1e
|
||||
#define BME680_REG_PRESS_MSB_0 0x1f
|
||||
#define BME680_REG_PRESS_LSB_0 0x20
|
||||
#define BME680_REG_PRESS_XLSB_0 0x21
|
||||
#define BME680_REG_TEMP_MSB_0 0x22
|
||||
#define BME680_REG_TEMP_LSB_0 0x23
|
||||
#define BME680_REG_TEMP_XLSB_0 0x24
|
||||
#define BME680_REG_HUM_MSB_0 0x25
|
||||
#define BME680_REG_HUM_LSB_0 0x26
|
||||
#define BME680_REG_GAS_R_MSB_0 0x2a
|
||||
#define BME680_REG_GAS_R_LSB_0 0x2b
|
||||
|
||||
// field data 1 registers (not documented, used in SEQUENTIAL_MODE)
|
||||
#define BME680_REG_MEAS_STATUS_1 0x2e
|
||||
#define BME680_REG_MEAS_INDEX_1 0x2f
|
||||
|
||||
// field data 2 registers (not documented, used in SEQUENTIAL_MODE)
|
||||
#define BME680_REG_MEAS_STATUS_2 0x3f
|
||||
#define BME680_REG_MEAS_INDEX_2 0x40
|
||||
|
||||
// field data addresses
|
||||
#define BME680_REG_RAW_DATA_0 BME680_REG_MEAS_STATUS_0 // 0x1d ... 0x2b
|
||||
#define BME680_REG_RAW_DATA_1 BME680_REG_MEAS_STATUS_1 // 0x2e ... 0x3c
|
||||
#define BME680_REG_RAW_DATA_2 BME680_REG_MEAS_STATUS_2 // 0x40 ... 0x4d
|
||||
#define BME680_REG_RAW_DATA_LEN (BME680_REG_GAS_R_LSB_0 - BME680_REG_MEAS_STATUS_0 + 1)
|
||||
|
||||
// calibration data registers
|
||||
#define BME680_REG_CD1_ADDR 0x89 // 25 byte calibration data
|
||||
|
|
@ -114,8 +134,8 @@
|
|||
#define BME680_REG_CD3_LEN 8
|
||||
|
||||
// register structure definitions
|
||||
#define BME680_NEW_DATA_0_BITS 0x80 // BME680_REG_MEAS_STATUS<7>
|
||||
#define BME680_NEW_DATA_0_SHIFT 7 // BME680_REG_MEAS_STATUS<7>
|
||||
#define BME680_NEW_DATA_BITS 0x80 // BME680_REG_MEAS_STATUS<7>
|
||||
#define BME680_NEW_DATA_SHIFT 7 // BME680_REG_MEAS_STATUS<7>
|
||||
#define BME680_GAS_MEASURING_BITS 0x40 // BME680_REG_MEAS_STATUS<6>
|
||||
#define BME680_GAS_MEASURING_SHIFT 6 // BME680_REG_MEAS_STATUS<6>
|
||||
#define BME680_MEASURING_BITS 0x20 // BME680_REG_MEAS_STATUS<5>
|
||||
|
|
@ -166,10 +186,7 @@
|
|||
#define BME680_GAS_WAIT_MULT_SHIFT 6 // BME680_REG_GAS_WAIT+x<7:6>
|
||||
|
||||
// commands
|
||||
#define BME680_SLEEP_MODE 0x00 // BME680_REG_CTRL_MEAS<1:0>
|
||||
#define BME680_FORCED_MODE 0x01 // BME680_REG_CTRL_MEAS<1:0>
|
||||
#define BME680_RESET_CMD 0xb6 // BME680_REG_RESET<7:0>
|
||||
|
||||
#define BME680_RESET_PERIOD 5 // reset time in ms
|
||||
|
||||
#define BME680_RHR_BITS 0x30 // BME680_REG_RES_HEAT_RANGE<5:4>
|
||||
|
|
@ -220,7 +237,6 @@
|
|||
*/
|
||||
typedef struct {
|
||||
|
||||
bool new_data; // indicate that read raw data were new in sensor
|
||||
bool gas_valid; // indicate that gas measurement results are valid
|
||||
bool heater_stable; // indicate that heater temperature was stable
|
||||
|
||||
|
|
@ -229,6 +245,10 @@ typedef struct {
|
|||
uint16_t humidity; // relative humidity x1000 in %
|
||||
uint16_t gas_resistance; // gas resistance data
|
||||
uint8_t gas_range; // gas resistance range
|
||||
|
||||
uint8_t gas_index; // heater profile used (0 ... 9)
|
||||
uint8_t meas_index;
|
||||
|
||||
|
||||
} bme680_raw_data_t;
|
||||
|
||||
|
|
@ -244,7 +264,6 @@ static uint32_t bme680_convert_gas (bme680_sensor_t *dev, uint16_t raw_gas, uint
|
|||
|
||||
static uint8_t bme680_heater_resistance (const bme680_sensor_t* dev, uint16_t temperature);
|
||||
static uint8_t bme680_heater_duration (uint16_t duration);
|
||||
static int32_t bme680_measurement_duration (const bme680_sensor_t* dev);
|
||||
|
||||
static bool bme680_reset (bme680_sensor_t* dev);
|
||||
static bool bme680_is_available (bme680_sensor_t* dev);
|
||||
|
|
@ -270,18 +289,19 @@ bme680_sensor_t* bme680_init_sensor(uint8_t bus, uint8_t addr, uint8_t cs)
|
|||
return NULL;
|
||||
|
||||
// init sensor data structure
|
||||
dev->active = false;
|
||||
dev->bus = bus;
|
||||
dev->addr = addr;
|
||||
dev->spi_cs_pin = cs;
|
||||
dev->meas_started = false;
|
||||
dev->meas_status = 0;
|
||||
dev->settings.ambient_temperature = 0;
|
||||
dev->settings.osr_temperature = osr_none;
|
||||
dev->settings.osr_pressure = osr_none;
|
||||
dev->settings.osr_humidity = osr_none;
|
||||
dev->settings.filter_size = iir_size_0;
|
||||
dev->settings.heater_temperature = 0;
|
||||
dev->settings.heater_duration = 0;
|
||||
dev->settings.ambient_temperature = 0;
|
||||
dev->settings.heater_profile = BME680_HEATER_NOT_USED;
|
||||
memset(dev->settings.heater_temperature, 0, sizeof(uint16_t)*10);
|
||||
memset(dev->settings.heater_duration, 0, sizeof(uint16_t)*10);
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
|
|
@ -306,8 +326,6 @@ bme680_sensor_t* bme680_init_sensor(uint8_t bus, uint8_t addr, uint8_t cs)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
dev->active = true;
|
||||
|
||||
uint8_t buf[BME680_CDM_SIZE];
|
||||
|
||||
// read all calibration parameters from sensor
|
||||
|
|
@ -376,19 +394,27 @@ bme680_sensor_t* bme680_init_sensor(uint8_t bus, uint8_t addr, uint8_t cs)
|
|||
// Set ambient temperature of sensor to default value (25 degree C)
|
||||
dev->settings.ambient_temperature = 25;
|
||||
|
||||
// Set heater default profile 320 degree Celcius for 150 ms
|
||||
if (!bme680_set_heater_profile (dev, 320, 150))
|
||||
// Set heater default profile 0 to 320 degree Celcius for 150 ms
|
||||
if (!bme680_set_heater_profile (dev, 0, 320, 150))
|
||||
{
|
||||
error_dev ("Could not configure default sensor settings for TPH.", __FUNCTION__, dev);
|
||||
error_dev ("Could not configure default heater profile settings.", __FUNCTION__, dev);
|
||||
free (dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!bme680_use_heater_profile (dev, 0))
|
||||
{
|
||||
error_dev ("Could not configure default heater profile.", __FUNCTION__, dev);
|
||||
free (dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
int32_t bme680_force_measurement (bme680_sensor_t* dev)
|
||||
bool bme680_force_measurement (bme680_sensor_t* dev)
|
||||
{
|
||||
if (!dev || !dev->active) return BME680_NOK;
|
||||
if (!dev) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
|
|
@ -397,7 +423,7 @@ int32_t bme680_force_measurement (bme680_sensor_t* dev)
|
|||
{
|
||||
debug_dev ("Measurement is already running.", __FUNCTION__, dev);
|
||||
dev->error_code |= BME680_MEAS_ALREADY_RUNNING;
|
||||
return bme680_is_measuring (dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the power mode to forced mode to trigger one TPHG measurement cycle
|
||||
|
|
@ -405,48 +431,99 @@ int32_t bme680_force_measurement (bme680_sensor_t* dev)
|
|||
{
|
||||
error_dev ("Could not set forced mode to start TPHG measurement cycle.", __FUNCTION__, dev);
|
||||
dev->error_code |= BME680_FORCE_MODE_FAILED;
|
||||
return BME680_NOK;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the total measurement duration to sleep or wait till the measurement is complete */
|
||||
int32_t meas_period = bme680_measurement_duration (dev);
|
||||
|
||||
if (meas_period < 0)
|
||||
return BME680_NOK;
|
||||
|
||||
dev->meas_duration = meas_period;
|
||||
dev->meas_started = true;
|
||||
dev->meas_start_tick = xTaskGetTickCount (); // system time in RTOS ticks
|
||||
dev->meas_status = 0;
|
||||
|
||||
debug_dev ("Started measurement at %.3f.", __FUNCTION__, dev,
|
||||
(double)sdk_system_get_time()*1e-3);
|
||||
|
||||
return dev->meas_duration;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// returns 0 when finished, -1 on error, remaining measurement time otherwise
|
||||
int32_t bme680_is_measuring (bme680_sensor_t* dev)
|
||||
/**
|
||||
* @brief Estimate the measuerment duration in ms
|
||||
*
|
||||
* Timing formulas extracted from BME280 datasheet and test in some
|
||||
* experiments. They represent the maximum measurement duration.
|
||||
*
|
||||
* @return estimated measurument duration in RTOS ticks or -1 on error
|
||||
*/
|
||||
uint32_t bme680_get_measurement_duration (const bme680_sensor_t *dev)
|
||||
{
|
||||
if (!dev || !dev->active) return BME680_NOK;
|
||||
if (!dev) return 0;
|
||||
|
||||
int32_t duration = 0; /* Calculate in us */
|
||||
|
||||
// wake up duration from sleep into forced mode
|
||||
duration += 1250;
|
||||
|
||||
// THP cycle duration which consumes 1963 µs for each measurement at maximum
|
||||
if (dev->settings.osr_temperature) duration += (1 << (dev->settings.osr_temperature-1)) * 2300;
|
||||
if (dev->settings.osr_pressure ) duration += (1 << (dev->settings.osr_pressure-1)) * 2300 + 575;
|
||||
if (dev->settings.osr_humidity ) duration += (1 << (dev->settings.osr_humidity-1)) * 2300 + 575;
|
||||
|
||||
// if gas measurement is used
|
||||
if (dev->settings.heater_profile != BME680_HEATER_NOT_USED &&
|
||||
dev->settings.heater_duration[dev->settings.heater_profile] &&
|
||||
dev->settings.heater_temperature[dev->settings.heater_profile])
|
||||
{
|
||||
// gas heating time
|
||||
duration += dev->settings.heater_duration[dev->settings.heater_profile]*1000;
|
||||
// gas measurement duration;
|
||||
duration += 2300 + 575;
|
||||
}
|
||||
|
||||
// round up to next ms (1 us ... 1000 us => 1 ms)
|
||||
duration += 999;
|
||||
duration /= 1000;
|
||||
|
||||
// some ms tolerance
|
||||
duration += 5;
|
||||
|
||||
// ceil to next integer value that is divisible by portTICK_PERIOD_MS and
|
||||
// compute RTOS ticks (1 ... portTICK_PERIOD_MS = 1 tick)
|
||||
duration = (duration + portTICK_PERIOD_MS-1) / portTICK_PERIOD_MS;
|
||||
|
||||
// Since first RTOS tick can be shorter than the half of defined tick period,
|
||||
// the delay caused by vTaskDelay(duration) might be 1 or 2 ms shorter than
|
||||
// computed duration in rare cases. Since the duration is computed for maximum
|
||||
// and not for the typical durations and therefore tends to be too long, this
|
||||
// should not be a problem. Therefore, only one additional tick used.
|
||||
return duration + 1;
|
||||
}
|
||||
|
||||
|
||||
bool bme680_is_measuring (bme680_sensor_t* dev)
|
||||
{
|
||||
if (!dev) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
// if measurement wasn't started, it is of course not measuring
|
||||
if (!dev->meas_started)
|
||||
{
|
||||
error_dev ("Measurement was not started.", __FUNCTION__, dev);
|
||||
dev->error_code |= BME680_MEAS_NOT_RUNNING;
|
||||
return BME680_NOK;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t raw[2];
|
||||
|
||||
// read maesurment status from sensor
|
||||
if (!bme680_read_reg(dev, BME680_REG_MEAS_STATUS_0, raw, 2))
|
||||
{
|
||||
error_dev ("Could not read measurement status from sensor.", __FUNCTION__, dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t elapsed_ticks;
|
||||
|
||||
elapsed_ticks = (xTaskGetTickCount () - dev->meas_start_tick); // in ms
|
||||
|
||||
if (elapsed_ticks >= dev->meas_duration)
|
||||
return 0;
|
||||
else
|
||||
return dev->meas_duration - elapsed_ticks;
|
||||
dev->meas_status = raw[0];
|
||||
|
||||
// test whether measuring bit is set
|
||||
return (dev->meas_status & BME680_MEASURING_BITS);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -464,12 +541,10 @@ bool bme680_get_results_fixed (bme680_sensor_t* dev, bme680_values_fixed_t* resu
|
|||
|
||||
bme680_raw_data_t raw;
|
||||
|
||||
if (!bme680_get_raw_data(dev, &raw) || !raw.new_data)
|
||||
if (!bme680_get_raw_data(dev, &raw))
|
||||
// return invalid values
|
||||
return false;
|
||||
|
||||
dev->meas_started = false;
|
||||
|
||||
// use compensation algorithms to compute sensor values in fixed point format
|
||||
|
||||
if (dev->settings.osr_temperature)
|
||||
|
|
@ -481,9 +556,17 @@ bool bme680_get_results_fixed (bme680_sensor_t* dev, bme680_values_fixed_t* resu
|
|||
if (dev->settings.osr_humidity)
|
||||
results->humidity = bme680_convert_humidity (dev, raw.humidity);
|
||||
|
||||
if (dev->settings.heater_duration)
|
||||
results->gas_resistance = bme680_convert_gas (dev, raw.gas_resistance,
|
||||
raw.gas_range);
|
||||
if (dev->settings.heater_profile != BME680_HEATER_NOT_USED)
|
||||
{
|
||||
// convert gas only if raw data are valid and heater was stable
|
||||
if (raw.gas_valid && raw.heater_stable)
|
||||
results->gas_resistance = bme680_convert_gas (dev, raw.gas_resistance,
|
||||
raw.gas_range);
|
||||
else if (!raw.gas_valid)
|
||||
dev->error_code = BME680_MEAS_GAS_NOT_VALID;
|
||||
else
|
||||
dev->error_code = BME680_HEATER_NOT_STABLE;
|
||||
}
|
||||
|
||||
debug_dev ("Fixed point sensor valus - %d ms: %d/100 C, %d/1000 Percent, %d Pascal, %d Ohm",
|
||||
__FUNCTION__, dev, sdk_system_get_time (),
|
||||
|
|
@ -500,21 +583,15 @@ bool bme680_get_results_float (bme680_sensor_t* dev, bme680_values_float_t* resu
|
|||
{
|
||||
if (!dev || !results) return false;
|
||||
|
||||
// fill data structure with invalid values
|
||||
results->temperature = INT16_MIN / 100.0f;
|
||||
results->pressure = 0;
|
||||
results->humidity = 0;
|
||||
results->gas_resistance = 0;
|
||||
|
||||
bme680_values_fixed_t fixed;
|
||||
|
||||
if (!bme680_get_results_fixed (dev, &fixed))
|
||||
return false;
|
||||
|
||||
results->temperature = dev->settings.osr_temperature ? fixed.temperature / 100.0f : -327.68;
|
||||
results->pressure = dev->settings.osr_pressure ? fixed.pressure / 100.0f : 0.0;
|
||||
results->humidity = dev->settings.osr_humidity ? fixed.humidity / 1000.0f : 0.0;
|
||||
results->gas_resistance = dev->settings.heater_duration ? fixed.gas_resistance : 0.0;
|
||||
results->temperature = fixed.temperature / 100.0f;
|
||||
results->pressure = fixed.pressure / 100.0f;
|
||||
results->humidity = fixed.humidity / 1000.0f;
|
||||
results->gas_resistance = fixed.gas_resistance;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -558,7 +635,7 @@ bool bme680_set_oversampling_rates (bme680_sensor_t* dev,
|
|||
bme680_oversampling_rate_t osp,
|
||||
bme680_oversampling_rate_t osh)
|
||||
{
|
||||
if (!dev || !dev->active) return false;
|
||||
if (!dev) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
|
|
@ -617,7 +694,7 @@ bool bme680_set_oversampling_rates (bme680_sensor_t* dev,
|
|||
|
||||
bool bme680_set_filter_size(bme680_sensor_t* dev, bme680_filter_size_t size)
|
||||
{
|
||||
if (!dev || !dev->active) return false;
|
||||
if (!dev) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
|
|
@ -647,24 +724,31 @@ bool bme680_set_filter_size(bme680_sensor_t* dev, bme680_filter_size_t size)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool bme680_set_heater_profile (bme680_sensor_t* dev, uint16_t temperature, uint16_t duration)
|
||||
bool bme680_set_heater_profile (bme680_sensor_t* dev, uint8_t profile,
|
||||
uint16_t temperature, uint16_t duration)
|
||||
{
|
||||
if (!dev || !dev->active) return false;
|
||||
if (!dev) return false;
|
||||
|
||||
if (profile > BME680_HEATER_PROFILES-1)
|
||||
{
|
||||
error_dev("Wrong heater profile id %d.", __FUNCTION__, dev, profile);
|
||||
dev->error_code = BME680_WRONG_HEAT_PROFILE;
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
bool temperature_changed = dev->settings.heater_temperature != temperature;
|
||||
bool duration_changed = dev->settings.heater_duration != duration;
|
||||
bool temperature_changed = dev->settings.heater_temperature[profile] != temperature;
|
||||
bool duration_changed = dev->settings.heater_duration[profile] != duration;
|
||||
|
||||
if (!temperature_changed && !duration_changed)
|
||||
return true;
|
||||
|
||||
// set external gas sensor configuration
|
||||
dev->settings.heater_temperature = temperature; // degree Celsius
|
||||
dev->settings.heater_duration = duration; // milliseconds
|
||||
dev->settings.heater_temperature[profile] = temperature; // degree Celsius
|
||||
dev->settings.heater_duration [profile] = duration; // milliseconds
|
||||
|
||||
// compute internal gas sensor configuration parameters
|
||||
uint8_t profile = 0; // only profile 0 is supported for the moment
|
||||
uint8_t heat_dur = bme680_heater_duration(duration); // internal duration value
|
||||
uint8_t heat_res = bme680_heater_resistance(dev, temperature); // internal temperature value
|
||||
|
||||
|
|
@ -677,29 +761,51 @@ bool bme680_set_heater_profile (bme680_sensor_t* dev, uint16_t temperature, uint
|
|||
!bme680_write_reg(dev, BME680_REG_GAS_WAIT_BASE+profile, &heat_dur, 1))
|
||||
return false;
|
||||
|
||||
debug_dev ("Setting heater profile done: temperature=%d duration=%d "
|
||||
debug_dev ("Setting heater profile %d done: temperature=%d duration=%d "
|
||||
"heater_resistance=%02x heater_duration=%02x",
|
||||
__FUNCTION__, dev,
|
||||
dev->settings.heater_temperature, dev->settings.heater_duration,
|
||||
__FUNCTION__, dev, profile,
|
||||
dev->settings.heater_temperature[profile],
|
||||
dev->settings.heater_duration[profile],
|
||||
heat_dur, heat_res);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bme680_use_heater_profile (bme680_sensor_t* dev, int8_t profile)
|
||||
{
|
||||
if (!dev) return false;
|
||||
|
||||
if (profile != BME680_HEATER_NOT_USED && (profile < 0 || profile > BME680_HEATER_PROFILES-1))
|
||||
{
|
||||
error_dev("Wrong heater profile id %d.", __FUNCTION__, dev, profile);
|
||||
dev->error_code = BME680_WRONG_HEAT_PROFILE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dev->settings.heater_profile == profile)
|
||||
return false;
|
||||
|
||||
dev->settings.heater_profile = profile;
|
||||
|
||||
uint8_t reg = 0; // set
|
||||
// set active profile
|
||||
reg = bme_set_reg_bit (reg, BME680_NB_CONV, profile);
|
||||
reg = bme_set_reg_bit (reg, BME680_NB_CONV, profile != BME680_HEATER_NOT_USED ? profile : 0);
|
||||
|
||||
// enable or disable gas measurement
|
||||
reg = bme_set_reg_bit (reg, BME680_RUN_GAS, (temperature && duration));
|
||||
reg = bme_set_reg_bit (reg, BME680_RUN_GAS, (profile != BME680_HEATER_NOT_USED &&
|
||||
dev->settings.heater_temperature[profile] &&
|
||||
dev->settings.heater_duration[profile]));
|
||||
|
||||
if (!bme680_write_reg(dev, BME680_REG_CTRL_GAS_1, ®, 1))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool bme680_set_ambient_temperature (bme680_sensor_t* dev, int16_t ambient)
|
||||
{
|
||||
if (!dev || !dev->active) return false;
|
||||
if (!dev) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
|
|
@ -710,38 +816,40 @@ bool bme680_set_ambient_temperature (bme680_sensor_t* dev, int16_t ambient)
|
|||
|
||||
// set ambient temperature configuration
|
||||
dev->settings.ambient_temperature = ambient; // degree Celsius
|
||||
|
||||
// compute internal gas sensor configuration parameters
|
||||
uint8_t profile = 0; // only profile 0 is supported for the moment
|
||||
uint8_t heat_res = bme680_heater_resistance(dev, dev->settings.heater_temperature);
|
||||
|
||||
// set internal gas sensor configuration parameters if changed
|
||||
if (ambient_changed &&
|
||||
!bme680_write_reg(dev, BME680_REG_RES_HEAT_BASE+profile, &heat_res, 1))
|
||||
|
||||
// update all valid heater profiles
|
||||
|
||||
// takes 894 us for only one defined profile and 1585 us for 10 defined profiles
|
||||
uint8_t data[10];
|
||||
for (int i = 0; i < BME680_HEATER_PROFILES; i++)
|
||||
{
|
||||
data[i] = dev->settings.heater_temperature[i] ?
|
||||
bme680_heater_resistance(dev, dev->settings.heater_temperature[i]) : 0;
|
||||
}
|
||||
if (!bme680_write_reg(dev, BME680_REG_RES_HEAT_BASE, data, 10))
|
||||
return false;
|
||||
|
||||
|
||||
/*
|
||||
// takes 346 us for only one defined profile and 3316 us for 10 defined profiles
|
||||
for (int i = 0; i < BME680_HEATER_PROFILES; i++)
|
||||
if (dev->settings.heater_temperature[i])
|
||||
{
|
||||
uint8_t heat_res = bme680_heater_resistance(dev, dev->settings.heater_temperature[i]);
|
||||
if (!bme680_write_reg(dev, BME680_REG_RES_HEAT_BASE+i, &heat_res, 1))
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
debug_dev ("Setting heater ambient temperature done: ambient=%d",
|
||||
__FUNCTION__, dev,
|
||||
dev->settings.ambient_temperature);
|
||||
__FUNCTION__, dev, dev->settings.ambient_temperature);
|
||||
|
||||
uint8_t reg = 0; // reset register value
|
||||
|
||||
// set active profile
|
||||
reg = bme_set_reg_bit (reg, BME680_NB_CONV, profile);
|
||||
|
||||
// enable or disable gas measurement
|
||||
reg = bme_set_reg_bit (reg, BME680_RUN_GAS, dev->settings.heater_temperature &&
|
||||
dev->settings.heater_duration);
|
||||
|
||||
if (!bme680_write_reg(dev, BME680_REG_CTRL_GAS_1, ®, 1))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bme680_set_mode (bme680_sensor_t *dev, uint8_t mode)
|
||||
{
|
||||
if (!dev || !dev->active) return false;
|
||||
if (!dev) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
|
|
@ -973,48 +1081,58 @@ static uint32_t bme680_convert_gas (bme680_sensor_t *dev, uint16_t gas, uint8_t
|
|||
#define msb_lsb_xlsb_to_20bit(t,b,o) (t)((t) b[o] << 12 | (t) b[o+1] << 4 | b[o+2] >> 4)
|
||||
#define msb_lsb_to_type(t,b,o) (t)(((t)b[o] << 8) | b[o+1])
|
||||
|
||||
#define BME680_RAW_P_OFF 0
|
||||
#define BME680_RAW_T_OFF (BME680_REG_TEMP_MSB - BME680_REG_PRESS_MSB)
|
||||
#define BME680_RAW_H_OFF (BME680_REG_HUM_MSB - BME680_REG_PRESS_MSB)
|
||||
#define BME680_RAW_G_OFF (BME680_REG_GAS_R_MSB - BME680_REG_PRESS_MSB)
|
||||
#define BME680_RAW_P_OFF BME680_REG_PRESS_MSB_0-BME680_REG_MEAS_STATUS_0
|
||||
#define BME680_RAW_T_OFF (BME680_RAW_P_OFF + BME680_REG_TEMP_MSB_0 - BME680_REG_PRESS_MSB_0)
|
||||
#define BME680_RAW_H_OFF (BME680_RAW_T_OFF + BME680_REG_HUM_MSB_0 - BME680_REG_TEMP_MSB_0)
|
||||
#define BME680_RAW_G_OFF (BME680_RAW_H_OFF + BME680_REG_GAS_R_MSB_0 - BME680_REG_HUM_MSB_0)
|
||||
|
||||
static bool bme680_get_raw_data(bme680_sensor_t *dev, bme680_raw_data_t* raw_data)
|
||||
{
|
||||
if (!dev || !dev->active || !raw_data) return false;
|
||||
if (!dev || !raw_data) return false;
|
||||
|
||||
dev->error_code = BME680_OK;
|
||||
|
||||
if (!dev->meas_started)
|
||||
{
|
||||
debug_dev ("Measurement was not started.", __FUNCTION__, dev);
|
||||
error_dev ("Measurement was not started.", __FUNCTION__, dev);
|
||||
dev->error_code = BME680_MEAS_NOT_RUNNING;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t raw[BME680_REG_RAW_DATA_LEN] = { 0 };
|
||||
|
||||
raw_data->new_data = false;
|
||||
|
||||
// read maesurment status from sensor
|
||||
if (!bme680_read_reg(dev, BME680_REG_MEAS_STATUS_0, raw, 1))
|
||||
if (!(dev->meas_status & BME680_NEW_DATA_BITS))
|
||||
{
|
||||
error_dev ("Could not read new data status from sensor.", __FUNCTION__, dev);
|
||||
return false;
|
||||
}
|
||||
// read maesurment status from sensor
|
||||
if (!bme680_read_reg(dev, BME680_REG_MEAS_STATUS_0, raw, 2))
|
||||
{
|
||||
error_dev ("Could not read measurement status from sensor.", __FUNCTION__, dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->meas_status = raw[0];
|
||||
if (dev->meas_status & BME680_MEASURING_BITS)
|
||||
{
|
||||
debug_dev ("Measurement is still running.", __FUNCTION__, dev);
|
||||
dev->error_code = BME680_MEAS_STILL_RUNNING;
|
||||
return false;
|
||||
}
|
||||
|
||||
// test whether there are new data
|
||||
if (!(raw_data->new_data = raw[0] & BME680_NEW_DATA_0_BITS))
|
||||
{
|
||||
debug_dev ("No new data.", __FUNCTION__, dev);
|
||||
dev->error_code = BME680_NO_NEW_DATA;
|
||||
return false;
|
||||
// test whether there are new data
|
||||
if (!(dev->meas_status & BME680_NEW_DATA_BITS))
|
||||
{
|
||||
debug_dev ("No new data.", __FUNCTION__, dev);
|
||||
dev->error_code = BME680_NO_NEW_DATA;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// XXXXX improve status check
|
||||
// raw_data->gas_index = raw[0] & BME680_GAS_MEAS_INDEX_BITS >> BME680_GAS_MEAS_INDEX_SHIFT;
|
||||
// raw_data->meas_index = raw[1];
|
||||
dev->meas_started = false;
|
||||
raw_data->gas_index = (dev->meas_status & BME680_GAS_MEAS_INDEX_BITS);
|
||||
|
||||
if (!bme680_read_reg(dev, BME680_REG_RAW_DATA, raw, BME680_REG_RAW_DATA_LEN))
|
||||
// if there are new data, read raw data from sensor
|
||||
|
||||
if (!bme680_read_reg(dev, BME680_REG_RAW_DATA_0, raw, BME680_REG_RAW_DATA_LEN))
|
||||
{
|
||||
error_dev ("Could not read raw data from sensor.", __FUNCTION__, dev);
|
||||
return false;
|
||||
|
|
@ -1023,14 +1141,26 @@ static bool bme680_get_raw_data(bme680_sensor_t *dev, bme680_raw_data_t* raw_dat
|
|||
raw_data->gas_valid = bme_get_reg_bit(raw[BME680_RAW_G_OFF+1],BME680_GAS_VALID);
|
||||
raw_data->heater_stable = bme_get_reg_bit(raw[BME680_RAW_G_OFF+1],BME680_HEAT_STAB_R);
|
||||
|
||||
// if there are new data, read raw data from sensor
|
||||
|
||||
raw_data->temperature = msb_lsb_xlsb_to_20bit (uint32_t, raw, BME680_RAW_T_OFF);
|
||||
raw_data->pressure = msb_lsb_xlsb_to_20bit (uint32_t, raw, BME680_RAW_P_OFF);
|
||||
raw_data->humidity = msb_lsb_to_type (uint16_t, raw, BME680_RAW_H_OFF);
|
||||
raw_data->gas_resistance = ((uint16_t)raw[BME680_RAW_G_OFF] << 2) | raw[BME680_RAW_G_OFF+1] >> 6;
|
||||
raw_data->gas_range = raw[BME680_RAW_G_OFF+1] & BME680_GAS_RANGE_R_BITS;
|
||||
|
||||
/*
|
||||
// These data are not documented and it is not really clear when they are filled
|
||||
if (!bme680_read_reg(dev, BME680_REG_MEAS_STATUS_1, raw, BME680_REG_RAW_DATA_LEN))
|
||||
{
|
||||
error_dev ("Could not read raw data from sensor.", __FUNCTION__, dev);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bme680_read_reg(dev, BME680_REG_MEAS_STATUS_2, raw, BME680_REG_RAW_DATA_LEN))
|
||||
{
|
||||
error_dev ("Could not read raw data from sensor.", __FUNCTION__, dev);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
debug ("Raw data: %d %d %d %d %d",__FUNCTION__,
|
||||
raw_data->temperature, raw_data->pressure,
|
||||
raw_data->humidity, raw_data->gas_resistance, raw_data->gas_range);
|
||||
|
|
@ -1072,7 +1202,7 @@ static uint8_t bme680_heater_duration (uint16_t duration)
|
|||
*/
|
||||
static uint8_t bme680_heater_resistance (const bme680_sensor_t *dev, uint16_t temp)
|
||||
{
|
||||
if (!dev || !dev->active) return 0;
|
||||
if (!dev) return 0;
|
||||
|
||||
if (temp < BME680_HEATER_TEMP_MIN)
|
||||
temp = BME680_HEATER_TEMP_MIN;
|
||||
|
|
@ -1100,55 +1230,6 @@ static uint8_t bme680_heater_resistance (const bme680_sensor_t *dev, uint16_t te
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Estimate the measuerment duration in ms
|
||||
*
|
||||
* Timing formulas extracted from BME280 datasheet and some experiments. They
|
||||
* represent maximum measurement duration.
|
||||
*
|
||||
* @return estimated measurument duration in RTOS ticks or -1 on error
|
||||
*/
|
||||
static int32_t bme680_measurement_duration (const bme680_sensor_t *dev)
|
||||
{
|
||||
if (!dev || !dev->active) return BME680_NOK;
|
||||
|
||||
int32_t duration = 0; /* Calculate in us */
|
||||
|
||||
// wake up duration from sleep into forced mode
|
||||
duration += 1250;
|
||||
|
||||
// THP cycle duration which consumes 1963 µs for each measurement at maximum
|
||||
if (dev->settings.osr_temperature) duration += (1 << (dev->settings.osr_temperature-1)) * 2300;
|
||||
if (dev->settings.osr_pressure ) duration += (1 << (dev->settings.osr_pressure-1)) * 2300 + 575;
|
||||
if (dev->settings.osr_humidity ) duration += (1 << (dev->settings.osr_humidity-1)) * 2300 + 575;
|
||||
|
||||
// if gas measurement is used
|
||||
if (dev->settings.heater_duration && dev->settings.heater_temperature)
|
||||
{
|
||||
// gas heating time
|
||||
duration += dev->settings.heater_duration*1000;
|
||||
// gas measurement duration;
|
||||
duration += 2300 + 575;
|
||||
}
|
||||
|
||||
// round up to next ms (1 us ... 1000 us => 1 ms)
|
||||
duration += 999;
|
||||
duration /= 1000;
|
||||
|
||||
// some ms tolerance
|
||||
duration += 3;
|
||||
|
||||
// ceil to next integer value that is divisible by portTICK_PERIOD_MS and
|
||||
// compute RTOS ticks (1 ... portTICK_PERIOD_MS = 1 tick)
|
||||
duration = (duration + portTICK_PERIOD_MS-1) / portTICK_PERIOD_MS;
|
||||
|
||||
// Since first RTOS tick can be shorter than the half of defined tick period,
|
||||
// the delay caused by vTaskDelay(duration) might be 1 or 2 ms shorter than
|
||||
// computed duration in rare cases. Since the duration is computed for maximum
|
||||
// and not the typical durations and therefore tends to be too long, this should
|
||||
// not be a problem.
|
||||
return duration;
|
||||
}
|
||||
|
||||
static void bme680_delay_ms(uint32_t period)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -71,17 +71,23 @@
|
|||
#define BME680_SPI_SET_PAGE_FAILED 7
|
||||
|
||||
// BME680 driver error codes ORed with error codes for I2C and SPI interfaces
|
||||
#define BME680_RESET_CMD_FAILED (1 << 8)
|
||||
#define BME680_WRONG_CHIP_ID (2 << 8)
|
||||
#define BME680_READ_CALIB_DATA_FAILED (3 << 8)
|
||||
#define BME680_MEAS_ALREADY_RUNNING (4 << 8)
|
||||
#define BME680_MEAS_NOT_RUNNING (5 << 8)
|
||||
#define BME680_FORCE_MODE_FAILED (6 << 8)
|
||||
#define BME680_NO_NEW_DATA (7 << 8)
|
||||
#define BME680_RESET_CMD_FAILED ( 1 << 8)
|
||||
#define BME680_WRONG_CHIP_ID ( 2 << 8)
|
||||
#define BME680_READ_CALIB_DATA_FAILED ( 3 << 8)
|
||||
#define BME680_MEAS_ALREADY_RUNNING ( 4 << 8)
|
||||
#define BME680_MEAS_NOT_RUNNING ( 5 << 8)
|
||||
#define BME680_MEAS_STILL_RUNNING ( 6 << 8)
|
||||
#define BME680_FORCE_MODE_FAILED ( 7 << 8)
|
||||
#define BME680_NO_NEW_DATA ( 8 << 8)
|
||||
#define BME680_WRONG_HEAT_PROFILE ( 9 << 8)
|
||||
#define BME680_MEAS_GAS_NOT_VALID (10 << 8)
|
||||
#define BME680_HEATER_NOT_STABLE (11 << 8)
|
||||
|
||||
// Driver range definitions
|
||||
#define BME680_HEATER_TEMP_MIN 200 // min. 200 degree Celsius
|
||||
#define BME680_HEATER_TEMP_MAX 400 // max. 200 degree Celsius
|
||||
#define BME680_HEATER_TEMP_MIN 200 // min. 200 degree Celsius
|
||||
#define BME680_HEATER_TEMP_MAX 400 // max. 200 degree Celsius
|
||||
#define BME680_HEATER_PROFILES 10 // max. 10 heater profiles 0 ... 9
|
||||
#define BME680_HEATER_NOT_USED -1 // heater not used profile
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
|
@ -114,12 +120,12 @@ extern "C"
|
|||
* @brief Initialize a BME680 sensor
|
||||
*
|
||||
* The function initializes the sensor device data structure, probes the
|
||||
* sensor, soft resets the sensor, and configures the sensor with default
|
||||
* settings:
|
||||
* sensor, soft resets the sensor, and configures the sensor with the
|
||||
* the following default settings:
|
||||
*
|
||||
* - Oversampling rate for temperature, pressure, humidity is osr_1x
|
||||
* - Filter size for pressure and temperature is iir_size 3
|
||||
* - Heater profile for gas is 320 degree Celsius for 150 milliseconds.
|
||||
* - Heater profile 0 with 320 degree C and 150 ms duration
|
||||
*
|
||||
* The sensor can be connected either to an I2C or a SPI bus. In both cases,
|
||||
* the parameter *bus* specifies the ID of the corresponding bus. Please note
|
||||
|
|
@ -144,45 +150,50 @@ bme680_sensor_t* bme680_init_sensor (uint8_t bus, uint8_t addr, uint8_t cs_pin);
|
|||
/**
|
||||
* @brief Force one single TPHG measurement
|
||||
*
|
||||
* The function triggers the sensor to start one THPG measurement cycle in
|
||||
* forced mode, the only measurement mode supported by the BME680. Parameters
|
||||
* for the measurement like oversampling rates, IIR filter sizes and heater
|
||||
* profile can be configured before.
|
||||
* The function triggers the sensor to start one THPG measurement cycle.
|
||||
* Parameters for the measurement like oversampling rates, IIR filter sizes
|
||||
* and heater profile can be configured before.
|
||||
*
|
||||
* On success, the function returns an estimated measurement duration given
|
||||
* in RTOS ticks. This is the time in ticks needed by the sensor before
|
||||
* measurement results become available. The user task has to wait this
|
||||
* duration before it can use function *bme680_get_results_fixed* or
|
||||
* function *bme680_get_results_float* to fetch the measurement results.
|
||||
*
|
||||
* The measurement duration strongly depends on which measurements in the THPG
|
||||
* measurement cycle are performed and which configuration parameters were set.
|
||||
* It can vary from 1 RTOS (10 ms) tick up to 4500 RTOS ticks (4.5 seconds).
|
||||
* Once the TPHG measurement is started, the user task has to wait for the
|
||||
* results. The duration of the TPHG measurement can be determined with
|
||||
* function *bme680_get_measurement_duration*.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
* @return measurement duration given in RTOS ticks or -1 on error
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
int32_t bme680_force_measurement (bme680_sensor_t* dev);
|
||||
bool bme680_force_measurement (bme680_sensor_t* dev);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get remaining duration of a running measurement
|
||||
* @brief Get estimated duration of a TPHG measurement
|
||||
*
|
||||
* The function can be used to test whether a measurement has been started
|
||||
* and how long it still takes before measurement results become
|
||||
* available. The return value is given in RTOS ticks and can be
|
||||
* The function returns an estimated duration of the TPHG measurement cycle
|
||||
* in RTOS ticks for the current configuration of the sensor.
|
||||
*
|
||||
* >0 in case the measurement is is still running,
|
||||
* 0 in case the measurement has been already finished, or
|
||||
* <0 in case of error.
|
||||
* This duration is the time required by the sensor for one TPHG measurement
|
||||
* until the results are available. It strongly depends on which measurements
|
||||
* are performed in the THPG measurement cycle and what configuration
|
||||
* parameters were set. It can vary from 1 RTOS (10 ms) tick up to 4500 RTOS
|
||||
* ticks (4.5 seconds).
|
||||
*
|
||||
* That is, a return value greater than 0 indicates that the measurement
|
||||
* results are still not available and the user task has to wait that time.
|
||||
* If the measurement configuration is not changed, the duration can be
|
||||
* considered as constant.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
* @return duration of TPHG measurement cycle in ticks or 0 on error
|
||||
*/
|
||||
uint32_t bme680_get_measurement_duration (const bme680_sensor_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Get the measurement status
|
||||
*
|
||||
* The function can be used to test whether a measurement that was started
|
||||
* before is still running.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
* @return remaining measurement duration in RTOS ticks or -1 on error
|
||||
* @return true if measurement is still running or false otherwise
|
||||
*/
|
||||
int32_t bme680_is_measuring (bme680_sensor_t* dev);
|
||||
bool bme680_is_measuring (bme680_sensor_t* dev);
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -217,12 +228,12 @@ bool bme680_get_results_float (bme680_sensor_t* dev,
|
|||
* @brief Start a measurement, wait and return the results (fixed point)
|
||||
*
|
||||
* This function is a combination of functions above. For convenience it
|
||||
* starts a TPHG measurement using *bme680_force_measurement*, then waits it
|
||||
* starts a TPHG measurement using *bme680_force_measurement*, then it waits
|
||||
* the measurement duration for the results using *vTaskDelay* and finally it
|
||||
* returns the results using function *bme680_get_results_fixed*.
|
||||
*
|
||||
* Note: Since the calling task is delayed using function *vTaskDelay*, this
|
||||
* function must not be used when it is called by a software timer callback
|
||||
* function must not be used when it is called from a software timer callback
|
||||
* function.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
|
|
@ -242,7 +253,7 @@ bool bme680_measure_fixed (bme680_sensor_t* dev,
|
|||
* returns the results using function *bme680_get_results_float*.
|
||||
*
|
||||
* Note: Since the calling task is delayed using function *vTaskDelay*, this
|
||||
* function must not be used when it is called by a software timer callback
|
||||
* function must not be used when it is called from a software timer callback
|
||||
* function.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
|
|
@ -302,43 +313,65 @@ bool bme680_set_filter_size(bme680_sensor_t* dev, bme680_filter_size_t size);
|
|||
|
||||
|
||||
/**
|
||||
* @brief Set the heater profile for gas measurements
|
||||
* @brief Set a heater profile for gas measurements
|
||||
*
|
||||
* For gas measurement the sensor integrates a heater. The paremeters for
|
||||
* this heater are defined by a heater profile. Such a heater profile
|
||||
* consists of a temperature setting point (the target temperature) and the
|
||||
* heating duration. The target temperature is converted to the heater
|
||||
* resistance value.
|
||||
* The sensor integrates a heater for the gas measurement. Parameters for this
|
||||
* heater are defined by so called heater profiles. The sensor supports up to
|
||||
* 10 heater profiles, which are numbered from 0 to 9. Each profile consists of
|
||||
* a temperature set-point (the target temperature) and a heating duration.
|
||||
*
|
||||
* Even though the sensor supports up to 10 different profiles, only one
|
||||
* profile is used by this driver for simplicity. The temperature setting
|
||||
* point and the heating duration of this profile can be defined by this
|
||||
* function. Default values are 320 degree Celsius as target temperature and
|
||||
* 150 ms heating duration.
|
||||
* This function sets the parameters for one of the heater profiles 0 ... 9.
|
||||
* To activate the gas measurement with this profile, use function
|
||||
* *bme680_use_heater_profile*, see below.
|
||||
*
|
||||
* Please note: To disable the measurement of gas, set the heating duration
|
||||
* to 0 ms.
|
||||
*
|
||||
* Please note: According to the data sheet, target temperatures of between
|
||||
* Please note: According to the data sheet, a target temperatures of between
|
||||
* 200 and 400 degrees Celsius are typical and about 20 to 30 ms are necessary
|
||||
* for the heater to reach the desired target temperature.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
* @param temperature heating temperature in degree Celsius
|
||||
* @param profile heater profile 0 ... 9
|
||||
* @param temperature target temperature in degree Celsius
|
||||
* @param duration heating duration in milliseconds
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool bme680_set_heater_profile (bme680_sensor_t* dev,
|
||||
bool bme680_set_heater_profile (bme680_sensor_t* dev,
|
||||
uint8_t profile,
|
||||
uint16_t temperature,
|
||||
uint16_t duration);
|
||||
|
||||
/**
|
||||
* @brief Activate gas measurement with a given heater profile
|
||||
*
|
||||
* The function activates the gas measurement with one of the heater
|
||||
* profiles 0 ... 9 or deactivates the gas measurement completely when
|
||||
* -1 or BME680_HEATER_NOT_USED is used as heater profile.
|
||||
*
|
||||
* Parameters of the activated heater profile have to be set before with
|
||||
* function *bme680_set_heater_profile* otherwise the function fails.
|
||||
*
|
||||
* If several heater profiles have been defined with function
|
||||
* *bme680_set_heater_profile*, a sequence of gas measurements with different
|
||||
* heater parameters can be realized by a sequence of activations of different
|
||||
* heater profiles for successive TPHG measurements using this function.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure0 *
|
||||
* @param profile 0 ... 9 to activate or -1 to deactivate gas measure
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool bme680_use_heater_profile (bme680_sensor_t* dev, int8_t profile);
|
||||
|
||||
/**
|
||||
* @brief Set ambient temperature
|
||||
*
|
||||
* The heater resistance conversion algorithm takes into account the ambient
|
||||
* The heater resistance calculation algorithm takes into account the ambient
|
||||
* temperature of the sensor. This function can be used to set this ambient
|
||||
* temperature. Either values determined from this or another temperature
|
||||
* sensor can be used. The default ambient temperature is 25 degree Celsius.
|
||||
* temperature. Either values determined from the sensor itself or from
|
||||
* another temperature sensor can be used. The default ambient temperature
|
||||
* is 25 degree Celsius.
|
||||
*
|
||||
* @param dev pointer to the sensor device data structure
|
||||
* @param temperature ambient temperature in degree Celsius
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool bme680_set_ambient_temperature (bme680_sensor_t* dev,
|
||||
int16_t temperature);
|
||||
|
|
|
|||
|
|
@ -108,16 +108,17 @@ typedef enum {
|
|||
*/
|
||||
typedef struct {
|
||||
|
||||
uint8_t osr_temperature; // T oversampling rate (default osr_1x)
|
||||
uint8_t osr_pressure; // P oversampling rate (default osr_1x)
|
||||
uint8_t osr_humidity; // H oversampling rate (default osr_1x)
|
||||
uint8_t filter_size; // IIR filter size (default iir_size_3)
|
||||
uint8_t osr_temperature; // T oversampling rate (default osr_1x)
|
||||
uint8_t osr_pressure; // P oversampling rate (default osr_1x)
|
||||
uint8_t osr_humidity; // H oversampling rate (default osr_1x)
|
||||
uint8_t filter_size; // IIR filter size (default iir_size_3)
|
||||
|
||||
uint16_t heater_temperature; // Heater temperature for G (default 320)
|
||||
uint16_t heater_duration; // Heater duration for G (default 150)
|
||||
int8_t heater_profile; // Heater profile used (default 0)
|
||||
uint16_t heater_temperature[10]; // Heater temperature for G (default 320)
|
||||
uint16_t heater_duration[10]; // Heater duration for G (default 150)
|
||||
|
||||
int8_t ambient_temperature; // Ambient temperature for G (default 25);
|
||||
|
||||
int8_t ambient_temperature; // Ambient temperature for G (default 25)
|
||||
|
||||
} bme680_settings_t;
|
||||
|
||||
/**
|
||||
|
|
@ -168,7 +169,6 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
|
||||
bool active; // indicates whether sensor is active
|
||||
int error_code; // contains the error code of last operation
|
||||
|
||||
uint8_t bus; // I2C = x, SPI = 1
|
||||
|
|
@ -177,8 +177,8 @@ typedef struct {
|
|||
|
||||
bool meas_started; // indicates whether measurement started
|
||||
uint32_t meas_start_tick; // measurement start time in RTOS ticks
|
||||
uint32_t meas_duration; // measurement duration in RTOS ticks
|
||||
|
||||
uint8_t meas_status; // last sensor status (for internal use only)
|
||||
|
||||
bme680_settings_t settings; // sensor settings
|
||||
bme680_calib_data_t calib_data; // calibration data of the sensor
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue