This commit is contained in:
William Clark 2024-08-24 21:28:35 +01:00
commit 72572e2f9a
3 changed files with 85 additions and 225 deletions

View File

@ -28,7 +28,7 @@ The loggers spit out the following every minute:
>Note: disregard measured gas resistance if the heat stability bit is not 1.
## spi demo
## bme680_{i2c,spi} demo output
```
par_t1: 26203
par_t2: 26519
@ -67,48 +67,9 @@ gas resistance: 12100.310308 Ohm
=== heat_stab_r: 1
```
## i2c demo
```
par_t1: 26125
par_t2: 26370
par_t3: 3
par_p1: 36262
par_p2: -10371
par_p3: 88
par_p4: 6713
par_p5: -103
par_p6: 30
par_p7: 31
par_p8: -251
par_p9: -3158
par_p10: 30
par_h1: 776
par_h2: 1010
par_h3: 0
par_h4: 45
par_h5: 20
par_h6: 120
par_h7: -100
par_g1: 183
par_g2: 59281
par_g3: 18
range_switching_error: 19
res_heat_range: 1
res_heat_val: 39
float mode
tfine: 97289.819111
temp: 19.001918 degC
press: 100226.479673 Pa
humidity: 67.022216 % RH
gas resistance: 14702.868852 Ohm
== for heater target=300.0 and ambient temp=19.0 (degC)
=== gas_valid_r: 1
=== heat_stab_r: 1
```
## Burn-in / logging
See file `example/log.c`
See file `cmd/log.c`
![Graph of gas resistance measured over time](.gitea/gas.png)
![Graph of temperature measured over time](.gitea/temp.png)

166
bme680.c
View File

