0.4.0 SHT85

This commit is contained in:
Rob Tillaart 2023-04-06 16:54:56 +02:00
parent 075a12a543
commit 973bdce187
16 changed files with 687 additions and 253 deletions

View File

@ -6,7 +6,7 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update

View File

@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6

View File

@ -10,7 +10,7 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
with:

View File

@ -6,11 +6,25 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.4.0] - 2022-12-14
- redo asynchronous interface
- add **uint32_t getLastRequest()** timestamp.
- add offset functions for temperature and humidity.
- update readme.md
- move code from .h to .cpp
- updated unit test
- add examples
- update keywords.txt
- update GitHub actions
- update license 2023
- minor edits
----
## [0.3.3] - 2022-11-24
- Add RP2040 support to build-CI.
- Add CHANGELOG.md
## [0.3.2] - 2022-01-17
- fix #8 add SHT_DEFAULT_ADDRESS + 2x begin()

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2022 Rob Tillaart
Copyright (c) 2021-2023 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -11,69 +11,97 @@
Arduino library for the SHT85 temperature and humidity sensor.
Based upon the SHT31 library - https://github.com/RobTillaart/SHT31
however this one will be leading in the future as it implements classes for the following SHT sensors: **SHT30, SHT31 and SHT35.**
however this library will be leading in the future as it implements derived classes
for the following sensors: **SHT30, SHT31, SHT35 and SHT85.**.
**Warning:** to keep self-heating below 0.1°C, the SHT85 sensor should
**WARNING** to keep self-heating below 0.1°C, the SHT85 sensor should
not be used for more than 10% of the time.
## Description
Always check datasheet before connecting!
```
// TOPVIEW SHT85
// +-------+
// +-----\ | SDA 4 -----
// | /-+ ----+ GND 3 -----
// | +-+ ----+ +5V 2 -----
// +-----/ | SCL 1 -----
// +-------+
// TOPVIEW SHT85
// +-------+
// +-----\ | SDA 4 -----
// | /-+ ----+ GND 3 -----
// | +-+ ----+ +5V 2 -----
// +-----/ | SCL 1 -----
// +-------+
```
The SHT85 sensors should work up to 1000 KHz, however during tests
with an Arduino UNO it stopped between 500 - 550 KHz so to be safe I recommend
not to use it above 400 KHz. Also the differences in read time becomes
quite small. (max 15% gain). See output example sketch.
The SHT85 sensors should work up to 1000 KHz.
During tests with an Arduino UNO it stopped between 500 - 550 KHz.
So to be safe I recommend not to use the sensor above 400 KHz.
Also the differences in read time becomes quite small. (max 15% gain).
| I2C speed | read ms | notes |
|:---------:|:-------:|:------|
| 100 KHz | 5.11 | |
See indicative output example sketch.
SPS (= samples per second) are added later.
| I2C speed | read ms | SPS | notes |
|:---------:|:-------:|:-----:|:--------|
| 50 KHz | 6.60 | 123 |
| 100 KHz | 5.11 | 140 | default
| 150 KHz | 4.79 | |
| 200 KHz | 4.64 | |
| 200 KHz | 4.64 | 140 |
| 250 KHz | 4.56 | |
| 300 KHz | 4.50 | |
| 300 KHz | 4.50 | 164 |
| 350 KHz | 4.47 | |
| 400 KHz | 4.45 | |
| 400 KHz | 4.45 | 164 |
| 450 KHz | 4.43 | |
| 500 KHz | 4.42 | |
| 550 KHz | ---- | fail |
| 500 KHz | 4.42 | 163 |
| 550 KHz | ---- | | fail
### Compatibility
This library should also work for SHT30, SHT31 and SHT35 but
this is not verified yet.
Accuracy table
| SENSOR | Temperature | Humidity |
|:------:|:-----------:|:--------:|
| SHT30 | ~0.3° | 2.0% |
| SHT31 | ~0.3° | 1.5% |
| SHT35 | ~0.2° | 1.5% |
| SHT85 | ~0.2° | 1.5% |
At 10% load the SHT85 can be used to make about 10-15 SPS.
Need to investigate if the interface is identical?
If so the libraries might be merged.
#### Compatibility
The SHT85 is protocom compatible with the SHT3x series.
Main difference is the accuracy.
Compare the datasheets to see all differences.
Accuracy table:
| Sensor | Temperature | Humidity | Verified }
|:--------:|:-------------:|:----------:|:----------:|
| SHT30 | ~0.3° | 2.0% | N |
| SHT31 | ~0.3° | 1.5% | Y |
| SHT35 | ~0.2° | 1.5% | N |
| SHT85 | ~0.2° | 1.5% | Y |
Note: The SHT40, SHT41 and SHT45 are not protocol compatible with SHT3x and SHT85.
The SHT4x series is slightly faster than the SHT3x series.
#### Related libraries
- https://github.com/RobTillaart/SHT2x
- https://github.com/RobTillaart/SHT31
- https://github.com/RobTillaart/SHT31_SW = softWire based I2C.
- https://github.com/RobTillaart/tinySHT2x
An elaborated library for the SHT31 sensor can be found here
https://github.com/hawesg/SHT31D_Particle_Photon_ClosedCube
- https://github.com/hawesg/SHT31D_Particle_Photon_ClosedCube
Dewpoint, heatindex and related functions
- https://github.com/RobTillaart/Temperature
## Interface
```cpp
#include "SHT85.h"
```
#### Base interface
- **SHT()** constructor of the base class. **getType()** will return 0.
@ -82,47 +110,106 @@ https://github.com/hawesg/SHT31D_Particle_Photon_ClosedCube
- **SHT35()** constructor.
- **SHT85()** constructor.
- **uint8_t getType()** returns numeric part of sensor type.
Returns 0 for the base class.
- **bool begin(uint8_t address, uint8_t dataPin, uint8_t clockPin)** begin function for ESP8266 & ESP32; **WARNING: not verified yet**
returns false if device address is incorrect or device cannot be reset.
- **bool begin(uint8_t dataPin, uint8_t clockPin)** same as above.
Uses SHT_DEFAULT_ADDRESS as address.
Uses SHT_DEFAULT_ADDRESS (0x44) as address.
- **bool begin(uint8_t address, TwoWire \*wire = &Wire)** for platforms with multiple I2C buses. Default Wire as I2C bus.
- **bool begin(TwoWire \*wire = &Wire)** same as above.
Uses SHT_DEFAULT_ADDRESS as address.
- **bool read(bool fast = true)** blocks 4 (fast) or 15 (slow) milliseconds + actual read + math.
Does read both the temperature and humidity.
Uses SHT_DEFAULT_ADDRESS (0x44) as address.
#### Status
- **bool isConnected()** check sensor is reachable over I2C. Returns false if not connected.
- **uint16_t readStatus()** details see datasheet and **Status fields** below.
- **uint32_t lastRead()** in milliSeconds since start of program.
- **bool reset(bool hard = false)** resets the sensor, soft reset by default. Returns false if fails.
#### Synchronous read
- **bool read(bool fast = true)** blocks 4 (fast) or 15 (slow) milliseconds + actual read + math.
Does read both the temperature and humidity.
Note: the medium level is not supported (yet).
#### Asynchronous read
See async example for usage.
- **bool requestData(bool fast = true)** requests a new measurement.
Returns false if the request fails.
Set a timestamp.
- **bool dataReady(bool fast = true)** Checks if appropriate time (4 / 15 ms)
has past since request to read the data.
- **bool readData(bool fast = true)** fast = true skips the CRC check.
Returns false if reading the data fails or if CRC check failed.
- **uint32_t getLastRequest()** returns timestamp of last requestData.
#### Temperature and humidity
Note that the temperature and humidity values are recalculated on every call to **getHumidity()** and **getTemperature()**.
If you're worried about the extra cycles, you should make sure to cache these values or only request them after
you've performed a new reading.
- **float getHumidity()** computes the relative humidity in % based on the latest raw reading, and returns it.
- **float getTemperature()** computes the temperature in °C based on the latest raw reading, and returns it.
- **float getFahrenheit()** computes the temperature in °F based on the latest raw reading, and returns it.
Note that the optional offset is set in °Celsius.
The **getRawHumidity()** and **getRawTemperature()** can be used to minimize storage or communication.
Another application is faster comparison with a previous value or threshold.
- **uint16_t getRawHumidity()** returns the raw two-byte representation of humidity directly from the sensor.
- **uint16_t getRawTemperature()** returns the raw two-byte representation of temperature directly from the sensor.
Note that the temperature and humidity values are recalculated on every call to getHumidity() and getTemperature().
If you're worried about the extra cycles, you should make sure to cache these values or only request them after
you've performed a new reading.
The library has no **CelsiusToRaw()** function although this is relative easy.
```
rawTemperatureC = (tempC + 45) * (65535 / 175.0);
rawTemperatureF = (tempF + 49) * (65535 / 315.0);
rawHumidity = humidity * 655.35;
```
#### Temperature and humidity offset
Default the offset is zero for both temperature and humidity.
These functions allows one to adjust them a little.
Note: the offset is in degrees Celsius.
To set an offset in degrees Fahrenheit, multiply the Fahrenheit offset with 0.55555556 to get Celsius steps.
So 4°F becomes 2.2222°C.
- **void setTemperatureOffset(float offset = 0)** set the offset, default is zero removing the offset.
- **float getTemperatureOffset()** returns the set offset.
- **void setHumidityOffset(float offset = 0)** set the offset, default is zero removing the offset.
- **float getHumidityOffset()** returns the set offset.
#### Error interface
- **int getError()** returns last set error flag and clear it.
Be sure to clear the error flag by calling **getError()** before calling any command as the error flag could be from a previous command.
Be sure to clear the error flag by calling **getError()** before calling
any command as the error flag could be from a previous command.
| Error | Symbolic | Description |
|:-----:|:--------------------------|:----------------------------|
| 0x00 | SHT_OK | no error |
| 0x81 | SHT_ERR_WRITECMD | I2C write failed |
| 0x82 | SHT_ERR_READBYTES | I2C read failed |
| 0x83 | SHT_ERR_HEATER_OFF | Could not switch off heater |
| 0x84 | SHT_ERR_NOT_CONNECT | Could not connect |
| 0x85 | SHT_ERR_CRC_TEMP | CRC error in temperature |
| 0x86 | SHT_ERR_CRC_HUM | CRC error in humidity |
| 0x87 | SHT_ERR_CRC_STATUS | CRC error in status field |
| 0x88 | SHT_ERR_HEATER_COOLDOWN | Heater need to cool down |
| 0x89 | SHT_ERR_HEATER_ON | Could not switch on heater |
| Error | Symbolic | Description |
|:-------:|:--------------------------|:------------------------------|
| 0x00 | SHT_OK | no error |
| 0x81 | SHT_ERR_WRITECMD | I2C write failed |
| 0x82 | SHT_ERR_READBYTES | I2C read failed |
| 0x83 | SHT_ERR_HEATER_OFF | Could not switch off heater |
| 0x84 | SHT_ERR_NOT_CONNECT | Could not connect |
| 0x85 | SHT_ERR_CRC_TEMP | CRC error in temperature |
| 0x86 | SHT_ERR_CRC_HUM | CRC error in humidity |
| 0x87 | SHT_ERR_CRC_STATUS | CRC error in status field |
| 0x88 | SHT_ERR_HEATER_COOLDOWN | Heater need to cool down |
| 0x89 | SHT_ERR_HEATER_ON | Could not switch on heater |
#### Heater interface
@ -136,78 +223,68 @@ within **180** seconds of the last switch off. Note: this guarding is not reboot
**WARNING:** The user is responsible to switch the heater off manually!
The class does **NOT** do this automatically.
Switch off the heater by directly calling **heatOff()** or indirectly by calling **isHeaterOn()**.
Switch off the heater by explicitly calling **heatOff()** or indirectly by calling **isHeaterOn()**.
- **void setHeatTimeout(uint8_t seconds)** Set the time out of the heat cycle.
This value is truncated to max 180 seconds.
- **uint8_t getHeatTimeout
- **bool heatOn()** switches heat cycle on if not already on.
Returns false if fails, setting error to **SHT_ERR_HEATER_COOLDOWN**
- **uint8_t getHeatTimeout()** returns the value set.
- **bool heatOn()** switches the heat cycle on if not already on.
Returns false if this fails, setting error to **SHT_ERR_HEATER_COOLDOWN**
or to **SHT_ERR_HEATER_ON**.
- **bool heatOff()** switches heat cycle off.
- **bool heatOff()** switches the heat cycle off.
Returns false if fails, setting error to **SHT_ERR_HEATER_OFF**.
- **bool isHeaterOn()** is the sensor still in heating cycle? replaces **heatUp()**.
Will switch the heater off if max heating time has passed.
#### Async interface
See async example for usage
- **bool requestData()** requests a new measurement. Returns false if the request fails.
- **bool dataReady()** checks if enough time has passed to read the data. (15 milliseconds)
- **bool readData(bool fast = true)** fast = true skips the CRC check.
Returns false if reading fails or in case of a CRC failure.
- **bool isHeaterOn()** is the sensor still in a heating cycle? Replaces **heatUp()**.
Will switch the heater off if maximum heating time has passed.
## Status fields
| BIT | Description | value | notes |
|:-----|:---------------------------|:--------|:------|
| 15 | Alert pending status | 0 | no pending alerts
| | | 1 | at least one pending alert - default
| 14 | Reserved | 0 |
| 13 | Heater status | 0 | Heater OFF - default
| | | 1 | Heater ON
| 12 | Reserved | 0 |
| 11 | Humidity tracking alert | 0 | no alert - default
| | | 1 | alert
| 10 | Temperature tracking alert | 0 | no alert - default
| | | 1 | alert
| 9-5 | Reserved | 00000 |
| 4 | System reset detected | 0 | no reset since last clear status register command
| | | 1 | reset detected (hard or soft reset command or supply fail) - default
| 3-2 | Reserved | 00 |
| 1 | Command status | 0 | last command executed successfully
| | | 1 | last command not processed. Invalid or failed checksum
| 0 | Write data checksum status | 0 | checksum of last write correct
| | | 1 | checksum of last write transfer failed
## Operation
See examples.
| BIT | Description | value | notes |
|:------|:---------------------------|:--------|:--------|
| 15 | Alert pending status | 0 | no pending alerts
| | | 1 | at least one pending alert - default
| 14 | Reserved | 0 |
| 13 | Heater status | 0 | Heater OFF - default
| | | 1 | Heater ON
| 12 | Reserved | 0 |
| 11 | Humidity tracking alert | 0 | no alert - default
| | | 1 | alert
| 10 | Temperature tracking alert | 0 | no alert - default
| | | 1 | alert
| 9-5 | Reserved | 00000 | reserved
| 4 | System reset detected | 0 | no reset since last clear status register command
| | | 1 | reset detected (hard or soft reset command or supply fail) - default
| 3-2 | Reserved | 00 |
| 1 | Command status | 0 | last command executed successfully
| | | 1 | last command not processed. Invalid or failed checksum
| 0 | Write data checksum status | 0 | checksum of last write correct
| | | 1 | checksum of last write transfer failed
## Future
#### should
- testing
- verify working with ESP32
- software I2C experiments
- improve error handling / status. (all code paths)
- add offsets for temperature and humidity.
- like other sensors
- move code from .h to .cpp
#### Must
- improve documentation.
#### could
#### Should
- more testing (including heater)
- verify working with ESP32
- improve error handling / status.
- all code paths
- reset to OK
- support for medium level read.
- 3 levels iso 2.
#### Could
- investigate command ART (auto sampling at 4 Hz)
- investigate command BREAK (stop auto sampling)
- merge with other SHT sensors if possible
- separate release notes.
- test SHT30/35
#### won't
@ -217,5 +294,9 @@ See examples.
- create a SHT85 simulator
- I2C slave sketch with e.g. a DHT22 sensor/
- not within this library.
- software I2C experiments
- see https://github.com/RobTillaart/SHT31_SW
- merge with other SHT sensors if possible?
- derived classes fixes this enough.
- **getKelvin()** wrapper? (no => check temperature class)

