From cd756e59947b382f732c9d863cc07b058fb8c27c Mon Sep 17 00:00:00 2001 From: GrafZ3pp3lin Date: Mon, 26 Apr 2021 18:36:14 +0200 Subject: [PATCH] corrected values + bme --- lib/DHT/dht.cpp | 266 -------------------------------------------- lib/DHT/dht.h | 91 --------------- lib/MQ135/MQ135.cpp | 57 ++++++++++ lib/MQ135/MQ135.h | 27 ++++- platformio.ini | 8 +- src/main.cpp | 91 ++++++++++----- 6 files changed, 151 insertions(+), 389 deletions(-) delete mode 100644 lib/DHT/dht.cpp delete mode 100644 lib/DHT/dht.h diff --git a/lib/DHT/dht.cpp b/lib/DHT/dht.cpp deleted file mode 100644 index 4f39f9f..0000000 --- a/lib/DHT/dht.cpp +++ /dev/null @@ -1,266 +0,0 @@ -// -// FILE: dht.cpp -// AUTHOR: Rob Tillaart -// VERSION: 0.1.33 -// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino, AVR optimized -// URL: https://github.com/RobTillaart/DHTlib -// http://arduino.cc/playground/Main/DHTLib -// -// HISTORY: -// 0.1.33 2021-02-16 fix #6 T-GO signal in handshake. (needed for long wires) -// 0.1.32 2021-02-01 fix negative temperature DHT22 again (code from DHTNew) -// 0.1.31 2020-12-15 fix negative temperature DHT22 (code from DHTNew) -// 0.1.30 2020-06-30 own repo; -// 0.1.29 2018-09-02 fix negative temperature DHT12 - issue #111 -// 0.1.28 2018-04-03 refactor -// 0.1.27 2018-03-26 added _disableIRQ flag -// 0.1.26 2017-12-12 explicit support for AM23XX series and DHT12 -// 0.1.25 2017-09-20 FIX https://github.com/RobTillaart/Arduino/issues/80 -// 0.1.24 2017-07-27 FIX https://github.com/RobTillaart/Arduino/issues/33 double -> float -// 0.1.23 2017-07-24 FIX https://github.com/RobTillaart/Arduino/issues/31 -// 0.1.22 undo delayMicroseconds() for wakeups larger than 8 -// 0.1.21 replace delay with delayMicroseconds() + small fix -// 0.1.20 Reduce footprint by using uint8_t as error codes. (thanks to chaveiro) -// 0.1.19 masking error for DHT11 - FIXED (thanks Richard for noticing) -// 0.1.18 version 1.16/17 broke the DHT11 - FIXED -// 0.1.17 replaced micros() with adaptive loopcount -// removed DHTLIB_INVALID_VALUE -// added DHTLIB_ERROR_CONNECT -// added DHTLIB_ERROR_ACK_L DHTLIB_ERROR_ACK_H -// 0.1.16 masking unused bits (less errors); refactored bits[] -// 0.1.15 reduced # micros calls 2->1 in inner loop. -// 0.1.14 replace digital read with faster (~3x) code => more robust low MHz machines. -// -// 0.1.13 fix negative temperature -// 0.1.12 support DHT33 and DHT44 initial version -// 0.1.11 renamed DHTLIB_TIMEOUT -// 0.1.10 optimized faster WAKEUP + TIMEOUT -// 0.1.09 optimize size: timeout check + use of mask -// 0.1.08 added formula for timeout based upon clockspeed -// 0.1.07 added support for DHT21 -// 0.1.06 minimize footprint (2012-12-27) -// 0.1.05 fixed negative temperature bug (thanks to Roseman) -// 0.1.04 improved readability of code using DHTLIB_OK in code -// 0.1.03 added error values for temp and humidity when read failed -// 0.1.02 added error codes -// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011) -// 0.1.00 by Rob Tillaart (01/04/2011) -// -// inspired by DHT11 library - -#include "dht.h" - -///////////////////////////////////////////////////// -// -// PUBLIC -// - -int8_t dht::read11(uint8_t pin) -{ - // READ VALUES - if (_disableIRQ) noInterrupts(); - int8_t result = _readSensor(pin, DHTLIB_DHT11_WAKEUP, DHTLIB_DHT11_LEADING_ZEROS); - if (_disableIRQ) interrupts(); - - // these bits are always zero, masking them reduces errors. - bits[0] &= 0x7F; - bits[2] &= 0x7F; - - // CONVERT AND STORE - humidity = bits[0]; // bits[1] == 0; - temperature = bits[2]; // bits[3] == 0; - - // TEST CHECKSUM - uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3]; - if (bits[4] != sum) - { - return DHTLIB_ERROR_CHECKSUM; - } - return result; -} - -int8_t dht::read12(uint8_t pin) -{ - // READ VALUES - if (_disableIRQ) noInterrupts(); - int8_t result = _readSensor(pin, DHTLIB_DHT11_WAKEUP, DHTLIB_DHT11_LEADING_ZEROS); - if (_disableIRQ) interrupts(); - - // CONVERT AND STORE - humidity = bits[0] + bits[1] * 0.1; - temperature = bits[2] + (bits[3] & 0x7F) * 0.1; - if (bits[3] & 0x80) // negative temperature - { - temperature = -temperature; - } - - // TEST CHECKSUM - uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3]; - if (bits[4] != sum) - { - return DHTLIB_ERROR_CHECKSUM; - } - return result; -} - -int8_t dht::read(uint8_t pin) -{ - // READ VALUES - if (_disableIRQ) noInterrupts(); - int8_t result = _readSensor(pin, DHTLIB_DHT_WAKEUP, DHTLIB_DHT_LEADING_ZEROS); - if (_disableIRQ) interrupts(); - - // these bits are always zero, masking them reduces errors. - bits[0] &= 0x03; - bits[2] &= 0x83; - - // CONVERT AND STORE - humidity = (bits[0] * 256 + bits[1]) * 0.1; - int16_t t = (bits[2] * 256 + bits[3]); - temperature = t * 0.1; - - // HEXDUMP DEBUG - /* - Serial.println(); - // CHECKSUM - if (_bits[4] < 0x10) Serial.print(0); - Serial.print(_bits[4], HEX); - Serial.print(" "); - // TEMPERATURE - if (_bits[2] < 0x10) Serial.print(0); - Serial.print(_bits[2], HEX); - if (_bits[3] < 0x10) Serial.print(0); - Serial.print(_bits[3], HEX); - Serial.print(" "); - Serial.print(temperature, 1); - Serial.print(" "); - // HUMIDITY - if (_bits[0] < 0x10) Serial.print(0); - Serial.print(_bits[0], HEX); - if (_bits[1] < 0x10) Serial.print(0); - Serial.print(_bits[1], HEX); - Serial.print(" "); - Serial.print(humidity, 1); - */ - - // TEST CHECKSUM - uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3]; - if (bits[4] != sum) - { - return DHTLIB_ERROR_CHECKSUM; - } - return result; -} - -///////////////////////////////////////////////////// -// -// PRIVATE -// - -int8_t dht::_readSensor(uint8_t pin, uint8_t wakeupDelay, uint8_t leadingZeroBits) -{ - // INIT BUFFERVAR TO RECEIVE DATA - uint8_t mask = 128; - uint8_t idx = 0; - - uint8_t data = 0; - uint8_t state = LOW; - uint8_t pstate = LOW; - uint16_t zeroLoop = DHTLIB_TIMEOUT; - uint16_t delta = 0; - - leadingZeroBits = 40 - leadingZeroBits; // reverse counting... - - // replace digitalRead() with Direct Port Reads. - // reduces footprint ~100 bytes => portability issue? - // direct port read is about 3x faster - uint8_t bit = digitalPinToBitMask(pin); - uint8_t port = digitalPinToPort(pin); - volatile uint8_t *PIR = portInputRegister(port); - - // REQUEST SAMPLE - pinMode(pin, OUTPUT); - digitalWrite(pin, LOW); // T-be - if (wakeupDelay > 8) delay(wakeupDelay); - else delayMicroseconds(wakeupDelay * 1000UL); - digitalWrite(pin, HIGH); // T-go - pinMode(pin, INPUT); - - uint16_t loopCount = DHTLIB_TIMEOUT * 2; // 200uSec max - // while(digitalRead(pin) == HIGH) - while ((*PIR & bit) != LOW ) - { - if (--loopCount == 0) - { - return DHTLIB_ERROR_CONNECT; - } - } - - // GET ACKNOWLEDGE or TIMEOUT - loopCount = DHTLIB_TIMEOUT; - // while(digitalRead(pin) == LOW) - while ((*PIR & bit) == LOW ) // T-rel - { - if (--loopCount == 0) - { - return DHTLIB_ERROR_ACK_L; - } - } - - loopCount = DHTLIB_TIMEOUT; - // while(digitalRead(pin) == HIGH) - while ((*PIR & bit) != LOW ) // T-reh - { - if (--loopCount == 0) - { - return DHTLIB_ERROR_ACK_H; - } - } - - loopCount = DHTLIB_TIMEOUT; - - // READ THE OUTPUT - 40 BITS => 5 BYTES - for (uint8_t i = 40; i != 0; ) - { - // WAIT FOR FALLING EDGE - state = (*PIR & bit); - if (state == LOW && pstate != LOW) - { - if (i > leadingZeroBits) // DHT22 first 6 bits are all zero !! DHT11 only 1 - { - zeroLoop = min(zeroLoop, loopCount); - delta = (DHTLIB_TIMEOUT - zeroLoop)/4; - } - else if ( loopCount <= (zeroLoop - delta) ) // long -> one - { - data |= mask; - } - mask >>= 1; - if (mask == 0) // next byte - { - mask = 128; - bits[idx] = data; - idx++; - data = 0; - } - // next bit - --i; - - // reset timeout flag - loopCount = DHTLIB_TIMEOUT; - } - pstate = state; - // Check timeout - if (--loopCount == 0) - { - return DHTLIB_ERROR_TIMEOUT; - } - - } - // pinMode(pin, OUTPUT); - // digitalWrite(pin, HIGH); - return DHTLIB_OK; -} -// -// END OF FILE -// \ No newline at end of file diff --git a/lib/DHT/dht.h b/lib/DHT/dht.h deleted file mode 100644 index 0f18253..0000000 --- a/lib/DHT/dht.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// FILE: dht.h -// AUTHOR: Rob Tillaart -// VERSION: 0.1.33 -// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino. AVR optimized -// URL: https://github.com/RobTillaart/DHTlib -// http://arduino.cc/playground/Main/DHTLib -// -// HISTORY: -// see dht.cpp file -// - -#ifndef dht_h -#define dht_h - -#if ARDUINO < 100 -#include -#include // fix for broken pre 1.0 version - TODO TEST -#else -#include -#endif - - -#define DHT_LIB_VERSION (F("0.1.33")) - -#define DHTLIB_OK 0 -#define DHTLIB_ERROR_CHECKSUM -1 -#define DHTLIB_ERROR_TIMEOUT -2 -#define DHTLIB_ERROR_CONNECT -3 -#define DHTLIB_ERROR_ACK_L -4 -#define DHTLIB_ERROR_ACK_H -5 - -#define DHTLIB_DHT11_WAKEUP 18 -#define DHTLIB_DHT_WAKEUP 1 - -#define DHTLIB_DHT11_LEADING_ZEROS 1 -#define DHTLIB_DHT_LEADING_ZEROS 6 - - -// max timeout is 100 usec. -// For a 16 Mhz proc 100 usec is 1600 clock cycles -// loops using DHTLIB_TIMEOUT use at least 4 clock cycli -// so 100 us takes max 400 loops -// so by dividing F_CPU by 40000 we "fail" as fast as possible -#ifndef F_CPU -#define DHTLIB_TIMEOUT 1000 // ahould be approx. clock/40000 -#else -#define DHTLIB_TIMEOUT (F_CPU/40000) -#endif - - -class dht -{ -public: - dht() { _disableIRQ = false; }; - // return values: - // DHTLIB_OK - // DHTLIB_ERROR_CHECKSUM - // DHTLIB_ERROR_TIMEOUT - // DHTLIB_ERROR_CONNECT - // DHTLIB_ERROR_ACK_L - // DHTLIB_ERROR_ACK_H - int8_t read11(uint8_t pin); - int8_t read(uint8_t pin); - int8_t read12(uint8_t pin); - - inline int8_t read21(uint8_t pin) { return read(pin); }; - inline int8_t read22(uint8_t pin) { return read(pin); }; - inline int8_t read33(uint8_t pin) { return read(pin); }; - inline int8_t read44(uint8_t pin) { return read(pin); }; - inline int8_t read2301(uint8_t pin) { return read(pin); }; - inline int8_t read2302(uint8_t pin) { return read(pin); }; - inline int8_t read2303(uint8_t pin) { return read(pin); }; - inline int8_t read2320(uint8_t pin) { return read(pin); }; - inline int8_t read2322(uint8_t pin) { return read(pin); }; - - bool getDisableIRQ() { return _disableIRQ; }; - void setDisableIRQ(bool b ) { _disableIRQ = b; }; - - float humidity; - float temperature; - -private: - uint8_t bits[5]; // buffer to receive data - int8_t _readSensor(uint8_t pin, uint8_t wakeupDelay, uint8_t leadingZeroBits); - bool _disableIRQ; -}; -#endif -// -// END OF FILE -// \ No newline at end of file diff --git a/lib/MQ135/MQ135.cpp b/lib/MQ135/MQ135.cpp index ef235f7..5e6ca01 100644 --- a/lib/MQ135/MQ135.cpp +++ b/lib/MQ135/MQ135.cpp @@ -9,6 +9,10 @@ double MQ135::getVoltage() { return (double)analogRead(pin) * VStep; } +double MQ135::getCorrectionFactor(float temparature, float humidity) { + return (CorrA * pow(temparature, 3) + CorrB * pow(temparature, 2) - CorrC * temparature + CorrD - (CorrE * humidity - CorrE * 33)); +} + double MQ135::getResistance() { double voltage = getVoltage(); double rs = ((VIn * RL) / voltage) - RL; @@ -18,6 +22,10 @@ double MQ135::getResistance() { return rs; } +double MQ135::getCorrectedResistance(float temparature, float humidity) { + return getResistance() / getCorrectionFactor(temparature, humidity); +} + double MQ135::getPPM(float a, float b) { double ratio = getResistance() / R0; double ppm = a * pow(ratio, b); @@ -27,6 +35,15 @@ double MQ135::getPPM(float a, float b) { return ppm; } +double MQ135::getCorrectedPPM(float a, float b, float temparature, float humidity) { + double ratio = getCorrectedResistance(temparature, humidity) / R0; + double ppm = a * pow(ratio, b); + if (ppm < 0) { + ppm = 0; + } + return ppm; +} + double MQ135::getPPMLinear(float a, float b) { double ratio = getResistance() / R0; double ppm_log = (log10(ratio) - b) / a; @@ -41,32 +58,61 @@ double MQ135::getAcetona() { return getPPM(34.668, -3.369); } +double MQ135::getCorrectedAcetona(float temparature, float humidity) { + return getCorrectedPPM(34.668, -3.369, temparature, humidity); +} + double MQ135::getAlcohol() { return getPPM(77.255, -3.18); } +double MQ135::getCorrectedAlcohol(float temparature, float humidity) { + return getCorrectedPPM(77.255, -3.18, temparature, humidity); +} + double MQ135::getCO2() { // return getPPMLinear(-0.3525, 0.7142) + ATMOCO2; return getPPM(110.47, -2.862) + ATMOCO2; } +double MQ135::getCorrectedCO2(float temparature, float humidity) { + return getCorrectedPPM(110.47, -2.862, temparature, humidity) + ATMOCO2; +} + double MQ135::getCO() { return getPPM(605.18, -3.937); } +double MQ135::getCorrectedCO(float temparature, float humidity) { + return getCorrectedPPM(605.18, -3.937, temparature, humidity); +} + double MQ135::getNH4() { return getPPM(102.2, -2.473); } +double MQ135::getCorrectedNH4(float temparature, float humidity) { + return getCorrectedPPM(102.2, -2.473, temparature, humidity); +} + double MQ135::getTolueno() { return getPPM(44.947, -3.445); } +double MQ135::getCorrectedTolueno(float temparature, float humidity) { + return getCorrectedPPM(44.947, -3.445, temparature, humidity); +} + float MQ135::getR0() { double r0 = getResistance() / 3.6; return r0; } +float MQ135::getCorrectedR0(float temparature, float humidity) { + double r0 = getCorrectedResistance(temparature, humidity) / 3.6; + return r0; +} + double MQ135::getR0ByCO2Level(float ppm) { if (ppm > ATMOCO2) { ppm -= ATMOCO2; @@ -78,6 +124,17 @@ double MQ135::getR0ByCO2Level(float ppm) { return pow(10, tmp); } +double MQ135::getCorrectedR0ByCO2Level(float ppm, float temparature, float humidity) { + if (ppm > ATMOCO2) { + ppm -= ATMOCO2; + } + else { + return NAN; + } + double tmp = -(log10(ppm / 110.47) / -2.862) + log10(getCorrectedResistance(temparature, humidity)); + return pow(10, tmp); +} + void MQ135::setR0(float r0) { R0 = r0; } diff --git a/lib/MQ135/MQ135.h b/lib/MQ135/MQ135.h index 4f3d0fe..597f6d1 100644 --- a/lib/MQ135/MQ135.h +++ b/lib/MQ135/MQ135.h @@ -1,5 +1,5 @@ -#ifndef MQ135New_H -#define MQ135New_H +#ifndef MQ135_H +#define MQ135_H #include "Arduino.h" @@ -16,6 +16,13 @@ /// CO2 Level in Atmosphere #define ATMOCO2 397.13 +//Correction Values +#define CorrA -0.000002469136 +#define CorrB 0.00048148148 +#define CorrC 0.0274074074 +#define CorrD 1.37530864197 +#define CorrE 0.0019230769 + /// Helper to calculate Voltage from Input /// Voltage = input * Vin / (Resolution - 1) const double VStep = (double)VIn / (Resolution - 1); @@ -33,34 +40,48 @@ class MQ135 { /// Get R0 in default conditions for calibration purposes. /// Assume CO2 Level is the default Atmospheric Level (~400ppm) float getR0(); + float getCorrectedR0(float temparature, float humidity); /// Get R0 in custom conditions for calibration purposes. /// Can be used, if you know the current CO2 Level. double getR0ByCO2Level(float ppm); + double getCorrectedR0ByCO2Level(float ppm, float temparature, float humidity); /// Set R0 Value for calibration. void setR0(float r0); - + /// Gets the resolved sensor voltage double getVoltage(); + + /// Calculate Correction Factor depending on temparature and humidity + double getCorrectionFactor(float temparature, float humidity); + /// Calculates the Resistance of the Sensor double getResistance(); + double getCorrectedResistance(float temparature, float humidity); /// Calculates ppm on a exponential curve /// (Different Gases have different curves) double getPPM(float a, float b); + double getCorrectedPPM(float a, float b, float temparature, float humidity); /// Calculates ppm on a linear curve /// (Different Gases have different curves) double getPPMLinear(float a, float b); /// Gets ppm of Acetona in Air (C3H6O) double getAcetona(); + double getCorrectedAcetona(float temparature, float humidity); /// Gets ppm of Alcohol in Air double getAlcohol(); + double getCorrectedAlcohol(float temparature, float humidity); /// Gets ppm of CO in Air double getCO(); + double getCorrectedCO(float temparature, float humidit); /// Gets ppm of CO2 in Air double getCO2(); + double getCorrectedCO2(float temparature, float humidit); /// Gets ppm of NH4 in Air double getNH4(); + double getCorrectedNH4(float temparature, float humidit); /// Gets ppm of Tolueno in Air (CH3) double getTolueno(); + double getCorrectedTolueno(float temparature, float humidit); }; #endif diff --git a/platformio.ini b/platformio.ini index ae5769a..85d4f78 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,10 +8,10 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:mega] +[env:arduino] platform = atmelavr -board = megaatmega2560 +board = nanoatmega328new framework = arduino -; lib_deps = -; adafruit/Adafruit BME280 Library @ ^2.1.2 +lib_deps = + adafruit/Adafruit BME280 Library @ ^2.1.2 ; miguel5612/MQUnifiedsensor @ ^2.0.1 diff --git a/src/main.cpp b/src/main.cpp index 133cbca..423ec8a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,14 +1,17 @@ #include #include +#include -#define PIN_MQ135 A0 -#define PIN_LED_GREEN DD2 -#define PIN_LED_YELLOW DD3 -#define PIN_LED_RED DD4 -#define PIN_NOISE DD5 +#define PIN_MQ135 A7 +#define PIN_NOISE 2 +#define PIN_LED_GREEN 3 +#define PIN_LED_GREEN2 4 +#define PIN_LED_YELLOW 5 +#define PIN_LED_YELLOW2 6 +#define PIN_LED_RED 7 +#define PIN_LED_RED2 8 -#define MEASURE_DELAY 1000 -#define NOISE_DELAY 100 +void printValues(); const int maxCount = 10; int count = 0; @@ -18,47 +21,85 @@ bool noiseActive = false; float ppm; MQ135 co2_sensor(PIN_MQ135); +Adafruit_BME280 bme; void setup() { + pinMode(PIN_LED_GREEN, OUTPUT); + pinMode(PIN_LED_GREEN2, OUTPUT); + pinMode(PIN_LED_YELLOW, OUTPUT); + pinMode(PIN_LED_YELLOW2, OUTPUT); + pinMode(PIN_LED_RED, OUTPUT); + pinMode(PIN_LED_RED2, OUTPUT); + pinMode(PIN_NOISE, OUTPUT); Serial.begin(9600); - co2_sensor.setR0(100); -} + co2_sensor.setR0(300); -void printValues(float ppm, float temp, float humidity); + if (!bme.begin(0x76)) { + Serial.println(F("Could not find a valid BME280 sensor, check wiring!")); + } +} void loop() { if (count >= maxCount || count < 0) { - ppm = co2_sensor.getCO2(); + float temp = bme.readTemperature(); + float humidity = bme.readHumidity(); + ppm = co2_sensor.getCorrectedCO2(temp, humidity); count = 0; + noiseActive = false; + digitalWrite(PIN_LED_GREEN, 0); + digitalWrite(PIN_LED_GREEN2, 0); + digitalWrite(PIN_LED_YELLOW, 0); + digitalWrite(PIN_LED_YELLOW2, 0); + digitalWrite(PIN_LED_RED, 0); + digitalWrite(PIN_LED_RED2, 0); + if (ppm < 1000) { - noiseActive = false; digitalWrite(PIN_LED_GREEN, 1); - digitalWrite(PIN_LED_YELLOW, 0); - digitalWrite(PIN_LED_RED, 0); + if (ppm > 750) { + digitalWrite(PIN_LED_GREEN2, 1); + } } - else if (ppm <= 2000) { - noiseActive = false; - digitalWrite(PIN_LED_GREEN, 0); + if (ppm > 1000 && ppm <= 2000) { digitalWrite(PIN_LED_YELLOW, 1); - digitalWrite(PIN_LED_RED, 0); + if (ppm > 1500) { + digitalWrite(PIN_LED_YELLOW2, 1); + } } - else { - noiseActive = true; - digitalWrite(PIN_LED_GREEN, 0); - digitalWrite(PIN_LED_YELLOW, 0); + if (ppm > 2000) { digitalWrite(PIN_LED_RED, 1); + if (ppm > 2500) { + noiseActive = true; + digitalWrite(PIN_LED_RED2, 1); + } } + + printValues(); } if (noiseActive) { noise = !noise; - digitalWrite(PIN_NOISE, noise); + // digitalWrite(PIN_NOISE, noise); } else { - digitalWrite(PIN_NOISE, 0); + // digitalWrite(PIN_NOISE, 0); } - delay(NOISE_DELAY); + delay(100); count++; +} + +void printValues() { + float temp = bme.readTemperature(); + float humidity = bme.readHumidity(); + float ppm = co2_sensor.getCO2(); + float cppm = co2_sensor.getCorrectedCO2(temp, humidity); + Serial.print("ppm: "); + Serial.println(ppm); + Serial.print("Temperature: "); + Serial.println(temp); + Serial.print("Humidity: "); + Serial.println(humidity); + Serial.print("corrected ppm: "); + Serial.println(cppm); } \ No newline at end of file