0.2.0 MTP40C

This commit is contained in:
rob tillaart 2021-09-02 07:40:38 +02:00
parent 3d7a3feecc
commit 66a10f2a48
26 changed files with 816 additions and 163 deletions

View File

@ -2,62 +2,68 @@
// FILE: MTP40C.h
// AUTHOR: Rob Tillaart
// DATE: 2021-08-20
// VERSION: 0.1.1
// PURPOSE: Arduino library for MTP40C CO2 sensor
// VERSION: 0.2.0
// PURPOSE: Arduino library for MTP40C MTP40D CO2 sensor
// URL: https://github.com/RobTillaart/MTP40C
//
// HISTORY:
// 0.1.0 2021-08-20 initial version
// 0.1.1 2021-08-23 added examples, minor fixes
// 0.2.0 2021-08-27 added MTP40D derived class
// + many fixes after testing
#include "MTP40C.h"
// debug flag, development.
// #define MTP40C_DEBUG 1
// #define MTP40_DEBUG 1
MTP40C::MTP40C(Stream * str)
MTP40::MTP40(Stream * str)
{
_ser = str;
_buffer[0] = '\0';
}
bool MTP40C::begin(uint8_t address)
bool MTP40::begin(uint8_t address)
{
if (address > 247) return false;
_useAddress = false;
_timeout = 100;
_lastRead = 0;
_airPressure = 0;
_airPressureReference = 0;
_gasLevel = 0;
_address = address;
_suppressError = false;
return isConnected();
}
bool MTP40C::isConnected()
bool MTP40::isConnected()
{
uint8_t addr = getAddress();
return (addr == _address);
}
uint8_t MTP40C::getAddress()
uint8_t MTP40::getAddress()
{
uint8_t cmd[8] = { 0xFE, 0x03, 0x14, 0x00, 0x01, 0x00, 0x55, 0xA5 };
if (request(cmd, 8, 7) )
{
_address = _buffer[3];
return _buffer[3];
}
return MTP40C_INVALID_ADDRESS;
return MTP40_INVALID_ADDRESS;
}
bool MTP40C::setAddress(uint8_t address)
bool MTP40::setAddress(uint8_t address)
{
if (address > 247) return false;
@ -73,7 +79,7 @@ bool MTP40C::setAddress(uint8_t address)
}
float MTP40C::getAirPressure()
float MTP40::getAirPressureReference()
{
union
{
@ -81,25 +87,30 @@ float MTP40C::getAirPressure()
uint8_t b[4];
} convert;
_lastError = MTP40_OK;
// max read freq 1x per 4 seconds
if (millis() - _lastRead < 4000) return _airPressure; // last value
if (millis() - _lastRead < 4000) return _airPressureReference; // last value
_lastRead = millis();
uint8_t cmd[5] = { 0xFE, 0x68, 0x01, 0xFE, 0x30 };
if (request(cmd, 5, 10))
{
for (uint8_t i = 0; i < 3; i++)
for (uint8_t i = 0; i < 4; i++)
{
convert.b[i] = _buffer[4 + i];
}
_airPressure = convert.value;
return _airPressure;
_airPressureReference = convert.value;
return _airPressureReference;
}
return MTP40C_INVALID_AIR_PRESSURE;
_lastError = MTP40_INVALID_AIR_PRESSURE;
if (_suppressError) return _airPressureReference;
return _lastError;
}
bool MTP40C::setAirPressureReference(float apr)
bool MTP40::setAirPressureReference(float apr)
{
if ((apr < 700) || (apr > 1100)) return false;
@ -111,7 +122,7 @@ bool MTP40C::setAirPressureReference(float apr)
uint8_t cmd[10] = { 0xFE, 0x67, 0x01, 0x01, 0x00, 0x40, 0x7D, 0x44, 0xC4, 0xA3 };
convert.value = apr;
for (uint8_t i = 0; i < 3; i++)
for (uint8_t i = 0; i < 4; i++)
{
cmd[4 + i] = convert.b[i];
}
@ -123,8 +134,11 @@ bool MTP40C::setAirPressureReference(float apr)
}
uint16_t MTP40C::getGasConcentration()
uint16_t MTP40::getGasConcentration()
{
_lastError = MTP40_OK;
// max read freq 1x per 4 seconds
if (millis() - _lastRead < 4000) return _gasLevel; // last value
_lastRead = millis();
@ -140,11 +154,14 @@ uint16_t MTP40C::getGasConcentration()
_gasLevel = _buffer[5] *256 + _buffer[4];
return _gasLevel;
}
return MTP40C_INVALID_GAS_LEVEL;
_lastError = MTP40_INVALID_GAS_LEVEL;
if (_suppressError) return _gasLevel;
return _lastError;
}
bool MTP40C::setSinglePointCorrection(float spc)
bool MTP40::setSinglePointCorrection(float spc)
{
if ((spc < 400) || (spc > 5000)) return false;
@ -156,7 +173,7 @@ bool MTP40C::setSinglePointCorrection(float spc)
uint8_t cmd[9] = { 0xFE, 0x28, 0x80, 0x00, 0x80, 0x40, 0x44, 0x33, 0x22 };
convert.value = spc;
for (uint8_t i = 0; i < 3; i++)
for (uint8_t i = 0; i < 4; i++)
{
cmd[3 + i] = convert.b[i];
}
@ -168,7 +185,7 @@ bool MTP40C::setSinglePointCorrection(float spc)
}
bool MTP40C::getSinglePointCorrectionReady()
bool MTP40::getSinglePointCorrectionReady()
{
uint8_t cmd[5] = { 0xFE, 0x28, 0x81, 0xCE, 0x50 };
if (request(cmd, 5, 6) )
@ -179,7 +196,7 @@ bool MTP40C::getSinglePointCorrectionReady()
}
bool MTP40C::openSelfCalibration()
bool MTP40::openSelfCalibration()
{
uint8_t cmd[6] = { 0xFE, 0x28, 0x66, 0xFF, 0xDA, 0x24 };
if (request(cmd, 6, 6) )
@ -190,7 +207,7 @@ bool MTP40C::openSelfCalibration()
}
bool MTP40C::closeSelfCalibration()
bool MTP40::closeSelfCalibration()
{
uint8_t cmd[6] = { 0xFE, 0x28, 0x66, 0x00, 0x9A, 0x64 };
if (request(cmd, 6, 6) )
@ -201,7 +218,7 @@ bool MTP40C::closeSelfCalibration()
}
uint8_t MTP40C::getSelfCalibrationStatus()
uint8_t MTP40::getSelfCalibrationStatus()
{
uint8_t cmd[5] = { 0xFE, 0x28, 0x67, 0x4F, 0xDA };
if (request(cmd, 5, 6) )
@ -212,7 +229,7 @@ uint8_t MTP40C::getSelfCalibrationStatus()
}
bool MTP40C::setSelfCalibrationHours(uint16_t hrs)
bool MTP40::setSelfCalibrationHours(uint16_t hrs)
{
if ((hrs < 24) || (hrs > 720)) return false;
uint8_t cmd[7] = { 0xFE, 0x28, 0x6A, 0x64, 0x00, 0x0E, 0xA8 };
@ -226,7 +243,7 @@ bool MTP40C::setSelfCalibrationHours(uint16_t hrs)
}
uint16_t MTP40C::getSelfCalibrationHours()
uint16_t MTP40::getSelfCalibrationHours()
{
uint8_t cmd[5] = { 0xFE, 0x28, 0x69, 0xCE, 0x1E };
if (request(cmd, 5, 9) )
@ -237,11 +254,20 @@ uint16_t MTP40C::getSelfCalibrationHours()
}
int MTP40::lastError()
{
int e = _lastError;
_lastError = MTP40_OK;
return e;
}
//////////////////////////////////////////////////////////////////////
//
// PRIVATE
//
bool MTP40C::request(uint8_t *data, uint8_t commandLength, uint8_t answerLength)
bool MTP40::request(uint8_t *data, uint8_t commandLength, uint8_t answerLength)
{
// generic or specific address
if (_useAddress)
@ -258,7 +284,7 @@ bool MTP40C::request(uint8_t *data, uint8_t commandLength, uint8_t answerLength)
data[commandLength - 2] = crc & 0xFF;
while (commandLength--)
{
#ifdef MTP40C_DEBUG
#ifdef MTP40_DEBUG
if (*data < 0x10) _ser->print(0);
_ser->print(*data++, HEX);
_ser->print(" ");
@ -286,7 +312,7 @@ bool MTP40C::request(uint8_t *data, uint8_t commandLength, uint8_t answerLength)
// from datasheet
uint16_t MTP40C::CRC(uint8_t *data, uint16_t len)
uint16_t MTP40::CRC(uint8_t *data, uint16_t len)
{
const uint8_t auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
@ -348,4 +374,22 @@ const uint8_t auchCRCLo[] = {
}
/////////////////////////////////////////////////////////////
//
// DERIVED CLASSES
//
MTP40C::MTP40C(Stream * str) : MTP40(str)
{
_type = 2;
};
MTP40D::MTP40D(Stream * str) : MTP40(str)
{
_type = 3;
};
// -- END OF FILE --

View File

@ -3,8 +3,8 @@
// FILE: MTP40C.h
// AUTHOR: Rob Tillaart
// DATE: 2021-08-20
// VERSION: 0.1.1
// PURPOSE: Arduino library for MTP40C CO2 sensor
// VERSION: 0.2.0
// PURPOSE: Arduino library for MTP40C + MTP40D CO2 sensor
// URL: https://github.com/RobTillaart/MTP40C
//
// HISTORY:
@ -17,30 +17,36 @@
#include "Arduino.h"
#define MTP40C_LIB_VERSION (F("0.1.1"))
#define MTP40C_DEFAULT_ADDRESS 0x64
#define MTP40C_INVALID_AIR_PRESSURE 0x00
#define MTP40C_INVALID_GAS_LEVEL 0x00
#define MTP40C_INVALID_ADDRESS 0xFF
#define MTP40_LIB_VERSION (F("0.2.0"))
#define MTP40_DEFAULT_ADDRESS 0x64
class MTP40C
#define MTP40_OK 0x00
#define MTP40_INVALID_AIR_PRESSURE 0x01
#define MTP40_INVALID_GAS_LEVEL 0x02
#define MTP40_INVALID_ADDRESS 0xFF
class MTP40
{
public:
MTP40C(Stream * str);
MTP40(Stream * str);
bool begin(uint8_t address = 0x64);
bool isConnected();
uint8_t getAddress();
bool setAddress(uint8_t address);
bool setAddress(uint8_t address = 0x64); // default
float getAirPressure();
float getAirPressureReference();
bool setAirPressureReference(float apr);
uint16_t getGasConcentration(); // returns PPM
void suppressError(bool se) { _suppressError = se; };
bool getSuppressError() { return _suppressError; };
// CALIBRATION FUNCTIONS
// READ DATASHEET !!
bool setSinglePointCorrection(float spc);
@ -62,26 +68,53 @@ public:
uint32_t lastRead() { return _lastRead; };
// 2 = MTP40C 3 = MTP40D
uint8_t getType() { return _type; };
int lastError();
/////////////////////////
private:
protected:
Stream * _ser;
char _buffer[256]; // datasheet states 256 - why ???
uint8_t _buffer[24]; // should be big enough.
uint8_t _address = 64;
bool _useAddress = false;
uint32_t _timeout = 100;
uint32_t _lastRead = 0;
float _airPressure = 0;
float _airPressureReference = 0;
uint16_t _gasLevel = 0;
uint8_t _type = 0xFF;
bool _suppressError = false;
int _lastError = MTP40_OK;
bool request(uint8_t *data, uint8_t cmdlen, uint8_t anslen);
uint16_t CRC(uint8_t *data, uint16_t len);
};
/////////////////////////////////////////////////////////////
//
// DERIVED CLASSES
//
class MTP40C : public MTP40
{
public:
MTP40C(Stream * str);
};
class MTP40D : public MTP40
{
public:
MTP40D(Stream * str);
// TODO
// I2C interface
// PWM interface
};
// -- END OF FILE --

View File

@ -5,28 +5,37 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/MTP40C/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/MTP40C.svg?maxAge=3600)](https://github.com/RobTillaart/MTP40C/releases)
# MTP40C
# MTP40C / MTP40D
Arduino library for MTP40C CO2 + air pressure sensor.
Arduino library for MTP40C and MTP40D CO2 sensor.
(include image)
## Description
The library for the MTP40C CO2 sensor is experimental as not all functionality is tested.
The library for the MTP40C / MTP40D CO2 sensor is experimental as not all functionality is tested.
The MTP40C is an NDIR (Non Dispersive InfraRed) CO2 sensor.
Both the MTP40C and MTP40D sensor is an NDIR (Non Dispersive InfraRed) CO2 sensor.
The sensor communicates over a 19200 baud serial (TTL) interface with a microprocessor or PC.
This implies that calls which can take up to 25 bytes can take as much as about 20 milliseconds.
Detailed performance measurements are planned for the future.
On the other hand this low baud rate implies it will work over relative long distances.
This signal quality over longer distances is not investigated.
The MTP40D has more interface options, I2C, PWM and ALARM.
This library does not support these other interfaces for now.
However minimal examples are added to have a starter but these
need to be tested if and how well these work.
### Hardware interface
#### MTP40-C
```
// TOPVIEW
TOPVIEW MTP40-C
+-------------+---+
| | O |
Vin 1 --| +---+
@ -38,64 +47,111 @@ Detailed performance measurements are planned for the future.
+-------------+---+
```
| Pin | Description |
|:------|:--------------------|
| Vin | 4.2V--5.5V |
| GND | idem |
| TX | Transmit 19200 baud |
| RX | Receive 19200 baud |
| NC | Not Connected |
| Pin | Name | Description |
|:----:|:------|:--------------------|
| 1 | Vin | 4.2V--5.5V |
| 2 | GND | idem |
| 3 | TX | Transmit 19200 baud |
| 4 | RX | Receive 19200 baud |
| 5 | NC | Not Connected |
#### MTP40-D
```
TOPVIEW MTP40-D
+-------------+
| |
VCC 5 --| |-- 1 Vin
TX 6 --| |-- 2 GND
RX 7 --| |-- 3 ALARM
NC 8 --| |-- 4 PWM / I2C
GND 9 --| |
| |
+-------------+
```
| Pin | Name | Description |
|:----:|:--------|:----------------------------|
| 1 | Vin | 4.2V--5.5V |
| 2 | GND | idem |
| 3 | ALARM | HIGH above 2000 PPM, LOW below 1800 PPM (hysteresis) |
| 4 | PWM/I2C | PWM out or I2C select |
| 5 | VCC_O | 3V3 out for serial |
| 6 | TX | Transmit 19200 baud or SDA |
| 7 | RX | Receive 19200 baud or SCL |
| 8 | NC | Not Connected |
| 9 | GND | idem |
## Interface
### Warnings
During tests with an UNO the communication over Software Serial did fail sometimes.
Therefore it is important to **always check return values** to make your project more robust.
During tests it became clear that the sensor needs time to process
commands e.g. **setSelfCalibration()**. By having a delay(100) between the calls
everything ran far more stable (within my test). Todo seek optimum delay(), added in Future section below.
The CRC of the sensor responses are not verified by the library.
### Constructors
- **MTP40(Stream \* str)** constructor. should get a Serial port as parameter e.g. \&Serial, \&Serial1. This is the base class.
- **MTP40C(Stream \* str)** constructor. should get a Serial port as parameter e.g. \&Serial, \&Serial1
or a software Serial port. That Serial port must connect to the sensor.
- **MTP40D(Stream \* str)** constructor. should get a Serial port as parameter e.g. \&Serial, \&Serial1
or a software Serial port. That Serial port must connect to the sensor.
- **bool begin(uint8_t address = 0x64)** initialize the device.
Sets the address to communicate to the sensor. Address values allowed 0 .. 247.
Uses the factory default value of 0x64 when no parameter is given.
Also resets internal settings.
- **bool isConnected()** returns true if the address as set by **begin()** or the default address of 0x64
(decimal 100) can be found on the Serial 'bus'.
- **bool isConnected()** returns true if the address as set by **begin()**
or the default address of 0x64 (decimal 100) can be found on the Serial 'bus'.
- **uint8_t getType()** returns 2 for the MTP40C and 3 for the MTP40D sensor.
Return 255 for the MTP40 base class.
### CO2 Measurement
- **uint16_t getGasConcentration()** returns the CO2 concentration in PPM (parts per million).
The function returns **MTP40_INVALID_GAS_LEVEL** if the request fails.
- **void suppressError(bool se)** sets or clears a flag that replaces the error value 0 with the last read value if the request fails.
- **bool getSuppressError()** gets the value of the suppress flag.
- **int lastError()** returns last error set by **getGasConcentration()**
or by **getAirPressureReference()**
Reading resets lastError to MTP40_OK;
### Configuration
- **uint8_t getAddress()** request the address from the device.
Expect a value from 0 .. 247.
Returns **MTP40C_INVALID_ADDRESS** (0xFF) if the request fails.
- **bool setAddress(uint8_t address)** set a new address for the device.
Returns false if not successful. If set this specific address will be used for the commands.
Returns **MTP40_INVALID_ADDRESS** (0xFF) if the request fails.
- **bool setAddress(uint8_t address = 0x64)** set a new address for the device.
0x64 as default. Returns false if not successful.
If **setSpecificAddress()** is called, this specific address will be used for further commands.
These address functions are only needed if handling multiple devices. (to be tested)
- **void setGenericAddress()** uses the broadcast address 0xFE in all requests. This is the default behaviour of the library.
- **void setSpecificAddress()** uses the address specified in **begin()** or **setAddress()** or the default 0x64
in all requests.
- **void setGenericAddress()** uses the broadcast address 0xFE in all requests.
This is the default behaviour of the library.
- **void setSpecificAddress()** uses the address specified in **begin()** or
**setAddress()** or the default 0x64 in all requests.
- **bool useSpecificAddress()** returns true if the specific address is used.
Returns false if the generic / broadcast address is used.
The MTP40C library can set a maximum timeout in the communication with the sensor.
Normally this is not needed to set as the default of 100 milliseconds is long enough.
- **void setTimeout(uint32_t to = 100)** sets the timeout. If no parameter is given a default timeout of 100 milliseconds is set.
- **uint32_t getTimeout()** get the value set above or the default. Value returned is time in milliseconds.
### Measurements
- **float getAirPressure()** returns the air pressure from the device.
Returns **MTP40C_INVALID_AIR_PRESSURE** (0) in case request fails.
- **bool setAirPressureReference(float apr)** to calibrate the air pressure one can calibrate
the sensor with an external device.
Value should between 700.0 and 1100.0.
The function returns **false** if the parameter is out of range or if the request fails.
- **uint16_t getGasConcentration()** returns the CO2 concentration in PPM (parts per million).
The function returns **MTP40C_INVALID_GAS_LEVEL** (0) if the request fails.
Note: there is no **getAirPressureReference()** command documented.
The library can set a maximum timeout in the communication with the sensor.
Normally this is not needed to set as the default of 100 milliseconds is long enough
for even the longest command. This timeout is needed if the sensor did not read the
command correctly, preventing the host to wait indefinitely.
- **void setTimeout(uint32_t to = 100)** sets the timeout.
If no parameter is given a default timeout of 100 milliseconds is set.
- **uint32_t getTimeout()** get the value set above or the default.
Value returned is time in milliseconds.
### Calibration
@ -103,6 +159,17 @@ Note: there is no **getAirPressureReference()** command documented.
Please read datasheet before using these functions to understand the process of calibration.
#### Air pressure calibration
- **float getAirPressureReference()** returns the air pressure reference from the device.
Returns **MTP40_INVALID_AIR_PRESSURE** in case request fails.
Default is 1013.0.
- **bool setAirPressureReference(float apr)** to calibrate the air pressure.
One can calibrate the sensor with an external device.
Value for air pressure should between 700.0 and 1100.0.
The function returns **false** if the parameter is out of range or if the request fails.
#### SPC calibration
This takes a relative short time (few minutes) to calibrate the sensor in a known
@ -119,12 +186,14 @@ As far as known the SPC point can not be retrieved from the sensor.
#### Self calibration
Self calibration is a process in which the sensor takes the minimum values over a longer period
between 24 - 720 hours as the reference for minimum outdoor values. (CHECK).
between 24 - 720 hours as the reference for minimum outdoor values.
Note that 720 hours is 30 days / 1 month.
- **bool openSelfCalibration()** start the self calibration cycle. CHECK
- **bool closeSelfCalibration()** stop the self calibration cycle. CHECK
- **uint8_t getSelfCalibrationStatus()** CHECK.
- **bool openSelfCalibration()** start the self calibration cycle.
- **bool closeSelfCalibration()** stop the self calibration cycle.
- **uint8_t getSelfCalibrationStatus()** Returns if the selfCalibration is open or closed.
**WARNING**: in our test the values in the datasheet seems to be not in sync with the sensor used.
The function returned **0x00 for CLOSED and 0xFF for OPEN**.
- **bool setSelfCalibrationHours(uint16_t hrs)** Sets the number of hours between self calibration
moments. Valid values are 24 - 720 .
- **uint16_t getSelfCalibrationHours()** returns the value set above.
@ -132,14 +201,21 @@ moments. Valid values are 24 - 720 .
## Future
- test test test test
#### CRC
- CRC in PROGMEM
- CRC test responses sensor
#### Performance
- performance measurements
- optimize performance
- optimize memory usage (buffer)
- optimize performance if possible
- caching? what?
- seek optimum delay() between calls.
#### Other
- serial bus with multiple devices? => diodes
- add improved error handling. e.g. **MTP40C_REQUEST_FAILS**
## Operations

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -12,18 +12,21 @@
#include "MTP40C.h"
#include "SoftwareSerial.h"
MTP40C mtp(&Serial1);
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws);
void setup()
{
Serial.begin(19200);
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MTP40C_LIB_VERSION:\t");
Serial.println(MTP40C_LIB_VERSION);
Serial.print("MTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
sws.begin(19200);
if (mtp.begin(248) == false) // must fail!
{
Serial.println("OK 248");
@ -36,12 +39,12 @@ void setup()
Serial.println(addr);
Serial.println();
Serial.println();
mtp.setAddress(0x10);
Serial.println();
mtp.setAddress(0x20);
Serial.println();
mtp.setAddress(0x30);
// Serial.println(mtp.setAddress(0x10));
// Serial.println(mtp.setAddress(0x20));
// Serial.println(mtp.setAddress(0x30));
mtp.setSpecificAddress();
Serial.println(mtp.setAddress()); // reset to default
Serial.println("\ndone");
}

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -12,19 +12,24 @@
#include "MTP40C.h"
#include "SoftwareSerial.h"
MTP40C mtp(&Serial1);
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws);
// MTP40C mtp(&Serial1);
int lines = 10;
void setup()
{
Serial.begin(19200);
Serial.begin(115200);
// Serial.println(__FILE__);
// Serial.print("MTP40C_LIB_VERSION:\t");
// Serial.println(MTP40C_LIB_VERSION);
// Serial.print("MTP40_LIB_VERSION:\t");
// Serial.println(MTP40_LIB_VERSION);
sws.begin(19200);
mtp.begin(); // default 0x64
// if (mtp.begin() == false)

View File

@ -22,8 +22,8 @@ void setup()
// DEBUG SERIAL
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MTP40C_LIB_VERSION:\t");
Serial.println(MTP40C_LIB_VERSION);
Serial.print("MTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
// SERIAL OF MTP40C SENSOR
sws.begin(19200);

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -14,20 +14,22 @@
#include "MTP40C.h"
#include "SoftwareSerial.h"
SoftwareSerial sws(6, 7);
MTP40C mtp(&Serial1); // use hardware Serial1 for MTP40C sensor
MTP40C mtp(&sws); // use hardware Serial1 for MTP40C sensor
void setup()
{
Serial.begin(115200);
// Serial.println(__FILE__);
// Serial.print("MTP40C_LIB_VERSION:\t");
// Serial.println(MTP40C_LIB_VERSION);
// Serial.print("MTP40_LIB_VERSION:\t");
// Serial.println(MTP40_LIB_VERSION);
Serial1.begin(19200);
mtp.begin(MTP40C_DEFAULT_ADDRESS); // default 0x64
sws.begin(19200);
mtp.begin(MTP40_DEFAULT_ADDRESS); // default 0x64
// if (mtp.begin() == false)
// {

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -0,0 +1,59 @@
//
// FILE: MTP40C_getPressureReference.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo of MTP40C library
// DATE: 2021-08-21
// URL: https://github.com/RobTillaart/MTP40C
//
// any board that support two or more hardware serial ports
// Serial and Serial1, e.g. for MEGA, LEONARDO, MICRO, ESP32,ESP8266
// Uno, Nano or Mini will fail to compile.
#include "MTP40C.h"
#include "SoftwareSerial.h"
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws);
// MTP40C mtp(&Serial1);
int lines = 10;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
sws.begin(19200);
if (mtp.begin(0x64) == false)
{
Serial.println("Could not connect!");
while(1);
}
}
void loop()
{
if (lines == 10)
{
lines = 0;
Serial.println("\nTIME\tPRESSURE (mbar)");
}
if (millis() - mtp.lastRead() >= 5000)
{
Serial.print(millis());
Serial.print("\t");
Serial.print(mtp.getAirPressureReference(), 1);
Serial.println();
lines++;
}
}
// -- END OF FILE --

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -12,8 +12,11 @@
#include "MTP40C.h"
#include "SoftwareSerial.h"
MTP40C mtp(&Serial1);
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws);
// MTP40C mtp(&Serial1);
uint32_t start;
@ -23,35 +26,48 @@ void setup()
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MTP40C_LIB_VERSION:\t");
Serial.println(MTP40C_LIB_VERSION);
Serial.print("MTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
Serial1.begin(19200);
mtp.begin(MTP40C_DEFAULT_ADDRESS);
sws.begin(19200);
mtp.begin(MTP40_DEFAULT_ADDRESS);
Serial.print("STAT:\t");
Serial.println(mtp.getSelfCalibrationStatus());
delay(100);
Serial.print("OPEN:\t");
Serial.println(mtp.openSelfCalibration());
delay(100);
Serial.print("STAT:\t");
Serial.println(mtp.getSelfCalibrationStatus());
delay(100);
Serial.print("CLOSE:\t");
Serial.println(mtp.closeSelfCalibration());
delay(100);
Serial.print("STAT:\t");
Serial.println(mtp.getSelfCalibrationStatus());
delay(100);
Serial.print("OPEN:\t");
Serial.println(mtp.openSelfCalibration());
delay(100);
Serial.print("STAT:\t");
Serial.println(mtp.getSelfCalibrationStatus());
delay(100);
Serial.println();
Serial.print("GET_HRS:\t");
uint16_t hrs = mtp.getSelfCalibrationHours();
Serial.println(hrs);
delay(100);
if (hrs > 720) hrs = 23;
Serial.print("SET_HRS:\t");
Serial.println(mtp.setSelfCalibrationHours(hrs + 1));
delay(100);
Serial.print("GET_HRS:\t");
Serial.println(mtp.getSelfCalibrationHours());
delay(100);
Serial.println("\ndone...");
}

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -0,0 +1,76 @@
//
// FILE: MTP40C_setPressureReference.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo of MTP40C library
// DATE: 2021-08-21
// URL: https://github.com/RobTillaart/MTP40C
//
// any board that support two or more hardware serial ports
// Serial and Serial1, e.g. for MEGA, LEONARDO, MICRO, ESP32,ESP8266
// Uno, Nano or Mini will fail to compile.
#include "MTP40C.h"
#include "SoftwareSerial.h"
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws);
// MTP40C mtp(&Serial1);
int lines = 10;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
sws.begin(19200);
if (mtp.begin(0x64) == false)
{
Serial.println("Could not connect!");
while (1);
}
Serial.print("990:\t");
Serial.println(mtp.setAirPressureReference(990.0));
delay(5000);
Serial.println(mtp.getAirPressureReference(), 1);
delay(100);
Serial.print("1013:\t");
Serial.println(mtp.setAirPressureReference(1013.0));
delay(5000);
Serial.println(mtp.getAirPressureReference(), 1);
delay(100);
}
void loop()
{
if (lines == 10)
{
lines = 0;
Serial.println("\nTIME\tPRESSURE (mbar)");
}
if (millis() - mtp.lastRead() >= 5000)
{
Serial.print(millis());
Serial.print("\t");
Serial.print(mtp.getAirPressureReference(), 1);
Serial.println();
lines++;
}
}
// -- END OF FILE --

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -12,8 +12,11 @@
#include "MTP40C.h"
#include "SoftwareSerial.h"
MTP40C mtp(&Serial1);
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws);
// MTP40C mtp(&Serial1);
uint32_t start;
@ -23,14 +26,14 @@ void setup()
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("MTP40C_LIB_VERSION:\t");
Serial.println(MTP40C_LIB_VERSION);
Serial.print("MTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
Serial1.begin(19200);
mtp.begin(MTP40C_DEFAULT_ADDRESS);
sws.begin(19200);
mtp.begin(MTP40_DEFAULT_ADDRESS);
Serial.println("Set air pressure to: ");
Serial.setTimeout(3000); // default is 1000 which is rather small.
Serial.println("Set CO2 level to: 400-5000");
Serial.setTimeout(10000); // default is 1000 which is rather small.
float spc = Serial.parseFloat(); // reads until carriage return
Serial.println(spc, 1);
@ -51,11 +54,17 @@ void setup()
}
if (millis() - start > 600000UL) // 600 seconds = 10 minutes
{
Serial.println("took > 10 minutes, something went wrong");
Serial.println();
Serial.println("took > 10 minutes, something went wrong?");
break;
}
}
}
else
{
Serial.println("could not set value");
}
Serial.println();
Serial.print("TIME: \t");
Serial.println(millis() - start);
Serial.println("\ndone");

