0.2.1 MHZCO2

This commit is contained in:
Rob Tillaart 2024-09-02 20:21:08 +02:00
parent a1e696709e
commit f4b74b6d23
10 changed files with 239 additions and 34 deletions

View File

@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.1] - 2024-09-02
- merge #11, update lastMeasurement only if read is successful (kudos JonNelson)
- add **void setTimeOut(uint16_t timeout = 1000)** to configure timeout
- add **uint16_t getTimeOut()**
- add example **MHZCO2_sw_serial_timeout.ino**.
- update unit tests
- update readme.md
- minor edits
## [0.2.0] - 2023-12-29
- Fix #9 bug in **setPPM()**
- fix race condition in **receive()**

View File

@ -1,7 +1,7 @@
//
// FILE: MHZCO2.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// PURPOSE: Arduino Library for MHZ series CO2 sensors
// DATE: 2020-05-05
// URL: https://github.com/RobTillaart/MHZCO2
@ -20,6 +20,7 @@ void MHZCO2::begin(Stream * str)
{
_str = str;
_lastMeasurement = 0;
_timeout = 1000;
_PPM = 0;
_CO2 = 0;
_temperature = 0;
@ -56,8 +57,6 @@ uint16_t MHZCO2::getPPM()
int MHZCO2::measure()
{
_lastMeasurement = millis();
uint8_t data[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
data[8] = checksum(data);
send(data, 9);
@ -71,7 +70,10 @@ int MHZCO2::measure()
_accuracy = data[5];
_minCO2 = data[6] * 256 + data[7];
}
if (rv == MHZCO2_OK)
{
_lastMeasurement = millis();
}
return rv;
}
@ -133,6 +135,19 @@ void MHZCO2::calibrateAuto(bool mode)
}
void MHZCO2::setTimeOut(uint16_t timeout)
{
_timeout = timeout;
}
uint16_t MHZCO2::getTimeOut()
{
return _timeout;
}
/////////////////////////////////////////////////
//
// PROTECTED
@ -159,12 +174,18 @@ int MHZCO2::receive(uint8_t * answer)
}
else
{
// note: hardcoded timeout
if (millis() - start > 1000) return MHZCO2_TIMEOUT;
// default _timeout = 1000
if ((_timeout > 0) && (millis() - start > _timeout))
{
return MHZCO2_TIMEOUT;
}
}
}
// verify checksum
if (answer[8] != checksum(answer)) return MHZCO2_ERROR_CRC;
if (answer[8] != checksum(answer))
{
return MHZCO2_ERROR_CRC;
}
return MHZCO2_OK;
}

View File

@ -2,7 +2,7 @@
//
// FILE: MHZCO2.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// PURPOSE: Arduino Library for MHZ series CO2 sensors
// DATE: 2020-05-05
// URL: https://github.com/RobTillaart/MHZCO2
@ -10,7 +10,7 @@
#include "Arduino.h"
#define MHZCO2_LIB_VERSION (F("0.2.0"))
#define MHZCO2_LIB_VERSION (F("0.2.1"))
#define MHZCO2_OK 0
#define MHZCO2_TIMEOUT -10
@ -47,11 +47,18 @@ public:
void calibrateSpan(uint16_t span);
void calibrateAuto(bool mode = true);
// default = 1000 millisecond
// depending on baud rate (9600) low values may fail
// 0 means no time ut check.
void setTimeOut(uint16_t timeout = 1000);
uint16_t getTimeOut();
protected:
Stream * _str;
uint32_t _startTime;
uint32_t _lastMeasurement;
Stream * _str = NULL;
uint32_t _startTime = 0;
uint32_t _lastMeasurement = 0;
uint16_t _timeout = 1000;
uint16_t _PPM = 0;
int _CO2 = 0;

View File

