Thanks for the reply,
I've written my own functions for both the AHT10 and BMx280. After 5 or 6 iterations the latest you can see below. I've also upload the data from March.
March Data.txt (277.5 KB)
The AHT10 is using the generic scaling values and I know from past work with calibrated systems, those scalers are a bit off, but are easily modified in the code. I live about 2400 meters from the official weather station for the local airport and both sensor track with the NWS data. Outside of this bad range in the BMx280s sensors the air pressure values, corrected for local elevation is allows only 0.01 or 0.02 inHg different than the official readings. I've seen this dead stop in both BMP's and BME's type sensors. I you want take a look at the BMx280 code and let me know is you see anything obvious.
/*
K Shoop March 2022
Basic functions to use a I2C interface with either a BMP280 or BME280 T/P/RH sensor
Provision to accommodate a I2C multiple chip with address 0x77 are included in the code
Provisions for using a separate temperature compensation value (t_fine) based in the 2nd sensor in incorporated into read_all()
To use with BMP type sesnor, comment out the humitiy related code in int_BMP() and read_All() functions
and reduce the requested number of byte to 6
Usage: Calling main function should define a doubles point to receive the read_All() returned values
ie: double *readings = read_All(TCV); to use BMx t_fine = -205000 (-204825 is t_fine for -40 C)
to use a temperture (in C) from 2nd sensor, t_fine = ((((int32_t)Temperature * 100)<<8)-128)/5
*/
#include <Arduino.h>
#include <Wire.h>
#include "bme280.h"
typedef uint32_t BME280_U32_t; //Type defined in the Bosch datasheet
typedef int32_t BME280_S32_t; //Type defined in the Bosch datasheet
typedef int64_t BME280_S64_t; //Type defined in the Bosch datasheet
BME280_S32_t t_fine; //Temperature correction factor for pressure calculations
#define addr 0x76 //BMx280 I2C Address
//#define plexer
uint16_t dig_T1; //Temperature compensation
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1; //Pressure compensation
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
uint8_t dig_H1; //Humidity compensation - Comment out H1 thru H6 for BMP type sensor
int16_t dig_H2;
uint8_t dig_H3;
int16_t dig_H4;
int16_t dig_H5;
int8_t dig_H6;
uint8_t buffer[8]; //Array for the 8 byte reading values
//Unsigned short read - use this to read ALL compensation value
uint16_t readCompsU(int Addr, int reg) {
Wire.beginTransmission(Addr);
Wire.write(reg);
if (Wire.endTransmission(true) != 0) {
Serial.println("Connection Failed");
}
Wire.requestFrom(addr, 1);
uint16_t temp1 = Wire.read();
return temp1;
}
//Signed short read
int16_t readComps(int Addr, int reg) {
Wire.beginTransmission(Addr);
Wire.write(reg);
if (Wire.endTransmission(true) != 0) {
Serial.println("Connection Failed");
}
Wire.requestFrom(addr, 1);
int16_t temp1 = Wire.read();
return temp1;
}
//Unsigned char read
uint8_t readCompUChar(int Addr, int reg) {
Wire.beginTransmission(Addr);
Wire.write(reg);
if (Wire.endTransmission(true) != 0) {
Serial.println("Connection Failed");
}
Wire.requestFrom(addr, 1);
uint8_t temp1 = Wire.read();
return temp1;
}
//Configure the sensor and read in compensation values, Returns TRUE on completion of all steps
bool init_BME() {
//If using a I2C multiplex chip to issolate the sensors
#ifdef plexer
Wire.beginTransmission(0x77); //Make the i2c connection to 0x76
Wire.write(0x80); //point to config register
// Wire.write(0x01); //Set osrs_h = 1 (0000)
if (Wire.endTransmission(true) != 0) {
return false; //Hard end connection
}
#endif
//Configure the humidity function
Wire.beginTransmission(addr); //Make the i2c connection to 0x76
Wire.write(0xF2); //point to H config register
Wire.write(0x01); //Set osrs_h = 1 (0001)
if (Wire.endTransmission(true) != 0) {//Hard end connection
return false;
}
//Configure the temperature & pressure functions and set sampling mode type
Wire.beginTransmission(addr); //Make the i2c connection to 0x76
Wire.write(0xF4); //point to ctrl_meas register
Wire.write(0x26); //osrs_t = 1x; osrs_p = 1x; mode = forced (00100110)
if (Wire.endTransmission(true) != 0) {//Hard end connection
return false;
}
//Configure the standby time, filter and spi function
Wire.beginTransmission(addr); //Make the i2c connection to 0x76
Wire.write(0xF5); //point to config register
Wire.write(0x60); //t_sb = 0.25 sec; filter = OFF; spi = OFF (01100000)
if (Wire.endTransmission(true) != 0) {//Hard end connection
return false;
}
//Get the compensation factors - can't use a burts read, chip locks up after first read
//Need to read values one at a time
dig_T1 = (readCompsU(addr, 0X89) << 8) | (readCompsU(addr, 0X88)); // Returns 27554 (datasheet example has 27504)
dig_T2 = (readCompsU(addr, 0X8B) << 8) | (readCompsU(addr, 0X8A)); // Returns 25544 (datasheet example has 26435)
dig_T3 = (readCompsU(addr, 0X8D) << 8) | (readCompsU(addr, 0X8C)); // Returns 50 (datasheet example has -1000)
dig_P1 = (readCompsU(addr, 0X8F) << 8) | (readCompsU(addr, 0X8E)); // Returns 36896 (datasheet example has 36477)
dig_P2 = (readCompsU(addr, 0X91) << 8) | (readCompsU(addr, 0X90)); // Returns -10678 (datasheet example has -10685)
dig_P3 = (readCompsU(addr, 0X93) << 8) | (readCompsU(addr, 0X92)); // Returns 3024 (datasheet example has 3024)
dig_P4 = (readCompsU(addr, 0X95) << 8) | (readCompsU(addr, 0X94)); // Returns 5200 (datasheet example has 2855)
dig_P5 = (readCompsU(addr, 0X97) << 8) | (readCompsU(addr, 0X96)); // Returns 65 (datasheet example has 140)
dig_P6 = (readCompsU(addr, 0X99) << 8) | (readCompsU(addr, 0X98)); // Returns -7 (datasheet example has -7)
dig_P7 = (readCompsU(addr, 0X9B) << 8) | (readCompsU(addr, 0X9A)); // Returns 15500 (datasheet example has 15500)
dig_P8 = (readCompsU(addr, 0X9D) << 8) | (readCompsU(addr, 0X9C)); // Returns -14600 (datasheet example has -14600)
dig_P9 = (readCompsU(addr, 0X9F) << 8) | (readCompsU(addr, 0X9E)); // Returns 6000 (datasheet example has 6000)
dig_H1 = readCompUChar(addr, 0XA1); // Returns 5200 (datasheet example has 2855)
dig_H2 = (readComps(addr, 0XE2) << 8) | (readComps(addr, 0XE1)); // Returns 65 (datasheet example has 140)
dig_H3 = readCompUChar(addr, 0XE3); // Returns -7 (datasheet example has -7)
dig_H4 = (readComps(addr, 0XE4) << 4) | (readComps(addr, 0XE5) & 0x0F); // Returns 15500 (datasheet example has 15500)
dig_H5 = ((readComps(addr, 0XE6) << 8) | (readComps(addr, 0XE5) & 0xF0) >> 4); // Returns -14600 (datasheet example has -14600)
dig_H6 = readCompUChar(addr, 0XE7); // Returns 6000 (datasheet example has 6000)
return true;
}
/* Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
t_fine carries fine temperature as global value.
Page 25 - BST-BME280-DS001-23 Revision_1.23_012022 */
BME280_S32_t BME280_compensate_T_int32(BME280_S32_t adc_T) {
BME280_S32_t var1, var2, T;
var1 = ((((adc_T >> 3) - ((BME280_S32_t)dig_T1 << 1))) * ((BME280_S32_t)dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((BME280_S32_t)dig_T1)) * ((adc_T >> 4) - ((BME280_S32_t)dig_T1))) >> 12) * ((BME280_S32_t)dig_T3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}
/* "Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa"
Page 25 - BST-BME280-DS001-23 Revision_1.23_012022 */
BME280_U32_t BME280_compensate_P_int64(BME280_S32_t adc_P) {
BME280_S64_t var1, var2, p;
var1 = ((BME280_S64_t)t_fine) - 128000;
var2 = var1 * var1 * (BME280_S64_t)dig_P6;
var2 = var2 + ((var1 * (BME280_S64_t)dig_P5) << 17);
var2 = var2 + (((BME280_S64_t)dig_P4) << 35);
var1 = ((var1 * var1 * (BME280_S64_t)dig_P3) >> 8) + ((var1 * (BME280_S64_t)dig_P2) << 12);
var1 = (((((BME280_S64_t)1) << 47) + var1)) * ((BME280_S64_t)dig_P1) >> 33;
// avoid exception caused by division by zero
if (var1 == 0) {
return 0;
}
p = 1048576 - adc_P;
p = (((p << 31) - var2) * 3125) / var1;
var1 = (((BME280_S64_t)dig_P9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((BME280_S64_t)dig_P8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((BME280_S64_t)dig_P7) << 4);
return (BME280_U32_t)p;
}
/* Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
Output value of “47445” represents 47445/1024 = 46.333 %RH
Page 25,26 - BST-BME280-DS001-23 Revision_1.23_012022 */
BME280_U32_t BME280_compensate_H_int32(BME280_S32_t adc_H) {
BME280_S32_t v_x1_u32r;
v_x1_u32r = (t_fine - ((BME280_S32_t)76800));
v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)dig_H4) << 20) - (((BME280_S32_t)dig_H5) * v_x1_u32r)) + ((BME280_S32_t)16384)) >> 15) * (((((((v_x1_u32r * ((BME280_S32_t)dig_H6)) >> 10) * (((v_x1_u32r * ((BME280_S32_t)dig_H3)) >> 11) + ((BME280_S32_t)32768))) >> 10) + ((BME280_S32_t)2097152)) * ((BME280_S32_t)dig_H2) + 8192) >> 14));
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((BME280_S32_t)dig_H1)) >> 4));
v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
return (BME280_U32_t)(v_x1_u32r >> 12);
}
//Check the data read/ready status - not functioning and not used
bool checkStatus() {
uint32_t startTime = millis();
if (millis() - startTime < 2000) {
#ifdef plexer
Wire.beginTransmission(0x77); //Make the i2c connection to mplex chip 0x77
Wire.write(0x80); //point to config register
if (Wire.endTransmission(true) != 0) {
return false; //Hard end connection
}
#endif
Wire.beginTransmission(addr);
Wire.write(0xF3);
if (Wire.endTransmission(true) != 0) {
return false;
}
delay(10);
Wire.requestFrom(addr, 1);
if (Wire.read() == 0) {
return true;
}
}
return false;
}
//Read sensors and convert to engineering units - returns pointer with 3 double values
double *read_All(int32_t T_FINE) {
static double answers[3] = { 0, 0, 0 }; //Init array to be returned - calling sketch can determine data validity by the pressure and humidity values
if (init_BME()) { //Set up sensor - this is here to allow hot swapping the BMx280 module
//Read Sensor
Wire.beginTransmission(addr);
Wire.write(0xF7); //point to first data registor
if (Wire.endTransmission(true) != 0) {
Serial.println("Data Read Failed");
return answers;
}
delay(50); //wait for the forced read to occor and the data to be placed in buffer
Wire.requestFrom(addr, 8); //Request the 8 data byte readings - Change 8 to 6 for BMP type sensor
for (int i = 0; i < 8; i++) { //Change 8 to 6 for BMP type sensor
buffer[i] = Wire.read();
}
//Process the temperature reading into 32-bit signed intiger
int32_t temp = ((((int32_t)buffer[3]) << 12) | (((int32_t)buffer[4]) << 4) | (((int32_t)buffer[5])) >> 4); //build temperature raw value
int32_t T = BME280_compensate_T_int32(temp); //Call the temperature porcessing
if (T_FINE > -204999) { //If incoming parameter is greater the the lowest possible t_fine for -40 C
t_fine = T_FINE; //Set t_fine = incoming parameter
}
//Process the pressure reading into 64-bit signed intiger
temp = ((((int32_t)buffer[0]) << 12) | (((int32_t)buffer[1]) << 4) | (((int32_t)buffer[2])) >> 4);
int64_t P = BME280_compensate_P_int64(temp);
//Process the humidity into 32-bit signed intiger - Comment out the next 2 lines for BMP type sensor
temp = ((int32_t)buffer[6]) << 8 | ((int32_t)buffer[7]);
int32_t H = BME280_compensate_H_int32(temp);
//Convert the temperature bytes to engineering unit, degrees C
answers[0] = (double)T / 100.0;
//Convert the pressure bytes to engineering unit, in-Hg C, corrected for 287 meters elevation
answers[1] = ((double)P / 256.0 / 6894.76 + 0.5108) * 2.03602;
//Convert the humidity bytes to engineering unit, % - Comment out for BMP type sensor
answers[2] = (double)H / 1024.0;
}
return answers; //return the 3-doubles array
}