Removed Si7021 and added HYT221 humidity sensor
This commit is contained in:
@@ -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();
|
||||
|
Reference in New Issue
Block a user