@ -25,12 +25,19 @@ This might change in the future as compatibles might differ on detail.
Reference: user manual MHZ129B 2019-04-25 version 1.4
#### Version 0.2.0
### Version 0.2.1
Minor breaking change as **Measure()** will only update lastMeasurement
in case the measurement was successful. See #11.
### Version 0.2.0
Version 0.2.0 fixes a bug in **setPPM()** which makes older versions obsolete.
#### Compatibles
### Compatibles
This list is not verified although these devices should be compatible based upon datasheet.
@ -60,7 +67,7 @@ If there are compatible devices missing in this list, please let me know.
In previous versions the MTP40F was incorrectly mentioned as compatible.
#### Links
### Related
- https://emariete.com/en/sensor-co2-mh-z19b/
- https://emariete.com/en/sensor-co2-low-consumption-mh-z1311a-winsen/
@ -83,44 +90,61 @@ In previous versions the MTP40F was incorrectly mentioned as compatible.
#include "MHZCO2.h"
```
#### Constructor
### Constructor
- **MHZCO2()** base class constructor.
- **MHZ19()** constructor. Also 19B, C, D, E
- **void begin(Stream \* str)** set the Serial port to use, e.g Serial1,
or a softwareSerial port.
**begin()** also resets all internal variables.
- **uint32_t uptime()** returns milliseconds since 'instantiation'.
#### Range
### Range
- **void setPPM(uint16_t PPM)** PPM = 2000, 5000, 10000.
- **uint16_t getPPM()** returns (cached) PPM value.
To set the max range of the actual sensor.
- **void setPPM(uint16_t PPM)** PPM = 2000, 5000, 10000.
The value set is persistent over reboots (see issue #9).
- **uint16_t getPPM()** returns the cached PPM value.
Note: initially this function returns zero / 0 as the cache is not
filled by **setPPM()** yet.
#### Measure
### Measure
- **int measure()** workhorse, send command to read the sensor and
waits until an answer is received. Return values see below.
Will only update lastMeasurement if the measurement is successful (0.2.1)
- **uint32_t lastMeasurement()** timestamp in milliseconds of last measurement.
- **int getCO2()** returns CO2 PPM last measurement.
- **int getTemperature()** returns temperature last measurement.
Note that the temperature can be negative.
- **int getAccuracy()** returns accuracy last measurement.
Note: check datasheet.
- **int getMinCO2()** returns minCO2 last measurement.
The latter two might not be supported by all MH sensors.
Return values of **measure()**
#### Return values of **measure()**
| value | Name | Description |
|:-------:|:------------------:|:--------------|
| 0 | MHZCO2_OK | measurement succeeded.
| -10 | MHZCO2_TIMEOUT | to too long to receive an answer
| -10 | MHZCO2_TIMEOUT | took too long to receive an answer.
| -11 | MHZCO2_ERROR_CRC | Checksum error, handle answer with care.
#### Calibration
#### CRC error
In case of an checksum error the values received may be corrupted.
Best strategy is to ignore the measurement. However this is not always
possible so a strategy might be to compare the values of the measurement
with the previous ones.
Often one can determine the failing ones but definitely not always.
### Calibration
**WARNING:** use with care, read the datasheet as these commands may disrupt your sensor.
@ -137,6 +161,23 @@ The University of San Diego keeps track of CO2 for a long time now.
See - https://keelingcurve.ucsd.edu/
### Timeout
These functions are used to set the default timeout in the receive function.
The faster the baud rate used, the smaller this value can be. As the **receive()**
call has to read 9 bytes at (default) 9600 baud. This is max 1 character per
millisecond. To receive 9 bytes one needs therefore at least 10 to 15 milliseconds
under ideal circumstances. So setting the timeout lower makes little sense.
If the timeout is set to zero / 0 there will be no time out checking.
Use with care!
- **void setTimeOut(uint16_t timeout = 1000)** set the stream reading timeout,
defaults to 1000 milliseconds.
- **uint16_t getTimeOut()** returns the set stream reading timeout.
## Future
#### Must
@ -146,22 +187,25 @@ See - https://keelingcurve.ucsd.edu/
- test with hardware
- verify timeout
#### Should
- check 3000 PPM
- fix SoftwareSerial - https://github.com/Arduino-CI/arduino_ci/issues/346
- check 5000 and 10000 PPM and possible others?
- is there an effect on the PWM output.
- should the PPM be a parameter of the constructor?
- default to 2000? or model based?
#### Could
- investigate configurable timeout. now hardcoded 1 second.
- 2 bytes + 2 functions.
- extend unit tests
- add type info for derived classes?
- A .. E ?
- save RAM? possible?
- all arrays start with 0xFF, 0x01
- reduce data types?
- **uint16_t send()** could return bytes send?
- would allow higher level functions to check.
- add **int maxCO2()** by keeping track myself?
- extend unit tests if needed.
- fix SoftwareSerial - https://github.com/Arduino-CI/arduino_ci/issues/346
#### Won't

View File

@ -0,0 +1,31 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
# - uno
# - due
# - zero
# - leonardo
# - m4
# - esp32
# - esp8266
# - mega2560
# - rpipico
# external libraries
libraries:
# - "SoftwareSerial" does not work

View File

@ -0,0 +1,55 @@
//
// FILE: MHZCO2_sw_serial_timeout.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// DATE: 2020-09-01
#include "SoftwareSerial.h"
#include "Arduino.h"
#include "MHZCO2.h"
const int TX = 4;
const int RX = 5;
SoftwareSerial ss(TX, RX);
MHZ19B MHZ19B;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MHZCO2_LIB_VERSION: ");
Serial.println(MHZCO2_LIB_VERSION);
MHZ19B.begin(&ss);
ss.begin(9600);
MHZ19B.setTimeOut(200);
}
void loop()
{
int rv = MHZ19B.measure();
Serial.print("Meas: ");
Serial.println(rv); // 0 = OK, -10 = timeout, -11 = CRC
Serial.print("CO2: ");
Serial.println(MHZ19B.getCO2());
Serial.print("MCO2: ");
Serial.println(MHZ19B.getMinCO2());
Serial.print("Temp: ");
Serial.println(MHZ19B.getTemperature());
Serial.print("Accu: ");
Serial.println(MHZ19B.getAccuracy());
Serial.println();
delay(1000);
}
// -- END OF FILE --

View File

@ -28,6 +28,9 @@ calibrateZero KEYWORD2
calibrateSpan KEYWORD2
calibrateAuto KEYWORD2
setTimeout KEYWORD2
getTimeout KEYWORD2
# Constants (LITERAL1)
MHZCO2_LIB_VERSION LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/MHZCO2.git"
},
"version": "0.2.0",
"version": "0.2.1",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=MHZCO2
version=0.2.0
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino Library for MHZ series CO2 sensors.

View File

@ -54,6 +54,41 @@ unittest(test_constructor)
}
unittest(test_functions_no_measurement)
{
MHZCO2 A;
A.begin(&Serial);
// verify default
assertEqual(0, A.getPPM());
assertEqual(0, A.getCO2());
assertEqual(0, A.getTemperature());
assertEqual(0, A.getAccuracy());
assertEqual(0, A.getMinCO2());
}
unittest(test_timeout)
{
MHZCO2 A;
A.begin(&Serial);
// verify default
assertEqual(1000, A.getTimeOut());
// just a value
A.setTimeOut(2000);
assertEqual(2000, A.getTimeOut());
// zero should work.
A.setTimeOut(0);
assertEqual(0, A.getTimeOut());
// default parameter
A.setTimeOut();
assertEqual(1000, A.getTimeOut());
}
unittest_main()