0.3.1 AGS02MA

This commit is contained in:
rob tillaart 2022-08-12 12:15:08 +02:00
parent 2b00021ae6
commit a393271f22
9 changed files with 182 additions and 45 deletions

View File

@ -2,7 +2,7 @@
// FILE: AGS02MA.cpp
// AUTHOR: Rob Tillaart, Viktor Balint, Beanow
// DATE: 2021-08-12
// VERSION: 0.3.0
// VERSION: 0.3.1
// PURPOSE: Arduino library for AGS02MA TVOC
// URL: https://github.com/RobTillaart/AGS02MA
@ -53,12 +53,17 @@ bool AGS02MA::begin()
bool AGS02MA::isConnected()
{
#if defined (__AVR__)
TWBR = 255;
// TWBR = 255; // == 30.4 KHz with TWSR = 0x00
TWBR = 78; // == 25.0 KHZ
TWSR = 0x01; // prescaler = 4
#else
_wire->setClock(AGS02MA_I2C_CLOCK);
#endif
_wire->beginTransmission(_address);
bool rv = ( _wire->endTransmission(true) == 0);
#if defined (__AVR__)
TWSR = 0x00;
#endif
_wire->setClock(_I2CResetSpeed);
return rv;
}
@ -243,6 +248,7 @@ int AGS02MA::lastError()
return e;
}
bool AGS02MA::readRegister(uint8_t address, AGS02MA::RegisterData &reg) {
if (!_readRegister(address))
{
@ -293,17 +299,25 @@ bool AGS02MA::_readRegister(uint8_t reg)
while (millis() - _lastRegTime < 30) yield();
#if defined (__AVR__)
TWBR = 255;
// TWBR = 255; // == 30.4 KHz with TWSR = 0x00
TWBR = 78; // == 25.0 KHZ
TWSR = 0x01; // prescaler = 4
#else
_wire->setClock(AGS02MA_I2C_CLOCK);
#endif
_wire->beginTransmission(_address);
_wire->write(reg);
_error = _wire->endTransmission(true);
// TODO investigate async interface
delay(30);
if (_wire->requestFrom(_address, (uint8_t)5) != 5)
{
_error = AGS02MA_ERROR_READ;
#if defined (__AVR__)
TWSR = 0x00; // reset prescaler = 1
#endif
_wire->setClock(_I2CResetSpeed);
return false;
}
@ -311,6 +325,9 @@ bool AGS02MA::_readRegister(uint8_t reg)
{
_buffer[i] = _wire->read();
}
#if defined (__AVR__)
TWSR = 0x00; // reset prescaler = 1
#endif
_wire->setClock(_I2CResetSpeed);
return true;
}
@ -322,7 +339,9 @@ bool AGS02MA::_writeRegister(uint8_t reg)
_lastRegTime = millis();
#if defined (__AVR__)
TWBR = 255;
// TWBR = 255; // == 30.4 KHz with TWSR = 0x00
TWBR = 78; // == 25.0 KHZ
TWSR = 0x01; // prescaler = 4
#else
_wire->setClock(AGS02MA_I2C_CLOCK);
#endif
@ -333,6 +352,9 @@ bool AGS02MA::_writeRegister(uint8_t reg)
_wire->write(_buffer[i]);
}
_error = _wire->endTransmission(true);
#if defined (__AVR__)
TWSR = 0x00;
#endif
_wire->setClock(_I2CResetSpeed);
return (_error == 0);
}

View File

@ -3,7 +3,7 @@
// FILE: AGS02MA.h
// AUTHOR: Rob Tillaart, Viktor Balint, Beanow
// DATE: 2021-08-12
// VERSION: 0.3.0
// VERSION: 0.3.1
// PURPOSE: Arduino library for AGS02MA TVOC
// URL: https://github.com/RobTillaart/AGS02MA
//
@ -13,7 +13,7 @@
#include "Wire.h"
#define AGS02MA_LIB_VERSION (F("0.3.0"))
#define AGS02MA_LIB_VERSION (F("0.3.1"))
#define AGS02MA_OK 0
#define AGS02MA_ERROR -10
@ -22,7 +22,7 @@
#define AGS02MA_ERROR_NOT_READY -13
#define AGS02MA_I2C_CLOCK 30000
#define AGS02MA_I2C_CLOCK 25000 // max 30000
class AGS02MA