View File

@ -0,0 +1,75 @@
//
// FILE: MTP40D_I2C_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo of MTP40D I2C interface
// DATE: 2021-08-27
// URL: https://github.com/RobTillaart/MTP40C
//
// TODO TEST WITH SENSOR
// do not expect this to work yet
#include "Wire.h"
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
}
void loop()
{
uint16_t ppm = readMTP40D(0x62);
Serial.print("PPM: ");
Serial.println(ppm);
delay(4000);
}
////////////////////////////////////////////////////////////////////////////
//
// MINIMAL I2C READ
//
/*
Timing sequence of the master:
1. Send a start signal;
2. Send an address to write(slave address + R/W=0x62) and check responses;
3. Send a read command (0x52) and check the responses;
4. Send a stop signal;
5. Send a start signal;
6. Send an address to read (slave address + R/W(1) =0x63) and check responses;
7. Read 7 bytes from the module and send responses;
8. Send a stop signal.
*/
uint16_t readMTP40D(uint8_t address)
{
Wire.beginTransmission(address);
Wire.write(0x52);
if (Wire.endTransmission() != 0) return 0;
if (Wire.requestFrom(address + 1, 7) == 7)
{
// read 0x08
Wire.read();
uint16_t ppm = Wire.read() * 256;
ppm += Wire.read();
// read 4x 0x00
Wire.read();
Wire.read();
Wire.read();
Wire.read();
return ppm;
}
return 0;
}
// -- END OF FILE --