@ -279,6 +279,16 @@ int bme680_read(bme680_t *bme680) {
/* These arrays are used to compute a sensor heating value `res_heat' */
/* for a specified heating target, specified in degree C. */
/***********************************************************************/
/*
* Below functions are out of the datasheet
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverflow"
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wfloat-conversion"
static double const_array1[16] = {
1, 1, 1, 1, 1, 0.99, 1, 0.992, 1,
1, 0.998, 0.995, 1, 0.99, 1, 1
@ -297,14 +307,11 @@ static int const_array1_int[16] = {
2147483647
};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverflow"
static int const_array2_int[16] = {
4096000000, 2048000000, 1024000000, 512000000, 255744255,
127110228, 64000000, 32258064, 16016016, 8000000, 4000000,
2000000, 1000000, 500000, 250000, 125000
};
#pragma GCC diagnostic pop
/********************************************************************/
/********************************************************************/
@ -364,8 +371,6 @@ static void calc_press_comp_1 (bme680_t *bme680) {
}
/********************************************************************/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
static void calc_press_comp_2 (bme680_t *bme680 ) {
int32_t var1, var2, var3, press_comp;
@ -391,7 +396,6 @@ static void calc_press_comp_2 (bme680_t *bme680 ) {
press_comp = (int32_t)(press_comp) + ((var1 + var2 + var3 + ((int32_t)bme680->cal.par_p7 << 7)) >> 4);
bme680->icomp.press = press_comp;
}
#pragma GCC diagnostic pop
/********************************************************************/
static void calc_press_comp (bme680_t *bme680) {
@ -447,6 +451,78 @@ static void calc_hum_comp (bme680_t *bme680) {
}
}
/********************************************************************/
static void calc_gas_res_1(bme680_t *bme680) {
double var1, gas_res;
var1 = (1340.0 + 5.0 * bme680->cal.range_switching_error) * const_array1[bme680->adc.gas_range];
gas_res = var1 * const_array2[bme680->adc.gas_range] / (bme680->adc.gas - 512.0 + var1);
bme680->fcomp.gas_res = gas_res;
}
/********************************************************************/
static void calc_gas_res_2(bme680_t *bme680) {
int64_t var1, var2;
int32_t gas_res;
var1 = (int64_t)(((1340 + (5 * (int64_t)bme680->cal.range_switching_error)) *
((int64_t)const_array1_int[bme680->adc.gas_range])) >> 16);
var2 = (int64_t)(bme680->adc.gas << 15) - (int64_t)(1 << 24) + var1;
gas_res = (int32_t)((((int64_t)(const_array2_int[bme680->adc.gas_range] *
(int64_t)var1) >> 9) + (var2 >> 1)) / var2);
bme680->icomp.gas_res = gas_res;
}
/********************************************************************/
static void calc_gas_res(bme680_t *bme680) {
if (BME680_IS_FLOAT(bme680->mode)) {
calc_gas_res_1(bme680);
} else {
calc_gas_res_2(bme680);
}
}
/********************************************************************/
static uint8_t calc_target_1(bme680_t *bme680, double target, double ambient) {
double var1, var2, var3, var4, var5;
uint8_t res_heat;
var1 = ((double)bme680->cal.par_g1 / 16.0) + 49.0;
var2 = (((double)bme680->cal.par_g2 / 32768.0) * 0.0005) + 0.00235;
var3 = (double)bme680->cal.par_g3 / 1024.0;
var4 = var1 * (1.0 + (var2 * (double)target));
var5 = var4 + (var3 * (double)ambient);
res_heat = (uint8_t)(3.4 * ((var5 * (4.0 / (4.0 + (double)bme680->cal.res_heat_range)) *
(1.0 / (1.0 + ((double)bme680->cal.res_heat_val * 0.002)))) - 25));
return res_heat;
}
/********************************************************************/
static uint8_t calc_target_2(bme680_t *bme680, double target, double ambient) {
int32_t var1, var2, var3, var4, var5, res_heat_x100;
uint8_t res_heat;
var1 = (((int32_t)ambient * bme680->cal.par_g3) / 10) << 8;
var2 = (bme680->cal.par_g1 + 784) * (((((bme680->cal.par_g2 + 154009) * target * 5) /
100) + 3276800) / 10);
var3 = var1 + (var2 >> 1);
var4 = (var3 / (bme680->cal.res_heat_range + 4));
var5 = (131 * bme680->cal.res_heat_val) + 65536;
res_heat_x100 = (int32_t)(((var4 / var5) - 250) * 34);
res_heat = (uint8_t)((res_heat_x100 + 50) / 100);
return res_heat;
}
/********************************************************************/
uint8_t bme680_calc_target(bme680_t *bme680, double target, double ambient) {
if (BME680_IS_FLOAT(bme680->mode)) {
return calc_target_1(bme680, target, ambient);
} else {
return calc_target_2(bme680, target, ambient);
}
}
#pragma GCC diagnostic pop
/********************************************************************/
/* TODO: read one big contiguous block */
int bme680_calibrate(bme680_t *bme680) {
@ -539,80 +615,4 @@ int bme680_calibrate(bme680_t *bme680) {
bme680->cal.res_heat_val = (int8_t)buffer[0];
return err;
}
/********************************************************************/
static void calc_gas_res_1(bme680_t *bme680) {
double var1, gas_res;
var1 = (1340.0 + 5.0 * bme680->cal.range_switching_error) * const_array1[bme680->adc.gas_range];
gas_res = var1 * const_array2[bme680->adc.gas_range] / (bme680->adc.gas - 512.0 + var1);
bme680->fcomp.gas_res = gas_res;
}
/********************************************************************/
static void calc_gas_res_2(bme680_t *bme680) {
int64_t var1, var2;
int32_t gas_res;
var1 = (int64_t)(((1340 + (5 * (int64_t)bme680->cal.range_switching_error)) *
((int64_t)const_array1_int[bme680->adc.gas_range])) >> 16);
var2 = (int64_t)(bme680->adc.gas << 15) - (int64_t)(1 << 24) + var1;
gas_res = (int32_t)((((int64_t)(const_array2_int[bme680->adc.gas_range] *
(int64_t)var1) >> 9) + (var2 >> 1)) / var2);
bme680->icomp.gas_res = gas_res;
}
/********************************************************************/
static void calc_gas_res(bme680_t *bme680) {
if (BME680_IS_FLOAT(bme680->mode)) {
calc_gas_res_1(bme680);
} else {
calc_gas_res_2(bme680);
}
}
/********************************************************************/
static uint8_t calc_target_1(bme680_t *bme680, double target, double ambient) {
double var1, var2, var3, var4, var5;
uint8_t res_heat;
var1 = ((double)bme680->cal.par_g1 / 16.0) + 49.0;
var2 = (((double)bme680->cal.par_g2 / 32768.0) * 0.0005) + 0.00235;
var3 = (double)bme680->cal.par_g3 / 1024.0;
var4 = var1 * (1.0 + (var2 * (double)target)); /* */
var5 = var4 + (var3 * (double)ambient);
res_heat = (uint8_t)(3.4 * ((var5 * (4.0 / (4.0 + (double)bme680->cal.res_heat_range)) *
(1.0 / (1.0 + ((double)bme680->cal.res_heat_val * 0.002)))) - 25));
return res_heat;
}
/********************************************************************/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-conversion"
static uint8_t calc_target_2(bme680_t *bme680, double target, double ambient) {
int32_t var1, var2, var3, var4, var5, res_heat_x100;
uint8_t res_heat;
var1 = (((int32_t)ambient * bme680->cal.par_g3) / 10) << 8;
var2 = (bme680->cal.par_g1 + 784) * (((((bme680->cal.par_g2 + 154009) * target * 5) /
100) + 3276800) / 10);
var3 = var1 + (var2 >> 1);
var4 = (var3 / (bme680->cal.res_heat_range + 4));
var5 = (131 * bme680->cal.res_heat_val) + 65536;
res_heat_x100 = (int32_t)(((var4 / var5) - 250) * 34);
res_heat = (uint8_t)((res_heat_x100 + 50) / 100);
return res_heat;
}
#pragma GCC diagnostic pop
/********************************************************************/
uint8_t bme680_calc_target(bme680_t *bme680, double target, double ambient) {
if (BME680_IS_FLOAT(bme680->mode)) {
return calc_target_1(bme680, target, ambient);
} else {
return calc_target_2(bme680, target, ambient);
}
}
}

View File

@ -1,101 +0,0 @@
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include "bme680.h"
#include "i2c.h"
#define AMBIENT_TEMP_GUESS 19.0
#define HEATER_TARGET 300.0
int main(void) {
bme680_t bme680;
uint8_t mode;
double temperature = AMBIENT_TEMP_GUESS;
time_t curr_time;
char date[100];
bme680.dev.init = i2c_init;
bme680.dev.read = i2c_read;
bme680.dev.write = i2c_write;
bme680.dev.deinit = i2c_deinit;
bme680.dev.sleep = usleep;
mode = BME680_MODE_FLOAT | BME680_I2C | BME680_ENABLE_GAS;
if (bme680_init(&bme680, mode) != 0) {
fprintf(stderr, "bme680_init()\n");
exit(EXIT_FAILURE);
}
START:
bme680_reset(&bme680);
if (bme680_calibrate(&bme680) != 0) {
fprintf(stderr, "bme680_calibrate()\n");
bme680_deinit(&bme680);
exit(EXIT_FAILURE);
}
bme680.cfg.osrs_t = BME680_OVERSAMPLE_X16;
bme680.cfg.osrs_p = BME680_OVERSAMPLE_X16;
bme680.cfg.osrs_h = BME680_OVERSAMPLE_X8;
bme680.cfg.filter = BME680_IIR_COEFF_127;
bme680.cfg.res_heat[0] = bme680_calc_target(&bme680, HEATER_TARGET, temperature);
bme680.cfg.idac_heat[0] = BME680_IDAC(100);
bme680.cfg.gas_wait[0] = BME680_GAS_WAIT(25, BME680_GAS_WAIT_X4);
bme680.setpoint = 0;
if (bme680_configure(&bme680) != 0) {
fprintf(stderr, "bme680_configure()\n");
bme680_deinit(&bme680);
exit(EXIT_FAILURE);
}
if (bme680_start(&bme680) != 0) {
fprintf(stderr, "bme680_start()\n");
bme680_deinit(&bme680);
exit(EXIT_FAILURE);
}
if (bme680_poll(&bme680) != 0) {
fprintf(stderr, "bme680_poll()\n");
bme680_deinit(&bme680);
exit(EXIT_FAILURE);
}
if (bme680_read(&bme680) != 0) {
fprintf(stderr, "bme680_read()\n");
bme680_deinit(&bme680);
exit(EXIT_FAILURE);
}
curr_time = time(NULL);
strftime(date, 100, "%FT%T%z", localtime(&curr_time));
printf("%s %g %g %g %g %d\n",
date,
bme680.fcomp.temp,
bme680.fcomp.press,
bme680.fcomp.hum,
bme680.fcomp.gas_res,
!!bme680.heat_stab);
temperature = bme680.fcomp.temp;
// 60 secs
usleep(1000*1000*60);
goto START;
bme680_deinit(&bme680);
return 0;
}