View File

@ -10,22 +10,45 @@
Arduino library for AGS02MA TVOC sensor.
This library is experimental, so please use with care.
Note the warning about the I2C speed, the device works at only 30 KHz.
This library is still experimental, so please use with care.
Note the warning about the I2C low speed, the device works at max 30 KHz.
Since 0.3.1 this library uses 25 KHz.
## I2C - warning low speed
## I2C
### PIN layout from left to right
| Front L->R | Description |
|:----------:|:------------|
| pin 1 | VDD + |
| pin 2 | SDA data |
| pin 3 | GND |
| pin 4 | SCL clock |
### WARNING - LOW SPEED
The sensor uses I2C at very low speed <= 30 KHz.
For an Arduino UNO the lowest speed possible is about 30.4KHz (TWBR = 255) which works.
For an Arduino UNO the lowest speed supported is about 30.4KHz (TWBR = 255) which works.
First runs with Arduino UNO indicate 2 failed reads in > 500 Reads, so less than 1%
Tests with ESP32 / ESP8266 at 30 KHz look good,
tests with lower clock speeds are to be done but expected to work.
First runs indicate 2 failed reads in > 500 Reads, so less than 1%
tests with ESP32 at lower clock speeds are to be done but expected to work.
The library sets the clock speed to 30 KHz (for non AVR) during operation
and resets it to 100 KHz after operation.
and resets it default to 100 KHz after operation.
This is done to minimize interference with the communication of other devices.
The reset clock speed can be changed with **setI2CResetSpeed()** e.g. to 200 or 400 KHz.
The reset clock speed can be changed with **setI2CResetSpeed(speed)** e.g. to 200 or 400 KHz.
#### 0.3.1 fix.
Version 0.3.1 sets the **I2C prescaler TWSR** register of the Arduino UNO to 4 so the lowest
speed possible is reduced to about 8 KHz.
A test run 4 hours with 6000++ reads on an UNO at 25 KHz gave 0 errors.
So the communication speed will be set to 25 KHz, also for other boards, for stability.
After communication the clock (+ prescaler) is reset again as before.
## Version 118 problems
@ -62,7 +85,6 @@ Note: the version 0.2.0 determines the version in the calibration function so
it won't calibrate any non 117 version.
### Please report your experiences.
If you have a AGS20MA device, version 117 or 118 or other,
@ -111,7 +133,7 @@ Serial.println(dd, HEX); // prints YYYYMMDD e.g. 20210203
### I2C clock speed
The library sets the clock speed to 30 KHz during operation
The library sets the clock speed to 25 KHz during operation
and resets it to 100 KHz after operation.
This is done to minimize interference with the communication of other devices.
The following function can change the I2C reset speed to e.g. 200 or 400 KHz.
@ -148,27 +170,27 @@ Simplified formula for 1 atm @ 25°C:
Some known gasses
| gas | Common name | ratio | molecular weight M |
|:-----|:--------------|:--------------------|:------------------:|
| SO2 | | 1 ppb = 2.62 μg/m3 | 64 |
| NO2 | | 1 ppb = 1.88 μg/m3 | 46 |
| NO | | 1 ppb = 1.25 μg/m3 | 30 |
| O3 | | 1 ppb = 2.00 μg/m3 | 48 |
| CO | | 1 ppb = 1.145 μg/m3 | 28 |
| C6H6 | Benzene | 1 ppb = 3.19 μg/m3 | 78 |
| gas | Common name | ratio ppb-μg/m3 | molecular weight M |
|:-----|:------------------|:--------------------|:------------------:|
| SO2 | Sulphur dioxide | 1 ppb = 2.62 μg/m3 | 64 gr/mol |
| NO2 | Nitrogen dioxide | 1 ppb = 1.88 μg/m3 | 46 gr/mol |
| NO | Nitrogen monoxide | 1 ppb = 1.25 μg/m3 | 30 gr/mol |
| O3 | Ozone | 1 ppb = 2.00 μg/m3 | 48 gr/mol |
| CO | Carbon Monoxide | 1 ppb = 1.145 μg/m3 | 28 gr/mol |
| C6H6 | Benzene | 1 ppb = 3.19 μg/m3 | 78 gr/mol |
### Reading
### Read the sensor
WARNING: The datasheet advises to take 3 seconds between reads.
You might be able to squeeze time down to 1.5 second at your own risk.
Tests gave stable results at 1.5 second intervals.
Use this faster rate at your own risk.
- **uint32_t readPPB()** reads PPB (parts per billion) from device.
Typical value should be between 1 .. 999999.
Returns **lastPPB()** value if failed so one does not get sudden jumps in graphs.
Check **lastStatus()** and **lastError()** to get more info about success.
Time needed is ~35 milliseconds.
- **uint32_t readUGM3()** reads UGM3 (microgram per cubic meter) current value from device.
Typical values depend on the molecular weight of the TVOC.
Returns **lastUGM3()** if failed so one does not get sudden jumps in graphs.
@ -179,6 +201,8 @@ Typical value should be between 0.01 .. 999.99
- **float readUGF3()** returns microgram per cubic feet.
### Error Codes
| ERROR_CODES | value |
|:---------------------------|:-----:|
| AGS02MA_OK | 0 |
@ -195,16 +219,20 @@ Typical value should be between 0.01 .. 999.99
- **uint32_t lastUGM3()** returns last read UGM3 (microgram per cubic meter) value (cached).
### Other
### Calibration
- **bool zeroCalibration()** to be called after at least 5 minutes in fresh air.
See example sketch.
- **bool manualZeroCalibration(uint16_t value = 0)** Set the zero calibration value manually.
To be called after at least 5 minutes in fresh air.
For v117: 0-65535 = automatic calibration.
For v118: 0 = automatic calibration, 1-65535 manual calibration.
- For v117: 0-65535 = automatic calibration.
- For v118: 0 = automatic calibration, 1-65535 manual calibration.
- **bool getZeroCalibrationData(ZeroCalibrationData &data)** fills a data struct with the current zero calibration status and value.
Returns true on success.
### Other
- **bool readRegister(uint8_t address, RegisterData &reg)** fills a data struct with the chip's register data at that address.
Primarily intended for troubleshooting and analysis of the sensor. Not recommended to build applications on top of this method's raw data.
Returns true when the struct is filled, false when the data could not be read.
@ -218,7 +246,7 @@ Read datasheet or table below for details. A new read is needed to update this.
#### Status bits.
| bit | description | notes |
|:----:|:----------------------------------|:------|
|:-----:|:------------------------------------|:--------|
| 7-4 | internal use |
| 3-1 | 000 = PPB 001 = uG/M3 |
| 0 | RDY bit 0 = ready 1 = not ready | 1 == busy
@ -231,4 +259,8 @@ Read datasheet or table below for details. A new read is needed to update this.
- add indicative table for PPB health zone
- check the mode bits of the status byte with internal \_mode.
- elaborate error handling.
- create an async interface for **readPPB()** if possible
- put the I2C speed code in 2 inline functions
- less repeating conditional code places
- setLowSpeed() + setNormalSpeed()