View File

@ -1,7 +1,7 @@
//
// FILE: SHT85.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.3.3
// VERSION: 0.4.0
// DATE: 2021-02-10
// PURPOSE: Arduino library for the SHT85 temperature and humidity sensor
// https://nl.rs-online.com/web/p/temperature-humidity-sensor-ics/1826530
@ -12,33 +12,36 @@
#include "SHT85.h"
// SUPPORTED COMMANDS - single shot mode only
// SUPPORTED COMMANDS - single shot mode only
#define SHT_READ_STATUS 0xF32D
#define SHT_CLEAR_STATUS 0x3041
#define SHT_SOFT_RESET 0x30A2
#define SHT_HARD_RESET 0x0006
#define SHT_MEASUREMENT_FAST 0x2416 // page 10 datasheet
#define SHT_MEASUREMENT_SLOW 0x2400 // no clock stretching
#define SHT_MEASUREMENT_FAST 0x2416 // page 10 datasheet
#define SHT_MEASUREMENT_SLOW 0x2400 // no clock stretching
#define SHT_HEAT_ON 0x306D
#define SHT_HEAT_OFF 0x3066
#define SHT_HEATER_TIMEOUT 180000UL // milliseconds
#define SHT_HEATER_TIMEOUT 180000UL // milliseconds
SHT::SHT()
{
_address = 0;
_lastRead = 0;
_rawTemperature = 0;
_rawHumidity = 0;
_heatTimeout = 0;
_heaterStart = 0;
_heaterStop = 0;
_heaterOn = false;
_error = SHT_OK;
_type = 0;
_address = 0;
_wire = NULL;
_lastRead = 0;
_rawTemperature = 0;
_rawHumidity = 0;
_heatTimeout = 0;
_heaterStart = 0;
_heaterStop = 0;
_heaterOn = false;
_error = SHT_OK;
_type = 0;
_temperatureOffset = 0;
_humidityOffset = 0;
}
@ -88,17 +91,86 @@ bool SHT::begin(TwoWire *wire)
}
uint8_t SHT::getType()
{
return _type;
};
///////////////////////////////////////////////////
//
// SYNCHRONUOUS interface
//
bool SHT::read(bool fast)
{
requestData(fast);
while(dataReady(fast) == false) yield();
return readData(fast);
}
///////////////////////////////////////////////////
//
// ASYNCHRONUOUS interface
//
bool SHT::requestData(bool fast)
{
if (writeCmd(fast ? SHT_MEASUREMENT_FAST : SHT_MEASUREMENT_SLOW) == false)
{
return false;
}
delay(fast ? 4 : 15); // table 4 datasheet
return readData(fast);
_lastRequest = millis();
return true;
}
bool SHT::dataReady(bool fast)
{
return ((millis() - _lastRequest) > (fast ? 4 : 15));
}
bool SHT::readData(bool fast)
{
uint8_t buffer[6];
if (readBytes(6, (uint8_t*) &buffer[0]) == false)
{
return false;
}
if (!fast)
{
if (buffer[2] != crc8(buffer, 2))
{
_error = SHT_ERR_CRC_TEMP;
return false;
}
if (buffer[5] != crc8(buffer + 3, 2))
{
_error = SHT_ERR_CRC_HUM;
return false;
}
}
_rawTemperature = (buffer[0] << 8) + buffer[1];
_rawHumidity = (buffer[3] << 8) + buffer[4];
_lastRead = millis();
return true;
}
uint32_t SHT::lastRequest()
{
return _lastRequest;
};
///////////////////////////////////////////////////
//
// STATUS
//
bool SHT::isConnected()
{
_wire->beginTransmission(_address);
@ -152,7 +224,7 @@ uint16_t SHT::readStatus()
return 0xFFFF;
}
if (status[2] != crc8(status, 2))
if (status[2] != crc8(status, 2))
{
_error = SHT_ERR_CRC_STATUS;
return 0xFFFF;
@ -162,6 +234,12 @@ uint16_t SHT::readStatus()
}
uint32_t SHT::lastRead()
{
return _lastRead;
};
bool SHT::reset(bool hard)
{
bool b = writeCmd(hard ? SHT_HARD_RESET : SHT_SOFT_RESET);
@ -174,6 +252,18 @@ bool SHT::reset(bool hard)
}
int SHT::getError()
{
int rv = _error;
_error = SHT_OK;
return rv;
}
///////////////////////////////////////////////////
//
// HEATER
//
void SHT::setHeatTimeout(uint8_t seconds)
{
_heatTimeout = seconds;
@ -181,6 +271,12 @@ void SHT::setHeatTimeout(uint8_t seconds)
}
uint8_t SHT::getHeatTimeout()
{
return _heatTimeout;
};
bool SHT::heatOn()
{
if (isHeaterOn()) return true;
@ -230,75 +326,88 @@ bool SHT::isHeaterOn()
}
bool SHT::requestData()
//////////////////////////////////////////////////////////
//
// TEMPERATURE & HUMIDITY
//
float SHT::getHumidity()
{
if (writeCmd(SHT_MEASUREMENT_SLOW) == false)
{
return false;
}
_lastRequest = millis();
return true;
float hum = _rawHumidity * (100.0 / 65535);
if (_humidityOffset != 0) hum += _humidityOffset;
return hum;
}
bool SHT::dataReady()
float SHT::getTemperature()
{
return ((millis() - _lastRequest) > 15); // TODO MAGIC NR
float temp = _rawTemperature * (175.0 / 65535) - 45;
if (_temperatureOffset != 0) temp += _temperatureOffset;
return temp;
}
bool SHT::readData(bool fast)
float SHT::getFahrenheit()
{
uint8_t buffer[6];
if (readBytes(6, (uint8_t*) &buffer[0]) == false)
{
return false;
}
if (!fast)
{
if (buffer[2] != crc8(buffer, 2))
{
_error = SHT_ERR_CRC_TEMP;
return false;
}
if (buffer[5] != crc8(buffer + 3, 2))
{
_error = SHT_ERR_CRC_HUM;
return false;
}
}
_rawTemperature = (buffer[0] << 8) + buffer[1];
_rawHumidity = (buffer[3] << 8) + buffer[4];
_lastRead = millis();
return true;
float temp = _rawTemperature * (63.0 / 13107.0) - 49;
if (_temperatureOffset != 0) temp += _temperatureOffset * 1.8;
return temp;
}
int SHT::getError()
uint16_t SHT::getRawHumidity()
{
int rv = _error;
_error = SHT_OK;
return rv;
return _rawHumidity;
}
uint16_t SHT::getRawTemperature()
{
return _rawTemperature;
}
void SHT::setTemperatureOffset(float offset)
{
_temperatureOffset = offset;
}
float SHT::getTemperatureOffset()
{
return _temperatureOffset;
}
void SHT::setHumidityOffset(float offset)
{
_humidityOffset = offset;
}
float SHT::getHumidityOffset()
{
return _humidityOffset;
}
//////////////////////////////////////////////////////////
uint8_t SHT::crc8(const uint8_t *data, uint8_t len)
//
// PROTECTED
//
uint8_t SHT::crc8(const uint8_t *data, uint8_t len)
{
// CRC-8 formula from page 14 of SHT spec pdf
const uint8_t POLY(0x31);
uint8_t crc(0xFF);
for (uint8_t j = len; j; --j)
for (uint8_t j = len; j; --j)
{
crc ^= *data++;
for (uint8_t i = 8; i; --i)
for (uint8_t i = 8; i; --i)
{
crc = (crc & 0x80) ? (crc << 1) ^ POLY : (crc << 1);
}
@ -337,10 +446,9 @@ bool SHT::readBytes(uint8_t n, uint8_t *val)
}
////////////////////////////////////////////////////////
//
// DERIVED
// DERIVED CLASSES
//
SHT30::SHT30()
{
@ -367,3 +475,4 @@ SHT85::SHT85()
// -- END OF FILE --

View File

@ -2,7 +2,7 @@
//
// FILE: SHT85.h
// AUTHOR: Rob Tillaart
// VERSION: 0.3.3
// VERSION: 0.4.0
// DATE: 2021-02-10
// PURPOSE: Arduino library for the SHT85 temperature and humidity sensor
// https://nl.rs-online.com/web/p/temperature-humidity-sensor-ics/1826530
@ -10,6 +10,8 @@
//
// keep lib in sync with https://github.com/RobTillaart/SHT31
//
// ALWAYS check datasheet for connections.
//
// TOPVIEW SHT85
// +-------+
// +-----\ | SDA 4 -----
@ -23,10 +25,10 @@
#include "Wire.h"
#define SHT_LIB_VERSION (F("0.3.3"))
#define SHT_LIB_VERSION (F("0.4.0"))
#define SHT85_LIB_VERSION SHT_LIB_VERSION
#ifndef SHT_DEFAULT_ADDRESS
#ifndef SHT_DEFAULT_ADDRESS
#define SHT_DEFAULT_ADDRESS 0x44
#endif
@ -58,54 +60,70 @@ public:
SHT();
#if defined(ESP8266) || defined(ESP32)
bool begin(const uint8_t address, uint8_t dataPin, uint8_t clockPin);
bool begin(const uint8_t address, uint8_t dataPin, uint8_t clockPin);
// use SHT_DEFAULT_ADDRESS
bool begin(const uint8_t dataPin, const uint8_t clockPin);
bool begin(const uint8_t dataPin, const uint8_t clockPin);
#endif
bool begin(const uint8_t address, TwoWire *wire = &Wire);
bool begin(const uint8_t address, TwoWire *wire = &Wire);
// use SHT_DEFAULT_ADDRESS
bool begin(TwoWire *wire = &Wire);
bool begin(TwoWire *wire = &Wire);
uint8_t getType() { return _type; };
uint8_t getType();
// blocks 15 milliseconds + actual read + math
bool read(bool fast = true);
// SYNCHRONOUS INTERFACE
// read blocks 4 or 15 milliseconds + actual read + math
bool read(bool fast = true);
// ASYNCHRONOUS INTERFACE
bool requestData(bool fast = true);
bool dataReady(bool fast = true);
bool readData(bool fast = true);
uint32_t lastRequest();
// STATUS
// check sensor is reachable over I2C
bool isConnected();
bool isConnected();
// details see datasheet; summary in SHT85.cpp file
uint16_t readStatus();
// lastRead is in milliSeconds since start
uint32_t lastRead() { return _lastRead; };
uint32_t lastRead();
bool reset(bool hard = false);
bool reset(bool hard = false);
// returns last error and clears error flag
int getError();
// HEATER
// do not use heater for long periods,
// use it for max 3 minutes to heat up
// and let it cool down at least 3 minutes.
void setHeatTimeout(uint8_t seconds);
uint8_t getHeatTimeout() { return _heatTimeout; };
bool heatOn();
bool heatOff();
bool isHeaterOn(); // is the sensor still heating up?
void setHeatTimeout(uint8_t seconds);
uint8_t getHeatTimeout();
bool heatOn();
bool heatOff();
// is the sensor still heating up?
bool isHeaterOn();
float getHumidity() { return _rawHumidity * (100.0 / 65535); };
float getTemperature() { return _rawTemperature * (175.0 / 65535) - 45; };
float getFahrenheit() { return _rawTemperature * (63.0 /13107.0) - 49; };
uint16_t getRawHumidity() { return _rawHumidity; };
uint16_t getRawTemperature() { return _rawTemperature; };
// TEMPERATURE & HUMIDITY
float getHumidity();
float getTemperature();
float getFahrenheit();
uint16_t getRawHumidity();
uint16_t getRawTemperature();
// ASYNC INTERFACE
bool requestData();
bool dataReady();
bool readData(bool fast = true);
int getError(); // clears error flag
// TEMPERATURE & HUMIDITY OFFSET
void setTemperatureOffset(float offset = 0);
float getTemperatureOffset();
void setHumidityOffset(float offset = 0);
float getHumidityOffset();
protected:
@ -115,17 +133,22 @@ protected:
TwoWire* _wire;
uint8_t _address;
uint8_t _heatTimeout; // seconds
uint8_t _heatTimeout; // seconds
uint32_t _lastRead;
uint32_t _lastRequest; // for async interface
uint32_t _heaterStart;
uint32_t _heaterStop;
uint32_t _lastRequest; // for async interface
uint32_t _heaterStart; // timestamp
uint32_t _heaterStop; // timestamp
bool _heaterOn;
uint8_t _type;
uint8_t _type; // base class = 0
uint16_t _rawHumidity;
uint16_t _rawTemperature;
// offset in degrees Celsius
float _temperatureOffset = 0;
float _humidityOffset = 0;
uint8_t _error;
};
@ -133,7 +156,7 @@ protected:
////////////////////////////////////////////////////////
//
// DERIVED
// DERIVED CLASSES
//
class SHT30 : public SHT
{
@ -163,5 +186,5 @@ public:
};
// -- END OF FILE --
// -- END OF FILE --

View File

@ -32,7 +32,7 @@ void setup()
Wire.begin();
sht.begin(SHT85_ADDRESS);
for (uint32_t clk = 100000; clk < 550000; clk += 50000)
for (uint32_t clk = 50000; clk < 550000; clk += 50000)
{
Wire.setClock(clk);
start = micros();
@ -52,4 +52,4 @@ void loop()
}
// -- END OF FILE --
// -- END OF FILE --

View File

@ -0,0 +1,65 @@
//
// FILE: SHT85_demo_async.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo async interface
// URL: https://github.com/RobTillaart/SHT85
//
// TOPVIEW SHT85 (check datasheet)
// +-------+
// +-----\ | SDA 4 -----
// | +-+ ----+ GND 3 -----
// | +-+ ----+ +5V 2 -----
// +-----/ | SCL 1 -----
// +-------+
// TODO verify with HW
#include "SHT85.h"
#define SHT85_ADDRESS 0x44
SHT85 sht;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("SHT_LIB_VERSION: \t");
Serial.println(SHT_LIB_VERSION);
Wire.begin();
sht.begin(SHT85_ADDRESS);
Wire.setClock(100000);
uint16_t stat = sht.readStatus();
Serial.print(stat, HEX);
Serial.println();
sht.requestData();
}
void loop()
{
if (sht.dataReady())
{
sht.readData();
Serial.print("\t");
Serial.print(micros());
Serial.print("\t");
Serial.print(sht.lastRequest());
Serial.print("\t");
Serial.print(sht.getTemperature(), 1);
Serial.print("\t");
Serial.println(sht.getHumidity(), 1);
sht.requestData();
}
delay(1000); // do not call sensor too often (see datasheet)
}
// -- END OF FILE --

