0.1.2 AM2315

This commit is contained in:
rob tillaart 2022-01-14 11:39:18 +01:00
parent d81dd5eb89
commit 328f724f17
6 changed files with 142 additions and 100 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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.
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)

View File

@ -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)
@ -25,3 +32,10 @@ AM2315_OK LITERAL2
AM2315_ERROR_CHECKSUM LITERAL1
AM2315_ERROR_CONNECT LITERAL1
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

View File

@ -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": "*",

View File

@ -1,5 +1,5 @@
name=AM2315
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for I2C AM2315 temperature and humidity sensor.