View File

@ -0,0 +1,29 @@
30 KHz
16:14:33.046 -> ...\AGS02MA_PPB_TIMING.ino
16:14:33.046 -> AGS02MA_LIB_VERSION: 0.3.0
16:14:33.046 ->
16:14:33.046 -> BEGIN: 1
16:14:33.046 -> VERS: 117
16:14:33.093 ->
16:14:33.093 -> Warming up (120 seconds = 24 dots)
16:14:38.107 -> ........................
16:16:33.243 -> MODE: 1 0
16:16:34.790 -> 32 549 10 0
16:16:36.325 -> 32 547 10 0
16:16:37.872 -> 31 545 10 0
16:16:39.418 -> 32 545 10 0
16:16:40.922 -> 33 544 10 0
16:16:42.469 -> 33 543 10 0
16:16:44.015 -> 33 542 10 0
16:16:45.562 -> 33 543 10 0
16:16:47.062 -> 33 536 10 0
16:16:48.608 -> 33 541 10 0
16:16:50.155 -> 33 537 10 0
16:16:51.701 -> 32 537 10 0
16:16:53.201 -> 33 536 10 0
16:16:54.747 -> 33 535 10 0
16:16:56.294 -> 33 534 10 0
16:16:57.810 -> 32 533 10 0
16:16:59.357 -> 32 531 10 0

View File