View File

@ -0,0 +1,90 @@
//
// FILE: SHT85_demo_offset.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/SHT85
//
// TOPVIEW SHT85 (check datasheet)
// +-------+
// +-----\ | SDA 4 -----
// | +-+ ----+ GND 3 -----
// | +-+ ----+ +5V 2 -----
// +-----/ | SCL 1 -----
// +-------+
#include "SHT85.h"
#define SHT85_ADDRESS 0x44
uint32_t start;
uint32_t stop;
uint16_t count = 0;
uint32_t last = 0;
SHT85 sht;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("SHT_LIB_VERSION: \t");
Serial.println(SHT_LIB_VERSION);
Wire.begin();
sht.begin(SHT85_ADDRESS);
Wire.setClock(100000);
// uint16_t stat = sht.readStatus();
// Serial.print(stat, HEX);
// Serial.println();
Serial.println("OffT\t OffH\t temp\t hum");
sht.setTemperatureOffset((random(100) - 50) * 0.01);
sht.setHumidityOffset((random(100) - 50) * 0.01);
}
void loop()
{
if (millis() - last >= 1000)
{
last = millis();
sht.read();
Serial.print(sht.getTemperatureOffset(), 2);
Serial.print("\t");
Serial.print(sht.getHumidityOffset(), 2);
Serial.print("\t");
Serial.print(sht.getTemperature(), 2);
Serial.print("\t");
Serial.println(sht.getHumidity(), 2);
}
}
void loop2()
{
if (millis() - last >= 1000)
{
last = millis();
sht.read();
// just add awfull noisy offset +-0.5 degrees C
sht.setTemperatureOffset((random(100) - 50) * 0.01);
sht.setHumidityOffset((random(100) - 50) * 0.01);
Serial.print(sht.getTemperatureOffset(), 2);
Serial.print("\t");
Serial.print(sht.getHumidityOffset(), 2);
Serial.print("\t");
Serial.print(sht.getTemperature(), 2);
Serial.print("\t");
Serial.println(sht.getHumidity(), 2);
}
}
// -- END OF FILE --