View File

@ -0,0 +1,63 @@
//
// FILE: MTP40D_PWM_demo.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo of MTP40D PWM interface
// DATE: 2021-08-27
// URL: https://github.com/RobTillaart/MTP40C
//
// TODO TEST WITH MTP40D SENSOR
//
// Connect the PWM output to the interrup pin 2 or 3 of the UNO.
// other processors interrupts pins work slightly different
volatile uint32_t start = 0;
volatile uint16_t duration = 0;
uint8_t interruptPin = 3;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), mtp40D_irq, CHANGE);
}
void loop()
{
uint16_t d = duration;
uint16_t ppm = duration2PPM(d);
Serial.print(d);
Serial.print("\t");
Serial.println(ppm);
delay(2000);
}
////////////////////////////////////////////////////////////////////////////
//
// PWM CAPTURE IRQ + CONVERSION FUNCTION
//
void mtp40D_irq()
{
if (digitalRead(interruptPin) == HIGH) start = millis();
else duration = millis() - start;
}
// ppm == 0 is a pulselengtm of 2000 micros.
// every 10 ppm adds 2000 micros
// 1002000 micros = 5000 ppm
uint16_t duration2PPM(uint16_t d)
{
return ((duration - 1) >> 1 ) * 10;
}
// -- END OF FILE --