@ -0,0 +1,27 @@
10 KHz (TWBR 198, TWSR 1) just a test
16:08:08.836 -> ...\AGS02MA_PPB_TIMING.ino
16:20:01.824 -> AGS02MA_LIB_VERSION: 0.3.1
16:20:01.824 ->
16:20:01.824 -> BEGIN: 1
16:20:01.824 -> VERS: 117
16:20:01.871 ->
16:20:01.871 -> Warming up (120 seconds = 24 dots)
16:20:06.885 -> ........................
16:22:02.077 -> MODE: 1 0
16:22:03.624 -> 38 476 10 0
16:22:05.165 -> 38 474 10 0
16:22:06.712 -> 38 471 10 0
16:22:08.247 -> 38 474 10 0
16:22:09.794 -> 38 471 10 0
16:22:11.325 -> 38 472 10 0
16:22:12.871 -> 38 468 10 0
16:22:14.418 -> 37 465 10 0
16:22:15.917 -> 38 463 10 0
16:22:17.464 -> 38 463 10 0
16:22:19.016 -> 38 459 10 0
16:22:20.547 -> 37 460 10 0
16:22:22.094 -> 36 459 10 0
16:22:23.640 -> 38 461 10 0

View File

@ -0,0 +1,32 @@
25 KHz
16:08:08.836 -> ...\AGS02MA_PPB_TIMING.ino
16:08:08.836 -> AGS02MA_LIB_VERSION: 0.3.1
16:08:08.836 ->
16:08:08.836 -> BEGIN: 1
16:08:08.836 -> VERS: 117
16:08:08.929 ->
16:08:08.929 -> Warming up (120 seconds = 24 dots)
16:08:13.944 -> ........................
16:10:09.086 -> MODE: 1 0
16:10:10.633 -> 33 845 10 0
16:10:12.179 -> 32 846 10 0
16:10:13.726 -> 32 847 10 0
16:10:15.225 -> 33 847 10 0
16:10:16.772 -> 32 847 10 0
16:10:18.318 -> 33 841 10 0
16:10:19.849 -> 33 835 10 0
16:10:21.396 -> 34 829 10 0
16:10:22.895 -> 33 825 10 0
16:10:24.442 -> 33 828 10 0
16:10:25.988 -> 33 823 10 0
16:10:27.535 -> 34 824 10 0
16:10:29.081 -> 33 821 10 0
16:10:30.581 -> 33 821 10 0
16:10:32.127 -> 33 816 10 0
16:10:33.674 -> 34 826 10 0
16:10:35.221 -> 33 839 10 0
16:10:36.720 -> 33 855 10 0
16:10:38.267 -> 33 857 10 0
16:10:39.813 -> 33 857 10 0

View File

@ -21,7 +21,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/AGS02MA.git"
},
"version": "0.3.0",
"version": "0.3.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=AGS02MA
version=0.3.0
version=0.3.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for AGS02MA - TVOC sensor

View File

@ -31,6 +31,7 @@
unittest_setup()
{
fprintf(stderr, "AGS02MA_LIB_VERSION: %s\n", (char *) AGS02MA_LIB_VERSION);
}
@ -41,15 +42,13 @@ unittest_teardown()
unittest(test_constants)
{
fprintf(stderr, "AGS02MA_LIB_VERSION: %s\n", (char *) AGS02MA_LIB_VERSION);
assertEqual( 0, AGS02MA_OK);
assertEqual(-10, AGS02MA_ERROR);
assertEqual(-11, AGS02MA_ERROR_CRC);
assertEqual(-12, AGS02MA_ERROR_READ);
assertEqual(-13, AGS02MA_ERROR_NOT_READY);
assertEqual(30000, AGS02MA_I2C_CLOCK);
assertEqual(25000, AGS02MA_I2C_CLOCK);
}
@ -58,8 +57,6 @@ unittest(test_base)
AGS02MA AGS(26);
Wire.begin();
fprintf(stderr, "AGS02MA_LIB_VERSION: %s\n", (char *) AGS02MA_LIB_VERSION);
assertTrue(AGS.begin());
assertTrue(AGS.isConnected()); // TODO - GODMODE
@ -84,8 +81,6 @@ unittest(test_mode)
AGS02MA AGS(26);
Wire.begin();
fprintf(stderr, "AGS02MA_LIB_VERSION: %s\n", (char *) AGS02MA_LIB_VERSION);
assertTrue(AGS.begin());
assertTrue(AGS.isConnected()); // TODO - GODMODE