View File

@ -58,7 +58,7 @@ void loop()
Serial.print(sht.getTemperature(), 2);
Serial.print("\t");
Serial.println(sht.getHumidity(), 2);
if (millis() - last >= 100)
if (millis() - last >= 1000)
{
last = millis();
count = 0;
@ -66,5 +66,6 @@ void loop()
}
// -- END OF FILE --
// -- END OF FILE --

View File

@ -2,6 +2,10 @@
# Data types (KEYWORD1)
SHT KEYWORD1
SHT30 KEYWORD1
SHT31 KEYWORD1
SHT35 KEYWORD1
SHT85 KEYWORD1
@ -10,32 +14,43 @@ begin KEYWORD2
getType KEYWORD2
read KEYWORD2
requestData KEYWORD2
dataReady KEYWORD2
readData KEYWORD2
lastRequest KEYWORD2
isConnected KEYWORD2
readStatus KEYWORD2
lastRead KEYWORD2
reset KEYWORD2
getError KEYWORD2
setHeatTimeout KEYWORD2
getHeatTimeout KEYWORD2
heatOn KEYWORD2
heatOff KEYWORD2
isHeaterOn KEYWORD2
getHumidity KEYWORD2
getTemperature KEYWORD2
requestData KEYWORD2
dataReady KEYWORD2
readData KEYWORD2
getFahrenheit KEYWORD2
getRawHumidity KEYWORD2
getRawTemperature KEYWORD2
setTemperatureOffset KEYWORD2
getTemperatureOffset KEYWORD2
setHumidityOffset KEYWORD2
getHumidityOffset KEYWORD2
# Instances (KEYWORD2)
# Constants (LITERAL1)
SHT_LIB_VERSION LITERAL1
SHT_DEFAULT_ADDRESS
SHT_STATUS_ALERT_PENDING LITERAL1
SHT_STATUS_HEATER_ON LITERAL1
SHT_STATUS_HUM_TRACK_ALERT LITERAL1
@ -43,6 +58,15 @@ SHT_STATUS_TEMP_TRACK_ALERT LITERAL1
SHT_STATUS_SYSTEM_RESET LITERAL1
SHT_STATUS_COMMAND_STATUS LITERAL1
SHT_STATUS_WRITE_CRC_STATUS LITERAL1
SHT_OK LITERAL1
SHT_ERR_WRITECMD LITERAL1
SHT_ERR_READBYTES LITERAL1
SHT_ERR_HEATER_OFF LITERAL1
SHT_ERR_NOT_CONNECT LITERAL1
SHT_ERR_CRC_TEMP LITERAL1
SHT_ERR_CRC_HUM LITERAL1
SHT_ERR_CRC_STATUS LITERAL1
SHT_ERR_HEATER_COOLDOWN LITERAL1
SHT_ERR_HEATER_ON LITERAL1

