|
|
@ -10,7 +10,7 @@ |
|
|
|
* BLINK : I2C ERROR |
|
|
|
* BLINK : I2C ERROR |
|
|
|
* FLASH : Heartbeat |
|
|
|
* FLASH : Heartbeat |
|
|
|
* |
|
|
|
* |
|
|
|
* Copyright (C) 2023 M.T. Konstapel https://meezenest.nl/mees
|
|
|
|
* Copyright (C) 2023, 2024 M.T. Konstapel https://meezenest.nl/mees
|
|
|
|
* |
|
|
|
* |
|
|
|
* This file is part of weather_station |
|
|
|
* This file is part of weather_station |
|
|
|
* |
|
|
|
* |
|
|
@ -42,6 +42,7 @@ SI7021 si7021; |
|
|
|
// Pressure sensor
|
|
|
|
// Pressure sensor
|
|
|
|
#include "i2c_BMP280.h" |
|
|
|
#include "i2c_BMP280.h" |
|
|
|
BMP280 bmp280; |
|
|
|
BMP280 bmp280; |
|
|
|
|
|
|
|
float PRESSURE_OFFSET = 210; // Calibration of BMP280: offset in Pascal
|
|
|
|
|
|
|
|
|
|
|
|
/**************************/ |
|
|
|
/**************************/ |
|
|
|
/* Configurable variables */ |
|
|
|
/* Configurable variables */ |
|
|
@ -128,30 +129,33 @@ void ReadSi7021 (void) |
|
|
|
si7021.triggerMeasurement(); |
|
|
|
si7021.triggerMeasurement(); |
|
|
|
si7021.getHumidity(MeasuredData.Humidity); |
|
|
|
si7021.getHumidity(MeasuredData.Humidity); |
|
|
|
si7021.getTemperature(MeasuredData.Temperature); |
|
|
|
si7021.getTemperature(MeasuredData.Temperature); |
|
|
|
// Scale for more decimal positions when converted to integer value for ModBus
|
|
|
|
|
|
|
|
MeasuredData.Humidity *= 100; |
|
|
|
|
|
|
|
MeasuredData.Temperature *= 100; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//If humidity is larger than 80% switch on heater to get more acurate measurement
|
|
|
|
if (MeasuredData.Humidity>100 || MeasuredData.Humidity<0) |
|
|
|
//Switch off when lower than 78% (hysteresis)
|
|
|
|
MeasuredData.Humidity = 100; |
|
|
|
if (MeasuredData.Humidity > 80 && !MeasuredData.HeaterStatus) { |
|
|
|
|
|
|
|
|
|
|
|
//If humidity is larger than 96% switch on heater to get more acurate measurement and prevent memory offset
|
|
|
|
|
|
|
|
//Switch off when lower than 94% (hysteresis)
|
|
|
|
|
|
|
|
if (MeasuredData.Humidity > 96 && !MeasuredData.HeaterStatus) { |
|
|
|
Serial.print(F("Heater on.")); |
|
|
|
Serial.print(F("Heater on.")); |
|
|
|
MeasuredData.HeaterStatus = 1; |
|
|
|
MeasuredData.HeaterStatus = 1; |
|
|
|
si7021.setHeater(MeasuredData.HeaterStatus); |
|
|
|
si7021.setHeater(MeasuredData.HeaterStatus); |
|
|
|
} |
|
|
|
} |
|
|
|
if (MeasuredData.Humidity < 78 && MeasuredData.HeaterStatus) { |
|
|
|
if (MeasuredData.Humidity < 94 && MeasuredData.HeaterStatus) { |
|
|
|
Serial.print(F("Heater off.")); |
|
|
|
Serial.print(F("Heater off.")); |
|
|
|
MeasuredData.HeaterStatus = 0; |
|
|
|
MeasuredData.HeaterStatus = 0; |
|
|
|
si7021.setHeater(MeasuredData.HeaterStatus); |
|
|
|
si7021.setHeater(MeasuredData.HeaterStatus); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Scale for more decimal positions when converted to integer value for ModBus
|
|
|
|
|
|
|
|
MeasuredData.Humidity *= 100; |
|
|
|
|
|
|
|
MeasuredData.Temperature *= 100; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Read BMP280
|
|
|
|
// Read BMP280
|
|
|
|
void ReadBMP280 (void) |
|
|
|
void ReadBMP280 (void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
MeasuredData.Pressure=0; |
|
|
|
// MeasuredData.Pressure=0;
|
|
|
|
/*
|
|
|
|
|
|
|
|
bmp280.awaitMeasurement(); |
|
|
|
bmp280.awaitMeasurement(); |
|
|
|
|
|
|
|
|
|
|
|
float temperature; |
|
|
|
float temperature; |
|
|
@ -160,10 +164,20 @@ void ReadBMP280 (void) |
|
|
|
float pascal; |
|
|
|
float pascal; |
|
|
|
bmp280.getPressure(pascal); |
|
|
|
bmp280.getPressure(pascal); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pascal = (pascal - PRESSURE_OFFSET) / 10; // Convert to hPa
|
|
|
|
|
|
|
|
|
|
|
|
MeasuredData.Pressure = pascal; |
|
|
|
MeasuredData.Pressure = pascal; |
|
|
|
|
|
|
|
|
|
|
|
bmp280.triggerMeasurement(); |
|
|
|
bmp280.triggerMeasurement(); |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
// When humidity is high, the heater of the Si7021 is on. This causes the temperature sensor of the humidity sensor to heat up.
|
|
|
|
|
|
|
|
// Use temperature sensor of BMP280 instead.
|
|
|
|
|
|
|
|
if (MeasuredData.HeaterStatus) { |
|
|
|
|
|
|
|
bmp280.getTemperature(MeasuredData.Temperature); |
|
|
|
|
|
|
|
// Scale for more decimal positions when converted to integer value for ModBus
|
|
|
|
|
|
|
|
MeasuredData.Temperature *= 100; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int MaxOfArray (int array[], unsigned int length) |
|
|
|
int MaxOfArray (int array[], unsigned int length) |
|
|
@ -329,7 +343,7 @@ void setup() { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* // Initialize BMP280 pressure sensor
|
|
|
|
// Initialize BMP280 pressure sensor
|
|
|
|
Serial.print(F("Pressure sensor BMP280 ")); |
|
|
|
Serial.print(F("Pressure sensor BMP280 ")); |
|
|
|
if (bmp280.initialize())
|
|
|
|
if (bmp280.initialize())
|
|
|
|
Serial.println(F("found")); |
|
|
|
Serial.println(F("found")); |
|
|
@ -347,7 +361,7 @@ void setup() { |
|
|
|
// onetime-measure:
|
|
|
|
// onetime-measure:
|
|
|
|
bmp280.setEnabled(0); |
|
|
|
bmp280.setEnabled(0); |
|
|
|
bmp280.triggerMeasurement(); |
|
|
|
bmp280.triggerMeasurement(); |
|
|
|
*/ |
|
|
|
|
|
|
|
// Expected ADC values have been defined for various platforms in the
|
|
|
|
// Expected ADC values have been defined for various platforms in the
|
|
|
|
// library, however your platform may not be included. This code will check
|
|
|
|
// library, however your platform may not be included. This code will check
|
|
|
|
// if that's the case
|
|
|
|
// if that's the case
|
|
|
@ -358,6 +372,61 @@ void setup() { |
|
|
|
// resolution, so you'll need to specify it here:
|
|
|
|
// resolution, so you'll need to specify it here:
|
|
|
|
weatherMeterKit.setADCResolutionBits(10); |
|
|
|
weatherMeterKit.setADCResolutionBits(10); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Here we create a struct to hold all the calibration parameters
|
|
|
|
|
|
|
|
SFEWeatherMeterKitCalibrationParams calibrationParams = weatherMeterKit.getCalibrationParams(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The wind vane has 8 switches, but 2 could close at the same time, which
|
|
|
|
|
|
|
|
// results in 16 possible positions. Each position has a resistor connected
|
|
|
|
|
|
|
|
// to GND, so this library assumes a voltage divider is created by adding
|
|
|
|
|
|
|
|
// another resistor to VCC. Some of the wind vane resistor values are
|
|
|
|
|
|
|
|
// fairly close to each other, meaning an accurate ADC is required. However
|
|
|
|
|
|
|
|
// some ADCs have a non-linear behavior that causes this measurement to be
|
|
|
|
|
|
|
|
// inaccurate. To account for this, the vane resistor values can be manually
|
|
|
|
|
|
|
|
// changed here to compensate for the non-linear behavior of the ADC
|
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_0_0] = 943; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_22_5] = 828; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_45_0] = 885; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_67_5] = 702; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_90_0] = 785; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_112_5] = 404; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_135_0] = 460; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_157_5] = 82; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_180_0] = 91; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_202_5] = 64; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_225_0] = 185; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_247_5] = 125; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_270_0] = 285; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_292_5] = 242; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_315_0] = 628; |
|
|
|
|
|
|
|
calibrationParams.vaneADCValues[WMK_ANGLE_337_5] = 598; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The rainfall detector contains a small cup that collects rain water. When
|
|
|
|
|
|
|
|
// the cup fills, the water is dumped and the total rainfall is incremented
|
|
|
|
|
|
|
|
// by some value. This value defaults to 0.2794mm of rain per count, as
|
|
|
|
|
|
|
|
// specified by the datasheet
|
|
|
|
|
|
|
|
calibrationParams.mmPerRainfallCount = 0.2794; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The rainfall detector switch can sometimes bounce, causing multiple extra
|
|
|
|
|
|
|
|
// triggers. This input is debounced by ignoring extra triggers within a
|
|
|
|
|
|
|
|
// time window, which defaults to 100ms
|
|
|
|
|
|
|
|
calibrationParams.minMillisPerRainfall = 100; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The anemometer contains a switch that opens and closes as it spins. The
|
|
|
|
|
|
|
|
// rate at which the switch closes depends on the wind speed. The datasheet
|
|
|
|
|
|
|
|
// states that a wind of 2.4kph causes the switch to close once per second
|
|
|
|
|
|
|
|
calibrationParams.kphPerCountPerSec = 2.4; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Because the anemometer generates discrete pulses as it rotates, it's not
|
|
|
|
|
|
|
|
// possible to measure the wind speed exactly at any point in time. A filter
|
|
|
|
|
|
|
|
// is implemented in the library that averages the wind speed over a certain
|
|
|
|
|
|
|
|
// time period, which defaults to 1 second. Longer intervals result in more
|
|
|
|
|
|
|
|
// accurate measurements, but cause delay in the measurement
|
|
|
|
|
|
|
|
calibrationParams.windSpeedMeasurementPeriodMillis = 1000; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now we can set all the calibration parameters at once
|
|
|
|
|
|
|
|
weatherMeterKit.setCalibrationParams(calibrationParams); |
|
|
|
|
|
|
|
|
|
|
|
// Begin weather meter kit
|
|
|
|
// Begin weather meter kit
|
|
|
|
weatherMeterKit.begin(); |
|
|
|
weatherMeterKit.begin(); |
|
|
|
|
|
|
|
|
|
|
@ -396,6 +465,10 @@ void loop() { |
|
|
|
mb.Ireg (SensorHumidityIreg, MeasuredData.Humidity); |
|
|
|
mb.Ireg (SensorHumidityIreg, MeasuredData.Humidity); |
|
|
|
mb.Ireg (SensorPressureIreg, MeasuredData.Pressure); |
|
|
|
mb.Ireg (SensorPressureIreg, MeasuredData.Pressure); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Debug wind vane
|
|
|
|
|
|
|
|
//Serial.print(F("\n Measured ADC: "));
|
|
|
|
|
|
|
|
//Serial.print(analogRead(windDirectionPin));
|
|
|
|
|
|
|
|
|
|
|
|
digitalWrite(LED_BUILTIN, LOW); // LED as heartbeat
|
|
|
|
digitalWrite(LED_BUILTIN, LOW); // LED as heartbeat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|