Removed Si7021 and added HYT221 humidity sensor

This commit is contained in:
marcel
2024-05-02 11:04:41 +02:00
parent 71a3a48af7
commit eeb6bd846c
7 changed files with 103 additions and 149 deletions

View File

@@ -32,6 +32,9 @@
* - Changed some variables to the propper standard (uint8_t, uint16_t, etc.)
* - SparkFun wind interrupt now calculates over 3 seconds in stead of 1 second (KNMI standard)
*
* 2-24-05-02: - Removed cope for si7021
* - Added code for HYT221 humidity sensor
*
* See CHANGELOG.md
*
**********************************************************************************/
@@ -43,8 +46,7 @@
#include "i2c.h"
//Temperature and humidity sensor
#include "i2c_SI7021.h"
SI7021 si7021;
#define HYT_ADDR 0x28 // I2C address of the HYT 221, 271, 371 and most likely the rest of the family
// Pressure sensor
#include "i2c_BMP280.h"
@@ -152,136 +154,49 @@ struct MeasuredData {
bool HeaterStatus = 0;
} MeasuredData;
// State machine implementing smart heater to prevent saturation of the sensor
char HeaterSi7021 (float humidity)
void ReadHYT221 (void)
{
static int state=0;
static unsigned long StatemachineTimer=0;
bool TempValid=1;
bool Heater=0;
double humidity;
double temperature;
Wire.beginTransmission(HYT_ADDR); // Begin transmission with given device on I2C bus
Wire.requestFrom(HYT_ADDR, 4); // Request 4 bytes
// Read the bytes if they are available
// The first two bytes are humidity the last two are temperature
if(Wire.available() == 4) {
int b1 = Wire.read();
int b2 = Wire.read();
int b3 = Wire.read();
int b4 = Wire.read();
Wire.endTransmission(); // End transmission and release I2C bus
// combine humidity bytes and calculate humidity
int rawHumidity = b1 << 8 | b2;
// compound bitwise to get 14 bit measurement first two bits
// are status/stall bit (see intro text)
rawHumidity = (rawHumidity &= 0x3FFF);
humidity = 100.0 / pow(2,14) * rawHumidity;
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Humidity = 100 * humidity;
// If Smart heater algorithm is disabled, reset the statemachine forever.
// TempValid bit is also forced to 1, but it could be that we just came out of a heater period.
// We assume that the client on the other side of the ModBus is smart enough to understand.
if ( (MeasuredData.StatusBits & 0x04) == 0)
state = 0;
// combine temperature bytes and calculate temperature
b4 = (b4 >> 2); // Mask away 2 least significant bits see HYT 221 doc
int rawTemperature = b3 << 6 | b4;
temperature = 165.0 / pow(2,14) * rawTemperature - 40;
switch (state)
{
// Default state: humidity is below HUMIDITY_THRESHOLD
case 0:
Heater = 0;
if (humidity >= HUMIDITY_THRESHOLD) {
StatemachineTimer = millis();
state = 1;
}
break;
// Humidity went above HUMIDITY_THRESHOLD. See if humidity stays above HUMIDITY_THRESHOLD for more than an hour, if so turn on heater
case 1:
if (humidity >= HUMIDITY_THRESHOLD) {
if ( (millis() - StatemachineTimer) >= 3.6e+6 ) {
//if ( (millis() - StatemachineTimer) >= 300000 ) { // short delay for testing
Heater = 1;
TempValid = 0;
StatemachineTimer = millis();
state = 2;
} else {
Heater = 0;
}
} else {
Heater = 0;
state = 0;
}
break;
// Heater is now on, let the sensor cook for 5 minutes
case 2:
if ( (millis() - StatemachineTimer) >= 300000 ) {
StatemachineTimer = millis();
Heater = 0;
state = 3;
} else {
Heater = 1;
}
TempValid = 0;
break;
// Heater is now off, let the sensor cool for 15 minutes
case 3:
if ( (millis() - StatemachineTimer) >= 900000 ) {
TempValid = 1; // Sensor cooled, so we can take a valid temperature reading
if (humidity >= HUMIDITY_THRESHOLD) {
// Humidity still above HUMIDITY_THRESHOLD, repeat heating/cooling
Heater = 1;
StatemachineTimer = millis();
state = 2;
} else {
// Humidity below HUMIDITY_THRESHOLD, reset statemachine
Heater = 0;
state = 0;
}
} else {
Heater = 0;
TempValid = 0;
}
break;
default:
Heater = 0;
state = 0;
break;
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Temperature = 100 * temperature;
//Serial.print(MeasuredData.Humidity);
//Serial.print("% - Temperature: ");
//Serial.println(MeasuredData.Temperature);
}
else {
Serial.println("Not enough bytes available on wire.");
}
return TempValid<<1 | Heater;
}
// Read Si7021 sensor and process data
void ReadSi7021 (void)
{
char result=0x2;
float humidity;
si7021.triggerMeasurement();
si7021.getHumidity(humidity);
// There is a bug in the Si7021 chip: when the sensor is exposed to extreme environmental conditions for a longer period (very high or very low humidity),
// the humidity register will wrap around and give wrong values. (https://community.silabs.com/s/question/0D51M00007xeOo9SAE/si7021-relative-humidity-reading-underflowing-?language=en_US).
// Workaround: let's assume the humidity will never go below 15%. In the Netherlands a humidity of below 20% is rare, but can occur and the minimum value ever measured
// in De Bilt was 6% (on 1 april 1965). At several other sites in the Netherlands the humidity went as low as 10%. But as this was a one time event and the
// measurements are doubtful, this event was nor registered in the original database. (https://nl.wikipedia.org/wiki/Relatieve_luchtvochtigheid)
// In rare cases, the humidity value could creep up above 15% (when the actual humidity is 100%) and still give wrong values.
if (humidity>100 || humidity<15)
humidity = 100;
//If humidity is larger than HUMIDITY_THRESHOLD switch on heater to get more acurate measurement and prevent memory offset
result = HeaterSi7021(humidity);
MeasuredData.StatusBits &= 0xFFFC; // Reset heater status bits to zero
MeasuredData.StatusBits |= result; // And set the proper bits to one if there are any. The result is we copied the status bits to the register
// Temperture and humidity readings are valid (as the sensor is not heated)
if (result & 0x2) {
si7021.getTemperature(MeasuredData.Temperature);
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Temperature *= 100;
//Serial.print(F("Valid temp"));
si7021.getHumidity(MeasuredData.Humidity);
// See humidity bug workaround above.
if (MeasuredData.Humidity>100 || MeasuredData.Humidity<15)
MeasuredData.Humidity = 100;
// Scale for more decimal positions when converted to integer value for ModBus
MeasuredData.Humidity *= 100;
}
// Statemachine thinks it is time to switch on the heater
if (result & 0x1) {
//Serial.print(F("Heater on."));
MeasuredData.HeaterStatus = 1;
} else {
//Serial.print(F("Heater off."));
MeasuredData.HeaterStatus = 0;
}
si7021.setHeater(MeasuredData.HeaterStatus);
}
// Read BMP280
@@ -467,26 +382,11 @@ void setup() {
mb.Ireg (SensorRainSinceMidnightIreg, 0);
mb.Ireg (SensorSnowFallIreg, 0);
Serial.println(F("Weather station v0.2.6"));
Serial.println(F("Weather station v0.3.0"));
Serial.println(F("(C)2024 M.T. Konstapel"));
Serial.println(F("This project is free and open source"));
Serial.println(F("More details: https://meezenest.nl/mees/"));
//Initialize Si7021 sensor
Serial.print(F("Humidity sensor SI7021 "));
if (si7021.initialize())
Serial.println(F("found"));
else
{
Serial.println(F("missing"));
while(1) {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for half a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(500);
}
}
// The standard library of the Si7021 sets the heater element to the default 3.1mA, but we want the full power
// We could alter the library, but than we break compatibility. So for this one time we do a raw-write to the
// heater register.
@@ -601,7 +501,7 @@ void loop() {
digitalWrite(LED_BUILTIN, HIGH); // LED as heartbeat
// Read temperature and humidity
ReadSi7021();
ReadHYT221();
// Read pressure and temperature
ReadBMP280();