View File

@ -1,7 +1,7 @@
{
"name": "SHT85",
"keywords": "SHT85,Temperature,Humidity,I2C,SHT30, SHT31, SHT35, Senserion",
"description": "Arduino library for the SHT85, SHT30, SHT31, SHT35 temperature and humidity sensor",
"description": "Arduino library for the SHT85, SHT30, SHT31, SHT35 temperature and humidity sensors and compatibles.",
"authors":
[
{
@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/SHT85"
},
"version": "0.3.3",
"version": "0.4.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,8 +1,8 @@
name=SHT85
version=0.3.3
version=0.4.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for the SHT85, SHT30, SHT31, SHT35 Senserion temperature and humidity sensor
sentence=Arduino library for the SHT85, SHT30, SHT31, SHT35 Senserion temperature and humidity sensors and compatibles.
paragraph=
category=Sensors
url=https://github.com/RobTillaart/SHT85

View File

@ -22,13 +22,14 @@
// assertNull(actual)
/*
most unit tests will test for fail
most unit tests will test for fail
as there is no sensor connected
and there is no mock-up.
It appears that Wire.write does not fail without sensor...
*/
#include <ArduinoUnitTests.h>
#include "Arduino.h"
@ -53,6 +54,8 @@ unittest_teardown()
unittest(test_constants_1)
{
assertEqual(SHT_DEFAULT_ADDRESS, 0x44);
fprintf(stderr, "fields readStatus\n");
assertEqual(SHT_STATUS_ALERT_PENDING , (1 << 15) );
assertEqual(SHT_STATUS_HEATER_ON , (1 << 13) );
@ -97,6 +100,7 @@ unittest(test_begin)
// default value == 0
assertEqual(-45, sht.getTemperature());
assertEqual(-49, sht.getFahrenheit());
assertEqual(0, sht.getHumidity());
assertEqual(0, sht.getRawTemperature());
assertEqual(0, sht.getRawHumidity());
@ -112,24 +116,6 @@ unittest(test_read)
assertTrue(sht.isConnected());
expect = SHT_OK;
assertEqual(expect, sht.getError());
assertFalse(sht.read());
expect = SHT_ERR_READBYTES;
assertEqual(expect, sht.getError());
start = millis();
assertFalse(sht.read(false));
stop = millis();
Serial.println(stop - start);
expect = SHT_ERR_READBYTES;
assertEqual(expect, sht.getError());
start = millis();
assertFalse(sht.read(true));
stop = millis();
Serial.println(stop - start);
expect = SHT_ERR_READBYTES;
assertEqual(expect, sht.getError());
}
@ -138,7 +124,7 @@ unittest(test_readStatus)
SHT85 sht;
bool b = sht.begin(0x44);
assertEqual(b, true);
assertEqual(0xFFFF, sht.readStatus());
expect = SHT_ERR_READBYTES;
assertEqual(expect, sht.getError());
@ -150,7 +136,7 @@ unittest(test_heater)
SHT85 sht;
bool b = sht.begin(0x44);
assertEqual(b, true);
assertTrue(sht.heatOn());
expect = SHT_OK;
assertEqual(expect, sht.getError());
@ -170,7 +156,7 @@ unittest(test_async)
SHT85 sht;
bool b = sht.begin(0x44);
assertEqual(b, true);
assertTrue(sht.requestData());
expect = SHT_OK;
assertEqual(expect, sht.getError());
@ -193,6 +179,47 @@ unittest(test_async)
}
unittest(test_offset)
{
SHT85 sht;
fprintf(stderr, "temperature\n");
for (int i = -5; i < 6; i++)
{
sht.setTemperatureOffset(i);
assertEqual(i, sht.getTemperatureOffset());
}
fprintf(stderr, "humidity\n");
for (int i = -5; i < 6; i++)
{
sht.setHumidityOffset(i);
assertEqual(i, sht.getHumidityOffset());
}
}
//////////////////////////////////////////
//
// Test derived types
//
unittest(test_getType)
{
SHT sht;
SHT30 sht0;
SHT31 sht1;
SHT35 sht2;
SHT85 sht3;
assertEqual(00, sht.getType());
assertEqual(30, sht0.getType());
assertEqual(31, sht1.getType());
assertEqual(35, sht2.getType());
assertEqual(85, sht3.getType());
}
unittest_main()
// --------
// -- END OF FILE --