From 328f724f1740fdcf67a4c6070927db8284cf7ecc Mon Sep 17 00:00:00 2001 From: rob tillaart Date: Fri, 14 Jan 2022 11:39:18 +0100 Subject: [PATCH] 0.1.2 AM2315 --- libraries/AM2315/AM2315.cpp | 93 +++++++++++++-------------- libraries/AM2315/AM2315.h | 32 +++++----- libraries/AM2315/README.md | 97 ++++++++++++++++++++--------- libraries/AM2315/keywords.txt | 16 ++++- libraries/AM2315/library.json | 2 +- libraries/AM2315/library.properties | 2 +- 6 files changed, 142 insertions(+), 100 deletions(-) diff --git a/libraries/AM2315/AM2315.cpp b/libraries/AM2315/AM2315.cpp index ca7d9dd5..29cea93f 100644 --- a/libraries/AM2315/AM2315.cpp +++ b/libraries/AM2315/AM2315.cpp @@ -1,19 +1,20 @@ // // FILE: AM2315.cpp // AUTHOR: Rob.Tillaart@gmail.com -// VERSION: 0.1.1 +// VERSION: 0.1.2 // PURPOSE: AM2315 Temperature and Humidity sensor library for Arduino // URL: https://github.com/RobTillaart/AM2315 // // HISTORY: // 0.1.0 2022-01-05 initial version // 0.1.1 2022-01-11 fix handshake. +// 0.1.2 2022-01-13 fix wake-up in read() for ESP32. #include "AM2315.h" -// these defines are not for user to adjust +// these defines can not be tuned // READ_DELAY for blocking read #define AM2315_READ_DELAY 2000 @@ -27,11 +28,14 @@ // AM2315::AM2315(TwoWire *wire) { - _wire = wire; - _temperature = 0; - _humidity = 0; - _humOffset = 0; - _tempOffset = 0; + _wire = wire; + _temperature = 0; + _humidity = 0; + _humOffset = 0; + _tempOffset = 0; + _lastRead = 0; + _waitForRead = false; + _suppressError = false; }; @@ -70,16 +74,22 @@ bool AM2315::isConnected(uint16_t timeout) } +// return values: +// AM2315_OK +// AM2315_ERROR_CONNECT +// AM2315_MISSING_BYTES +// AM2315_ERROR_CHECKSUM; +// AM2315_HUMIDITY_OUT_OF_RANGE +// AM2315_TEMPERATURE_OUT_OF_RANGE int AM2315::read() { - // reset readDelay - if (_readDelay == 0) _readDelay = AM2315_READ_DELAY; - while (millis() - _lastRead < _readDelay) + while (millis() - _lastRead < AM2315_READ_DELAY) { if (!_waitForRead) return AM2315_WAITING_FOR_READ; yield(); } int rv = _read(); + _lastRead = millis(); return rv; } @@ -104,13 +114,19 @@ float AM2315::getTemperature() // // PRIVATE // + +// return values: +// AM2315_OK +// AM2315_ERROR_CONNECT +// AM2315_MISSING_BYTES +// AM2315_ERROR_CHECKSUM; +// AM2315_HUMIDITY_OUT_OF_RANGE +// AM2315_TEMPERATURE_OUT_OF_RANGE int AM2315::_read() { // READ VALUES int rv = _readSensor(); - _lastRead = millis(); - if (rv != AM2315_OK) { if (_suppressError == false) @@ -121,8 +137,9 @@ int AM2315::_read() return rv; // propagate error value } - _humidity = (_bits[0] * 256 + _bits[1]) * 0.1; - int16_t t = ((_bits[2] & 0x7F) * 256 + _bits[3]); + // EXTRACT HUMIDITY AND TEMPERATURE + _humidity = (_bits[2] * 256 + _bits[3]) * 0.1; + int16_t t = ((_bits[4] & 0x7F) * 256 + _bits[5]); if (t == 0) { _temperature = 0.0; // prevent -0.0; @@ -130,14 +147,14 @@ int AM2315::_read() else { _temperature = t * 0.1; - if ((_bits[2] & 0x80) == 0x80 ) + if ((_bits[4] & 0x80) == 0x80 ) { _temperature = -_temperature; } } - // TEST OUT OF RANGE #ifdef AM2315_VALUE_OUT_OF_RANGE + // TEST OUT OF RANGE if (_humidity > 100) { return AM2315_HUMIDITY_OUT_OF_RANGE; @@ -152,11 +169,6 @@ int AM2315::_read() } -///////////////////////////////////////////////////// -// -// PRIVATE -// - // return values: // AM2315_OK // AM2315_ERROR_CONNECT @@ -164,53 +176,38 @@ int AM2315::_read() // AM2315_ERROR_CHECKSUM; int AM2315::_readSensor() { - // EMPTY BUFFER - for (uint8_t i = 0; i < 5; i++) _bits[i] = 0; - - // HANDLE PENDING IRQ + // HANDLE PENDING IRQ etc. yield(); // WAKE UP the sensor - _wire->beginTransmission(AM2315_ADDRESS); - for (int i = 0; i < 10; i++) _wire->write(0); - int rv = _wire->endTransmission(); - if (rv < 0) return rv; + if (! isConnected() ) return AM2315_ERROR_CONNECT; - // REQUEST DATA + // SEND COMMAND _wire->beginTransmission(AM2315_ADDRESS); _wire->write(0X03); _wire->write(0); _wire->write(4); - rv = _wire->endTransmission(); + int rv = _wire->endTransmission(); if (rv < 0) return rv; - delayMicroseconds(1500); - // GET DATA + // REQUEST DATA const int length = 8; int bytes = _wire->requestFrom(AM2315_ADDRESS, length); if (bytes == 0) return AM2315_ERROR_CONNECT; if (bytes < length) return AM2315_MISSING_BYTES; - uint8_t buffer[12]; + // READ DATA for (int i = 0; i < bytes; i++) { - buffer[i] = _wire->read(); + _bits[i] = _wire->read(); } - _bits[0] = buffer[2]; - _bits[1] = buffer[3]; - _bits[2] = buffer[4]; - _bits[3] = buffer[5]; // TEST CHECKSUM - uint16_t crc0 = buffer[7] * 256 + buffer[6]; - uint16_t crc1 = _crc16(buffer, bytes - 2); - // Serial.print("CRC: "); - // Serial.print(crc0 - crc1); - // Serial.print("\t"); - // Serial.print(crc1); - // Serial.println(); - if (crc0 != crc1) return AM2315_ERROR_CHECKSUM; - + uint16_t crc = _bits[bytes - 1] * 256 + _bits[bytes - 2]; + if (_crc16(_bits, bytes - 2) != crc) + { + return AM2315_ERROR_CHECKSUM; + } return AM2315_OK; } diff --git a/libraries/AM2315/AM2315.h b/libraries/AM2315/AM2315.h index 1b9ed1e3..cd7cb84b 100644 --- a/libraries/AM2315/AM2315.h +++ b/libraries/AM2315/AM2315.h @@ -2,11 +2,10 @@ // // FILE: AM2315.h // AUTHOR: Rob Tillaart -// VERSION: 0.1.1 // PURPOSE: AM2315 Temperature and Humidity sensor library for Arduino +// VERSION: 0.1.2 // URL: https://github.com/RobTillaart/AM2315 - - +// // AM232X PIN layout AM2315 COLOR // ============================================ // bottom view DESCRIPTION COLOR @@ -16,13 +15,15 @@ // |o | GND BLACK // |o | SCL GREY // +---+ +// +// do not forget pull up resistors between SDA, SCL and VDD. #include "Arduino.h" #include "Wire.h" -#define AM2315_LIB_VERSION (F("0.1.1")) +#define AM2315_LIB_VERSION (F("0.1.2")) #define AM2315_OK 0 @@ -68,22 +69,18 @@ public: // adding offsets works well in normal range // might introduce under- or overflow at the ends of the sensor range - void setHumOffset(float offset) { _humOffset = offset; }; - void setTempOffset(float offset) { _tempOffset = offset; }; - float getHumOffset() { return _humOffset; }; - float getTempOffset() { return _tempOffset; }; + void setHumOffset(float offset = 0) { _humOffset = offset; }; + void setTempOffset(float offset = 0) { _tempOffset = offset; }; + float getHumOffset() { return _humOffset; }; + float getTempOffset() { return _tempOffset; }; - bool getWaitForReading() { return _waitForRead; }; - void setWaitForReading(bool b ) { _waitForRead = b; }; - - // set readDelay to 0 will reset to datasheet values - uint16_t getReadDelay() { return _readDelay; }; - void setReadDelay(uint16_t rd = 0) { _readDelay = rd; }; + bool getWaitForReading() { return _waitForRead; }; + void setWaitForReading(bool b ) { _waitForRead = b; }; // suppress error values of -999 => check return value of read() instead - bool getSuppressError() { return _suppressError; }; - void setSuppressError(bool b) { _suppressError = b; }; + bool getSuppressError() { return _suppressError; }; + void setSuppressError(bool b) { _suppressError = b; }; bool wakeUp() { return isConnected(); }; @@ -95,9 +92,8 @@ private: uint32_t _lastRead = 0; bool _waitForRead = false; bool _suppressError = false; - uint16_t _readDelay = 0; - uint8_t _bits[5]; // buffer to receive data + uint8_t _bits[8]; // buffer to hold raw data int _read(); int _readSensor(); uint16_t _crc16(uint8_t *ptr, uint8_t len); diff --git a/libraries/AM2315/README.md b/libraries/AM2315/README.md index 0a3b87d9..4c2d82f8 100644 --- a/libraries/AM2315/README.md +++ b/libraries/AM2315/README.md @@ -10,18 +10,55 @@ Arduino library for I2C AM2315 temperature and humidity sensor. +The AM2315 can also be read with the https://github.com/RobTillaart/AM232X library as it uses the same protocol. The AM232X library allows to read some internal registers. + ## Description -**Experimental** - -The library should be initiated by calling the **begin()** function, +The library must be initiated by calling the **begin()** function, optionally **begin(dataPin, clockPin)** for **ESP32** and similar platforms. Thereafter one has to call the **read()** function to do the actual reading, and with **getTemperature()** and **getHumidity()** to get the read values. Calling these latter again will return the same values until a new **read()** is called. +The I2C address is 0x5C and is hardcoded in the device. +If you need multiple AM2315 devices use a I2C multiplexer e.g. https://github.com/RobTillaart/TCA9548 + + +### I2C clock speed + +The datasheet states the AM2315 should be used on 100 KHz I2C only. +When overclocking I got good readings up to 190 KHz in a test with +- Arduino UNO +- very short wires (< 1 meter) +- not using pull ups. +- version 0.1.1 of this library + + +| I2C clock | timing us | Notes | +|:---------:|:---------:|:----------------------| +| 50 KHz | 4570 | under-clocking works (e.g. long wires) +| 100 KHz | 3276 | specs default, robust +| 150 KHz | 2836 | +| 160 KHz | 2792 | +| 170 KHz | 2750 | 0.5 ms off, interesting for performance. +| 180 KHz | 2700 | near critical. DO NOT USE. +| 190 KHz | 2672 | near critical. DO NOT USE. +| 200 KHz | crash | sensor needs a power cycle reboot. DO NOT USE. + + +If robustness is mandatory stick to the default of 100 KHz. +If performance is mandatory do not go beyond 170 KHz. + + +### Wake up + +As the sensor goes to sleep after 3 seconds after last read, it needs to be woken up. +This is hard coded in the **readSensor()** function. +There is also a **wakeUp()** function so the wake up can be done some time before the +read is actual needed. + ## Interface @@ -40,51 +77,51 @@ minimum = 800 us and maximum = 3000 us according to datasheet. - **int8_t read()** read the sensor and store the values internally. It returns the status of the read which should be **AM2315_OK** == 0. -- **float getHumidity()** returns last Humidity read, or -999 in case of error. -- **float getTemperature()** returns last Temperature read, or **AM2315_INVALID_VALUE** == -999 in case of error. +- **float getHumidity()** returns last Humidity read + optional offset, or **AM2315_INVALID_VALUE** == -999 in case of error. This error can be suppressed, see below. +- **float getTemperature()** returns last Temperature read + optional offset, or **AM2315_INVALID_VALUE** == -999 in case of error. This error can be suppressed, see below. - **uint32_t lastRead()** returns the timestamp in milliseconds since startup of the last successful read. ### Offset -- **void setHumOffset(float offset)** set an offset to calibrate (1st order) the sensor. -- **float getHumOffset()** return current offset, default 0. -- **void setTempOffset(float offset)** set an offset to calibrate (1st order) the sensor -- **float getTempOffset()** return current offset, default 0. +- **void setHumOffset(float offset = 0)** set an offset for humidity to calibrate (1st order) the sensor. +Default offset = 0, so no parameter will reset the offset. +- **float getHumOffset()** return current humidity offset, default 0. +- **void setTempOffset(float offset = 0)** set an offset for temperature to calibrate (1st order) the sensor. +Default offset = 0, so no parameter will reset the offset. +- **float getTempOffset()** return current temperature offset, default 0. ### Control Functions to adjust the communication with the sensor. -- **void setWaitForReading(bool b )** flag to enforce a blocking wait. +- **void setWaitForReading(bool b )** flag to enforce a blocking wait (up to 2 seconds) when **read()** is called. - **bool getWaitForReading()** returns the above setting. -- **void setReadDelay(uint16_t rd = 0)** To tune the time it waits before actual read. Default = 2000 ms. -set readDelay to 0 will reset to 2000 ms AFTER a call to **read()**. -- **uint16_t getReadDelay()** returns the above setting. -- **void setSuppressError(bool b)** suppress error values of -999 => you need to check the return value of read() instead. -This is used to keep spikes out of your graphs / logs. +- **void setSuppressError(bool b)** suppress error values of **AM2315_INVALID_VALUE** == -999 => you need to check the return value of read() instead. +This can be used to keep spikes out of your graphs / logs. - **bool getSuppressError()** returns the above setting. ### Misc -- **bool wakeUp()** function that will try for 3 milliseconds to wake up the sensor. +- **bool wakeUp()** function that will try for 3 milliseconds to wake up the sensor. +This can be done before an actual read to minimize the **read()** call. ### error codes -| name | value | notes | -|:----------------------------------|------:|:----------| +| name | value | notes | +|:----------------------------------|------:|:------------| | AM2315_OK | 0 | -| AM2315_ERROR_CHECKSUM | -10 | -| AM2315_ERROR_CONNECT | -11 | -| AM2315_MISSING_BYTES | -12 | -| AM2315_WAITING_FOR_READ | -50 | -| AM2315_HUMIDITY_OUT_OF_RANGE | -100 | -| AM2315_TEMPERATURE_OUT_OF_RANGE | -101 | -| AM2315_INVALID_VALUE | -999 | +| AM2315_ERROR_CHECKSUM | -10 | I2C problem. +| AM2315_ERROR_CONNECT | -11 | I2C problem. +| AM2315_MISSING_BYTES | -12 | I2C problem. +| AM2315_WAITING_FOR_READ | -50 | called **read()** too fast, within 2 seconds. +| AM2315_HUMIDITY_OUT_OF_RANGE | -100 | not used by default. +| AM2315_TEMPERATURE_OUT_OF_RANGE | -101 | not used by default. +| AM2315_INVALID_VALUE | -999 | can be suppressed. ## Operation @@ -94,17 +131,15 @@ See examples ## Future -- found that the interface is like AM232X library.need to test first. -- get hardware and test test test ... -- update unit test - documentation -- clean up code +- test +- update unit test - add examples -- add AM2320 derived class ? -- optimize +- merge with the AM232X library in a far future. **wont** - add calls for meta information (no description yet) - 0x07 status register - 0x08-0x0B user register HIGH LOW HIGH2 LOW2 + (use AM232x library to access those) diff --git a/libraries/AM2315/keywords.txt b/libraries/AM2315/keywords.txt index e97f6366..e87770b5 100644 --- a/libraries/AM2315/keywords.txt +++ b/libraries/AM2315/keywords.txt @@ -15,7 +15,14 @@ setHumOffset KEYWORD2 setTempOffset KEYWORD2 getHumOffset KEYWORD2 getTempOffset KEYWORD2 + +getWaitForReading KEYWORD2 +setWaitForReading KEYWORD2 +getSuppressError KEYWORD2 +setSuppressError KEYWORD2 + lastRead KEYWORD2 +wakeUp KEYWORD2 # Constants (LITERAL1) @@ -24,4 +31,11 @@ AM2315_LIB_VERSION LITERAL2 AM2315_OK LITERAL2 AM2315_ERROR_CHECKSUM LITERAL1 AM2315_ERROR_CONNECT LITERAL1 -AM2315_MISSING_BYTES LITERAL1 \ No newline at end of file +AM2315_MISSING_BYTES LITERAL1 +AM2315_WAITING_FOR_READ LITERAL1 + +AM2315_VALUE_OUT_OF_RANGE LITERAL1 +AM2315_HUMIDITY_OUT_OF_RANGE LITERAL1 +AM2315_TEMPERATURE_OUT_OF_RANGE LITERAL1 +AM2315_INVALID_VALUE LITERAL1 + diff --git a/libraries/AM2315/library.json b/libraries/AM2315/library.json index 08b7c51c..42c47de0 100644 --- a/libraries/AM2315/library.json +++ b/libraries/AM2315/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/AM2315.git" }, - "version": "0.1.1", + "version": "0.1.2", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/libraries/AM2315/library.properties b/libraries/AM2315/library.properties index af351049..00811ae1 100644 --- a/libraries/AM2315/library.properties +++ b/libraries/AM2315/library.properties @@ -1,5 +1,5 @@ name=AM2315 -version=0.1.1 +version=0.1.2 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for I2C AM2315 temperature and humidity sensor.