View File

@ -0,0 +1,7 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- leonardo
# - due
# - zero

View File

@ -0,0 +1,106 @@
//
// FILE: MTP40_scanner.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// PURPOSE: demo of MTP40C library
// DATE: 2021-08-21
// URL: https://github.com/RobTillaart/MTP40C
//
// any board that support two or more hardware serial ports
// Serial and Serial1, e.g. for MEGA, LEONARDO, MICRO, ESP32,ESP8266
// Uno, Nano or Mini will fail to compile.
#include "MTP40C.h"
#include "SoftwareSerial.h"
SoftwareSerial sws(6, 7);
MTP40C mtp(&sws); // use hardware Serial1 for MTP40C sensor
void setup()
{
Serial.begin(115200);
delay(100);
Serial.println();
Serial.println(__FILE__);
Serial.print("\tMTP40_LIB_VERSION:\t");
Serial.println(MTP40_LIB_VERSION);
Serial.println();
Serial.println("\tMTP40 ADDRESS SCANNER 0.1.1");
sws.begin(19200);
mtp.setTimeout(50);
uint32_t start = millis();
full_scan();
Serial.print("Time ms:\t");
Serial.println(millis() - start);
start = millis();
detect_scan();
Serial.print("Time ms:\t");
Serial.println(millis() - start);
Serial.println("\ndone");
}
void loop()
{
}
void full_scan()
{
Serial.println();
uint8_t found = 0;
for (int addr = 0; addr < 248; addr += 16)
{
Serial.println();
Serial.print("0x");
if (addr < 0x10) Serial.print('0');
Serial.print(addr, HEX);
for (uint8_t i = 0; i < 16; i++)
{
Serial.print("\t");
bool b = mtp.begin(addr + i);
Serial.print(b);
if (b) found++;
}
}
Serial.println();
Serial.println();
Serial.print("Devices:\t");
Serial.println(found);
}
void detect_scan()
{
Serial.println();
uint8_t found = 0;
for (int addr = 0; addr < 248; addr++)
{
bool b = mtp.begin(addr);
if (b)
{
Serial.print("Address:\t0x");
if (addr < 0x10) Serial.print('0');
Serial.print(addr, HEX);
Serial.print("\t");
found++;
}
}
Serial.println();
Serial.print("Devices:\t");
Serial.println(found);
}
// -- END OF FILE --

View File

@ -1,19 +1,26 @@
# Syntax Colouring Map For MTP40C
# Data types (KEYWORD1)
MTP40 KEYWORD1
MTP40C KEYWORD1
MTP40D KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
isConnected KEYWORD2
getAddress KEYWORD2
setAddress KEYWORD2
getAirPressure KEYWORD2
getAirPressureReference KEYWORD2
setAirPressureReference KEYWORD2
getGasConcentration KEYWORD2
suppressError KEYWORD2
getSuppressError KEYWORD2
setSinglePointCorrection KEYWORD2
getSinglePointCorrectionReady KEYWORD2
@ -30,12 +37,19 @@ useSpecificAddress KEYWORD2
setTimeout KEYWORD2
getTimeout KEYWORD2
lastRead KEYWORD2
getType KEYWORD2
lastError KEYWORD2
# Constants (LITERAL1)
MTP40C_LIB_VERSION LITERAL1
MTP40C_DEFAULT_ADDRESS LITERAL1
MTP40C_INVALID_AIR_PRESSURE LITERAL1
MTP40C_INVALID_GAS_LEVEL LITERAL1
MTP40C_INVALID_ADDRESS LITERAL1
MTP40_LIB_VERSION LITERAL1
MTP40_OK LITERAL1
MTP40_DEFAULT_ADDRESS LITERAL1
MTP40_INVALID_AIR_PRESSURE LITERAL1
MTP40_INVALID_GAS_LEVEL LITERAL1
MTP40_INVALID_ADDRESS LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "MTP40C",
"keywords": "MTP40C, CO2, air pressure, serial",
"description": "Arduino library for MTP40C CO2 + air pressure sensor",
"keywords": "MTP40, MTP40C, MTP40D, CO2, serial",
"description": "Arduino library for MTP40, MTP40C + MTP40D CO2 sensor",
"authors":
[
{
@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/MTP40C.git"
},
"version": "0.1.1",
"version": "0.2.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*"

View File

@ -1,8 +1,8 @@
name=MTP40C
version=0.1.1
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for MTP40C CO2 + air pressure sensor
sentence=Arduino library for MTP40, MTP40C and MTP40D CO2 sensor
paragraph=
category=Sensors
url=https://github.com/RobTillaart/MTP40C

View File

@ -38,7 +38,7 @@
// MANY TESTS WILL BLOCK AS BUILD CI HAS NO GOOD TIMEOUT
// ALL FAILING TESTS ARE COMMENTED
//
// USE GODMODE SERIAL TO IMPROVE THESE TESTS LATER
// USE GODMODE SERIAL TO IMPROVE THESE TESTS
//
#include <ArduinoUnitTests.h>
@ -58,9 +58,25 @@ unittest_teardown()
}
unittest(test_getType)
{
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensorC = MTP40C(&Serial);
assertEqual(2, sensorC.getType());
MTP40D sensorD = MTP40D(&Serial);
assertEqual(3, sensorD.getType());
MTP40 sensor = MTP40(&Serial);
assertEqual(255, sensor.getType());
}
unittest(test_begin)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
@ -76,7 +92,7 @@ unittest(test_begin)
unittest(test_address)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
// assertTrue(sensor.begin()); blocks!
@ -92,12 +108,12 @@ unittest(test_address)
unittest(test_air_pressure)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
// assertTrue(sensor.begin()); // default address
// assertEqual(-999, sensor.getAirPressure());
// assertEqual(-999, sensor.getAirPressureReference());
assertFalse(sensor.setAirPressureReference(600.0));
assertFalse(sensor.setAirPressureReference(1200.0));
@ -107,7 +123,7 @@ unittest(test_air_pressure)
unittest(test_gas_concentration)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
// assertTrue(sensor.begin());
@ -118,7 +134,7 @@ unittest(test_gas_concentration)
unittest(test_single_point_correction)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
// assertTrue(sensor.begin());
@ -133,7 +149,7 @@ unittest(test_single_point_correction)
unittest(test_self_calibration)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
// assertTrue(sensor.begin()); // default address
@ -146,7 +162,7 @@ unittest(test_self_calibration)
unittest(test_self_calibration_hours)
{
fprintf(stderr, "MTP40C_LIB_VERSION:\t%s\n", MTP40C_LIB_VERSION);
fprintf(stderr, "MTP40_LIB_VERSION:\t%s\n", MTP40_LIB_VERSION);
MTP40C sensor = MTP40C(&Serial);
// assertTrue(sensor.begin()); // default address