Compare commits

...

3 Commits

Author SHA1 Message Date
Rob Tillaart
27e7621c92 0.1.1 LTR390_DFR 2024-09-25 12:05:56 +02:00
Rob Tillaart
090aa0cf8a 0.2.1 TLC5917 2024-09-24 14:41:56 +02:00
Rob Tillaart
054d79afa9 0.2.2 CHT8305 2024-09-22 11:42:37 +02:00
33 changed files with 881 additions and 247 deletions

View File

@ -6,12 +6,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.2] - 2024-09-16
- Fix #15, improve error handling.
- add return value **CHT8305_ERROR_BUFSIZE**
- add return value **CHT8305_ERROR_GENERIC**
- add return value **0xFFFF** for 2 functions.
- set default values 0.0 for **offset** parameters.
- fix missing names in keywords.txt
- add plotter and performance example
- update readme.md.
## [0.2.1] - 2024-01-30
- add multiplexing section to readme.md
- update examples (URL)
- minor edits
## [0.2.0] - 2023-12-05
- refactor API, constructor, begin()
- update readme.md

View File

@ -1,7 +1,7 @@
//
// FILE: CHT8305.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.1
// VERSION: 0.2.2
// PURPOSE: Arduino library for CHT8305 temperature and humidity sensor
// URL: https://github.com/RobTillaart/CHT8305
@ -17,14 +17,24 @@ CHT8305::CHT8305(const uint8_t address, TwoWire *wire)
{
_wire = wire;
_address = address;
_error = CHT8305_OK;
}
int CHT8305::begin()
{
if ((_address < 0x40) || (_address > 0x43)) return CHT8305_ERROR_ADDR;
if (! isConnected()) return CHT8305_ERROR_CONNECT;
return CHT8305_OK;
if ((_address < 0x40) || (_address > 0x43))
{
_error = CHT8305_ERROR_ADDR;
return _error;
}
if (! isConnected())
{
_error = CHT8305_ERROR_CONNECT;
return _error;
}
_error = CHT8305_OK;
return _error;
}
@ -50,27 +60,33 @@ int CHT8305::read()
// do not read too fast
if (millis() - _lastRead < 1000)
{
return CHT8305_ERROR_LASTREAD;
_error = CHT8305_ERROR_LASTREAD;
return _error;
}
_lastRead = millis();
uint8_t data[4] = {0, 0, 0, 0 };
_readRegister(CHT8305_REG_TEMPERATURE, &data[0], 4);
if (_readRegister(CHT8305_REG_TEMPERATURE, &data[0], 4) != CHT8305_OK)
{
return _error;
}
uint16_t tmp = data[0] << 8 | data[1];
uint16_t tmp = (data[0] << 8) | data[1];
_temperature = tmp * (165.0 / 65535.0) - 40.0;
tmp = data[2] << 8 | data[3];
tmp = (data[2] << 8) | data[3];
_humidity = tmp * (1.0 / 655.35); // == / 65535 * 100%
if (_tempOffset != 0.0) _temperature += _tempOffset;
if (_humOffset != 0.0)
if (_humOffset != 0.0)
{
_humidity += _humOffset;
if (_humidity < 0.0) _humidity = 0.0;
if (_humidity > 100.0) _humidity = 100.0;
}
return CHT8305_OK;
_error = CHT8305_OK;
return _error;
}
@ -79,14 +95,18 @@ int CHT8305::readTemperature()
// do not read too fast
if (millis() - _lastRead < 1000)
{
return CHT8305_ERROR_LASTREAD;
_error = CHT8305_ERROR_LASTREAD;
return _error;
}
_lastRead = millis();
uint8_t data[2] = {0, 0};
_readRegister(CHT8305_REG_TEMPERATURE, &data[0], 2);
if (_readRegister(CHT8305_REG_TEMPERATURE, &data[0], 2) != CHT8305_OK)
{
return _error;
}
uint16_t tmp = data[0] << 8 | data[1];
uint16_t tmp = (data[0] << 8) | data[1];
_temperature = tmp * (165.0 / 65535.0) - 40.0;
if (_tempOffset != 0.0)
@ -94,7 +114,8 @@ int CHT8305::readTemperature()
_temperature += _tempOffset;
}
return CHT8305_OK;
_error = CHT8305_OK;
return _error;
}
@ -103,14 +124,18 @@ int CHT8305::readHumidity()
// do not read too fast
if (millis() - _lastRead < 1000)
{
return CHT8305_ERROR_LASTREAD;
_error = CHT8305_ERROR_LASTREAD;
return _error;
}
_lastRead = millis();
uint8_t data[2] = {0, 0};
_readRegister(CHT8305_REG_HUMIDITY, &data[0], 2);
if (_readRegister(CHT8305_REG_HUMIDITY, &data[0], 4) != CHT8305_OK)
{
return _error;
}
uint16_t tmp = data[0] << 8 | data[1];
uint16_t tmp = (data[0] << 8) | data[1];
_humidity = tmp * (1.0 / 655.35); // == / 65535 * 100%
if (_humOffset != 0.0)
@ -120,7 +145,8 @@ int CHT8305::readHumidity()
if (_humidity > 100.0) _humidity = 100.0;
}
return CHT8305_OK;
_error = CHT8305_OK;
return _error;
}
@ -184,20 +210,27 @@ float CHT8305::getTemperatureOffset()
//
// CONFIGURATION REGISTER
//
void CHT8305::setConfigRegister(uint16_t bitmask)
bool CHT8305::setConfigRegister(uint16_t bitmask)
{
uint8_t data[2];
data[0] = bitmask >> 8;
data[1] = bitmask & 0xFF;
_writeRegister(2, &data[0], 2);
if (_writeRegister(2, &data[0], 2) != CHT8305_OK)
{
return false;
}
return true;
}
uint16_t CHT8305::getConfigRegister()
{
uint8_t data[2] = { 0, 0};
_readRegister(CHT8305_REG_CONFIG, &data[0], 2);
uint16_t tmp = data[0] << 8 | data[1];
if (_readRegister(CHT8305_REG_CONFIG, &data[0], 2) != CHT8305_OK)
{
return 0;
}
uint16_t tmp = (data[0] << 8) | data[1];
return tmp;
}
@ -344,7 +377,10 @@ bool CHT8305::setAlertLevels(float temperature, float humidity)
tmp = (temperature + 40.0) * (511.0 / 165.0);
mask |= tmp;
_writeRegister(CHT8305_REG_ALERT, (uint8_t *)&mask, 2);
if (_writeRegister(CHT8305_REG_ALERT, (uint8_t *)&mask, 2) != CHT8305_OK)
{
return false;
}
return true;
}
@ -352,7 +388,10 @@ bool CHT8305::setAlertLevels(float temperature, float humidity)
float CHT8305::getAlertLevelTemperature()
{
uint16_t data = 0;
_readRegister(CHT8305_REG_ALERT, (uint8_t *)&data, 2);
if (_readRegister(CHT8305_REG_ALERT, (uint8_t *)&data, 2) != CHT8305_OK)
{
return CHT8305_ERROR_GENERIC;
}
data &= 0x01FF;
data <<= 7;
return data * (165.0 / 65535.0) - 40.0;
@ -362,7 +401,10 @@ float CHT8305::getAlertLevelTemperature()
float CHT8305::getAlertLevelHumidity()
{
uint16_t data = 0;
_readRegister(CHT8305_REG_ALERT, (uint8_t *)&data, 2);
if (_readRegister(CHT8305_REG_ALERT, (uint8_t *)&data, 2) != CHT8305_OK)
{
return CHT8305_ERROR_GENERIC;
}
data &= 0xFE00;
return data * (100.0 / 65535.0);
}
@ -375,8 +417,11 @@ float CHT8305::getAlertLevelHumidity()
float CHT8305::getVoltage()
{
uint8_t data[2] = { 0, 0};
_readRegister(CHT8305_REG_VOLTAGE, &data[0], 2);
uint16_t tmp = data[0] << 8 | data[1];
if (_readRegister(CHT8305_REG_VOLTAGE, &data[0], 2) != CHT8305_OK)
{
return CHT8305_ERROR_GENERIC;
}
uint16_t tmp = (data[0] << 8) | data[1];
return tmp * (5.0 / 32768.0); // best guess
}
@ -388,8 +433,11 @@ float CHT8305::getVoltage()
uint16_t CHT8305::getManufacturer()
{
uint8_t data[2] = { 0, 0};
_readRegister(CHT8305_REG_MANUFACTURER, &data[0], 2);
uint16_t tmp = data[0] << 8 | data[1];
if (_readRegister(CHT8305_REG_MANUFACTURER, &data[0], 2) != CHT8305_OK)
{
return 0xFFFF;
}
uint16_t tmp = (data[0] << 8) | data[1];
return tmp;
}
@ -397,12 +445,23 @@ uint16_t CHT8305::getManufacturer()
uint16_t CHT8305::getVersionID()
{
uint8_t data[2] = { 0, 0};
_readRegister(CHT8305_REG_VERSION, &data[0], 2);
uint16_t tmp = data[0] << 8 | data[1];
if (_readRegister(CHT8305_REG_VERSION, &data[0], 2) != CHT8305_OK)
{
return 0xFFFF;
}
uint16_t tmp = (data[0] << 8) | data[1];
return tmp;
}
int CHT8305::getLastError()
{
int e = _error;
_error = CHT8305_OK;
return e;
}
////////////////////////////////////////////////
//
// PRIVATE
@ -412,7 +471,11 @@ int CHT8305::_readRegister(uint8_t reg, uint8_t * buf, uint8_t size)
_wire->beginTransmission(_address);
_wire->write(reg);
int n = _wire->endTransmission();
if (n != 0) return CHT8305_ERROR_I2C;
if (n != 0)
{
_error = CHT8305_ERROR_I2C;
return _error;
}
if (reg == CHT8305_REG_TEMPERATURE) // wait for conversion...
{
@ -420,14 +483,17 @@ int CHT8305::_readRegister(uint8_t reg, uint8_t * buf, uint8_t size)
}
n = _wire->requestFrom(_address, size);
if (n == size)
if (n != size)
{
for (uint8_t i = 0; i < size; i++)
{
buf[i] = _wire->read();
}
_error = CHT8305_ERROR_BUFSIZE;
return _error;
}
return CHT8305_OK;
for (uint8_t i = 0; i < size; i++)
{
buf[i] = _wire->read();
}
_error = CHT8305_OK;
return _error;
}
@ -440,8 +506,13 @@ int CHT8305::_writeRegister(uint8_t reg, uint8_t * buf, uint8_t size)
_wire->write(buf[i]);
}
int n = _wire->endTransmission();
if (n != 0) return CHT8305_ERROR_I2C;
return CHT8305_OK;
if (n != 0)
{
_error = CHT8305_ERROR_I2C;
return _error;
}
_error = CHT8305_OK;
return _error;
}

View File

@ -2,7 +2,7 @@
//
// FILE: CHT8305.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.1
// VERSION: 0.2.2
// PURPOSE: Arduino library for CHT8305 temperature and humidity sensor
// URL: https://github.com/RobTillaart/CHT8305
//
@ -12,30 +12,34 @@
#include "Wire.h"
#define CHT8305_LIB_VERSION (F("0.2.1"))
#define CHT8305_LIB_VERSION (F("0.2.2"))
// DEFAULT ADDRESS
#ifndef CHT8305_DEFAULT_ADDRESS
#define CHT8305_DEFAULT_ADDRESS 0x40
#endif
// ERRORS
#define CHT8305_OK 0
#define CHT8305_ERROR_ADDR -10
#define CHT8305_ERROR_I2C -11
#define CHT8305_ERROR_CONNECT -12
#define CHT8305_ERROR_BUFSIZE -13
#define CHT8305_ERROR_LASTREAD -20
#define CHT8305_ERROR_GENERIC -999
// REGISTERS
#define CHT8305_REG_TEMPERATURE 0x00
#define CHT8305_REG_HUMIDITY 0x01
#define CHT8305_REG_CONFIG 0x02
#define CHT8305_REG_ALERT 0x03
#define CHT8305_REG_VOLTAGE 0x04
#define CHT8305_REG_MANUFACTURER 0xFE
#define CHT8305_REG_VERSION 0xFF
// REGISTER MASKS
// REGISTERS (in .h for build-CI test)
#define CHT8305_REG_TEMPERATURE 0x00
#define CHT8305_REG_HUMIDITY 0x01
#define CHT8305_REG_CONFIG 0x02
#define CHT8305_REG_ALERT 0x03
#define CHT8305_REG_VOLTAGE 0x04
#define CHT8305_REG_MANUFACTURER 0xFE
#define CHT8305_REG_VERSION 0xFF
// REGISTER MASKS (in .h for build-CI test)
#define CHT8305_CFG_SOFT_RESET 0x8000
#define CHT8305_CFG_CLOCK_STRETCH 0x4000
#define CHT8305_CFG_HEATER 0x2000
@ -78,15 +82,16 @@ public:
// adding offsets works well in normal range
void setHumidityOffset(float offset);
void setHumidityOffset(float offset = 0.0);
// might introduce under- or overflow at the ends of the sensor range
void setTemperatureOffset(float offset);
void setTemperatureOffset(float offset = 0.0);
float getHumidityOffset();
float getTemperatureOffset();
// CONFIGURATION REGISTER
void setConfigRegister(uint16_t bitmask);
// default configRegister = 0x1004 (explicit no default parameter)
bool setConfigRegister(uint16_t bitmask);
uint16_t getConfigRegister();
//
// | bit | mask | name | description |
@ -132,13 +137,12 @@ public:
void setVCCenable(bool enable = true);
bool getVCCenable();
// ALERT FUNCTIONS
// mode trigger
// 0 T or H (default)
// 1 T
// 2 H
// 3 T and H
// ALERT FUNCTIONS
// mode trigger
// 0 T or H (default)
// 1 T
// 2 H
// 3 T and H
bool setAlertTriggerMode(uint8_t mode = 0);
uint8_t getAlertTriggerMode();
bool getAlertPendingStatus();
@ -153,6 +157,8 @@ public:
// VOLTAGE
// one need to call setVCCenable(true) first.
// meaning of this function is unclear.
float getVoltage();
@ -161,6 +167,9 @@ public:
uint16_t getVersionID(); // may vary
// ERROR HANDLING
int getLastError();
private:
float _humOffset = 0.0;
float _tempOffset = 0.0;
@ -177,6 +186,8 @@ private:
void _setConfigMask(uint16_t mask);
void _clrConfigMask(uint16_t mask);
int _error = CHT8305_OK;
};

View File

@ -15,7 +15,8 @@ Arduino library for CHT8305 temperature and humidity sensor.
**EXPERIMENTAL** minimal tested.
If you are able to test this library, please let me know your experiences.
If you are able to test this library, please let me know
your experiences.
## Description
@ -34,25 +35,25 @@ One of the interesting functions is the support of an ALERT function.
This prevents the need for continuous polling of the sensor.
#### 0.2.0 Breaking change
### 0.2.0 Breaking change
Version 0.2.0 introduced a breaking change.
You cannot set the pins in **begin()** any more.
This reduces the dependency of processor dependent Wire implementations.
The user has to call **Wire.begin()** and can optionally set the Wire pins
The user has to call **Wire.begin()** and can optionally set the Wire pins
before calling **begin()**.
Moved the address parameter from **begin()** to constructor.
#### Tests
### Tests
- Temperature and humidity functions works on AVR.
- default about 14 milliseconds at 14 bit resolution.
- offset functions work.
- getVoltage() function works on AVR but meaning unclear.
- getManufacturer(), getVersionID() works on AVR.
-
-
The ALERT functions are not tested.
The reason is that the sensor I have does not expose the ALERT pin.
@ -86,20 +87,43 @@ Always check datasheet for connections.
Pull ups are needed on SDA, SCL and optional to ALERT.
#### Alert
### Alert
The CHT8305 has an ALERT logic output pin with an open drain structure.
This output is active low. (if the breakout supports this.)
## I2C
## I2C
#### performance
### performance
I2C bus speeds is supported up to 400 KHz.
I2C bus speeds is supported up to 400 kHz.
In practice the sensor seems to work even at 800 kHz.
However not clear if the higher speed brings extra wear?
As the sensor / library blocks on reading the temperature
using high I2C speeds does not make a difference, except
for reading Humidity.
So a higher I2C speed does not help to read this sensor.
See - HT8305_performance.ino
#### Addresses
| SPEED | READ | READ_T | READ_H |
|:--------:|:-------:|:--------:|:--------:|
| 100000 | 14824 | 14604 | 376 |
| 200000 | 14476 | 14360 | 224 |
| 300000 | 14368 | 14276 | 172 |
| 400000 | 14324 | 14244 | 148 |
| 500000 | 14300 | 14224 | 140 |
| 600000 | 14276 | 14212 | 132 |
| 700000 | 14272 | 14204 | 124 |
| 800000 | 14268 | 14196 | 120 |
### Addresses
| AD0 | Address | Notes |
|:-----:|:----------:|:--------|
@ -111,19 +135,19 @@ I2C bus speeds is supported up to 400 KHz.
Pull ups are needed on SDA, SCL and optional to ALERT.
#### I2C multiplexing
### I2C multiplexing
Sometimes you need to control more devices than possible with the default
address range the device provides.
This is possible with an I2C multiplexer e.g. TCA9548 which creates up
to eight channels (think of it as I2C subnets) which can use the complete
address range of the device.
This is possible with an I2C multiplexer e.g. TCA9548 which creates up
to eight channels (think of it as I2C subnets) which can use the complete
address range of the device.
Drawback of using a multiplexer is that it takes more administration in
your code e.g. which device is on which channel.
Drawback of using a multiplexer is that it takes more administration in
your code e.g. which device is on which channel.
This will slow down the access, which must be taken into account when
deciding which devices are on which channel.
Also note that switching between channels will slow down other devices
Also note that switching between channels will slow down other devices
too if they are behind the multiplexer.
- https://github.com/RobTillaart/TCA9548
@ -135,16 +159,16 @@ too if they are behind the multiplexer.
#include "CHT8305.h"
```
#### Constructor
### Constructor
- **CHT8305(const uint8_t address = CHT8305_DEFAULT_ADDRESS, TwoWire \*wire = &Wire)** Constructor
with default address (0x40) and I2C bus.
- **CHT8305(const uint8_t address = CHT8305_DEFAULT_ADDRESS, TwoWire \*wire = &Wire)**
Constructor with default address (0x40) and I2C bus.
- **int begin()** initializes internals.
Returns error status.
- **bool isConnected()** checks if address (default 0x40) can be seen on the I2C bus.
#### Core
### Core
- **int read()** reads both the temperature and humidity.
Can be called once per second.
@ -153,49 +177,63 @@ Can be called once per second.
- **uint32_t lastRead()** returns lastRead in MilliSeconds since start sketch.
Useful to check when it is time to call **read()** again, or for logging.
- **float getHumidity()** returns last humidity read.
Will return the same value until **read()** or **readTemperature()** is called again.
- **float getTemperature()** returns last temperature read.
Will return the same value until **read()** or **readHumidity()** is called again.
- **float getTemperature()** returns last temperature read.
Will return the same value until **read()** or **readTemperature()** is called again.
Note: read(), readTemperature() and readHumidity() blocks each other,
Note: **read()**, **readTemperature()** and **readHumidity()** block each other,
so you can call only one of them every second.
#### Conversion delay
### Conversion delay
- **void setConversionDelay(uint8_t cd = 14)** default is 14 milliseconds (datasheet).
7 ms failed. 8 ms worked, so values below 8 are mapped to 8 in the library.
Expect 10 ms is pretty save. Use at own risk.
- **void setConversionDelay(uint8_t cd = 14)** default is 14 milliseconds
(from the datasheet). 7 milliseconds failed and 8 milliseconds worked.
So values below 8 milliseconds are mapped to 8 in the library.
Expect that 10 milliseconds is a pretty save value to work with.
Adjust this setting at your own risk.
It might be that lower resolutions allow shorter delays. This is not tested.
- **uint8_t getConversionDelay()** returns set value.
- **uint8_t getConversionDelay()** returns the default (14) or last set value.
#### Offset
### Offset
Adding offsets works well in the "normal range" but might introduce
Adding offsets works well in the "normal range" but might introduce
under- or overflow at the ends of the sensor range.
These are not handled for temperature by the library (humidity since 0.1.7).
- **void setHumidityOffset(float offset)** idem.
- **void setTemperatureOffset(float offset)** idem.
- **void setHumidityOffset(float offset = 0.0)** idem. Default is set to
zero, for an easy reset off the offset.
There is no range check in this function, however, **read()** will
keep the value between 0 and 100%.
- **void setTemperatureOffset(float offset = 0.0)** idem. Default is set to
zero, for an easy reset off the offset.
There is no range check in this function.
- **float getHumidityOffset()** idem.
- **float getTemperatureOffset()** idem.
If the offset is not the same over the operational range,
If the offset is not the same over the operational range,
consider a mapping function for temperature and humidity.
e.g. https://github.com/RobTillaart/MultiMap
#### Configuration register
### Configuration register
Check the datasheet for details of the register bits.
- **void setConfigRegister(uint16_t bitmask)** idem. Default value 0x1004.
- **uint16_t getConfigRegister()** idem.
- **bool setConfigRegister(uint16_t bitmask)** See table below.
Default value 0x1004.
Returns false if write to the config register fails.
Check **getLastError()** for possible cause.
- **uint16_t getConfigRegister()** idem.
If 0x0000 is returned it may indicate an error.
Check **getLastError()** for possible cause.
Bits of configRegister, check datasheet for details.
| bit | mask | name | description |
|:-----:|:------:|:----------------|:--------------|
| 15 | 0x8000 | soft reset | 1 = reboot the sensor to default
| 15 | 0x8000 | soft reset | 1 = reboot the sensor to default
| 14 | 0x4000 | clock stretch | 1 = ON, 0 = OFF (default)
| 13 | 0x2000 | heater | 1 = ON, 0 = OFF (default)
| 12 | 0x1000 | mode | 1 = read both (default), 0 = read T or RH
@ -207,39 +245,40 @@ Check the datasheet for details of the register bits.
| 4 | 0x0010 | H-ALT | Humidity Alert status
| 3 | 0x0008 | T-ALT | Temperature Alert status
| 2 | 0x0004 | VCC enable | 1 = enable VCC measurement (default), 0 = disable
| 1-0 | 0x0003 | reserved. | do not change.
| 1-0 | 0x0003 | reserved. | do not change.
#### Getters / setters configuration register
### Getters / setters configuration register
Note: setting **setConfigRegister(bitmask)** can be faster.
Wrapper functions for easy configuration.
Wrapper functions for easy configuration. Read the datasheet for the details.
- **void softReset()** sets the soft reset bit in the configuration, causing the sensor to reset.
- **void softReset()** sets the soft reset bit in the configuration,
causing the sensor to reset.
- **void setI2CClockStretch(bool on = false)** check datasheet.
- **bool getI2CClockStretch()** check datasheet.
- **void setHeaterOn(bool on = false)** switch on internal heater.
- **void setHeaterOn(bool on = false)** switch on internal heater.
Can improve humidity readings.
See datasheet for (limited) details.
- **WARNING** User is responsible for timing as library does not support timing.
- **bool getHeater()** Returns status of the heater.
- **void setMeasurementMode(bool both = true)** both T and H or single value.
- **bool getMeasurementMode()** returns mode set above.
- **bool getMeasurementMode()** returns mode set above.
- **bool getVCCstatus()** 1 == > 2.8V 0 == < 2.8V Useful when battery operated?
- **void setTemperatureResolution(uint8_t res = 0)** 1 = 11 bit, 0 = 14 bit (default).
- **uint8_t getTemperatureResolution()** idem.
- **void setHumidityResolution(uint8_t res = 0)** 2 = 8 bit, 1 = 11 bit, 0 = 14 bit (default).
- **uint8_t getHumidityResolution()** idem.
- **void setVCCenable(bool enable = false)** idem.
- **bool getVCCenable()** idem.
- **void setVCCenable(bool enable = false)** enable VCC measurement of the power supply.
- **bool getVCCenable()** return current status of enable bit.
#### Alert
### Alert
See register 3 datasheet page 12 for details.
- **void setAlertTriggerMode(uint8_t mode)** see table below.
- **void setAlertTriggerMode(uint8_t mode = 0)** see table below.
- **uint8_t getAlertTriggerMode()** returns 0, 1, 2 or 3.
| mode | trigger | notes |
@ -252,7 +291,7 @@ See register 3 datasheet page 12 for details.
- **bool getAlertPendingStatus()** idem.
- **bool getAlertHumidityStatus()** idem.
- **bool getAlertTemperatureStatus()** idem.
- **bool setAlertLevels(float temperature, float humidity)**
- **bool setAlertLevels(float temperature, float humidity)**
- the values will be truncated to the nearest value possible.
- the ALERT supports HIGH limit only ==> there is no LOW limit ALERT.
- note: the datasheet is ambiguous with respect to the formula used.
@ -263,27 +302,53 @@ See register 3 datasheet page 12 for details.
The ALERT pin triggers with a falling edge (from HIGH to LOW).
#### Voltage
### Supply voltage
VCC measurement should be enabled by means of **void setVCCenable(true)**
or by **setConfigRegister(0x0004)**.
(datasheet 1.1.5)
The chip has a feature to measure supply voltage (VCC) with 16bit output data.
VCC measurement should be enabled by means of **void setVCCenable(true)**.
- **float getVoltage()** unclear what unit is used.
Best guess for now: 16 bit data implies ```voltage = 5.0V * value / 32768.0;```
Best guess for now: 16 bit data implies ```voltage = 5.0V * value / 32767.0;```
Varied slightly 5.000 - 4.999 also for 3V3 power supply.
Conclusion: it is unclear how to interpret this register.
Conclusion: it is not 100 % clear how to interpret this register.
#### Meta data
### Meta data
- **uint16_t getManufacturer()** returns 0x5959.
- **uint16_t getVersionID()** return value may differ.
- **uint16_t getVersionID()** return value may differ.
Test returned 0x8305.
#### Register map
### Error handling
Since 0.2.2 some error handling has been added.
This need to be improved in the future.
- **getLastError()** returns 0 if all is OK.
If it doesn't return 0 an error occurred during **read()** et al.
The table gives some information where the problem occurred.
A call to **getLastError()** resets the internal error flag.
Note: in case of e.g. an I2C error, the last values of Temperature
and Humidity do not change.
| Error constant | value | Notes |
|:-------------------------|:--------:|:--------|
| CHT8305_OK | 0 |
| CHT8305_ERROR_ADDR | -10 |
| CHT8305_ERROR_I2C | -11 |
| CHT8305_ERROR_CONNECT | -12 |
| CHT8305_ERROR_BUFSIZE | -13 |
| CHT8305_ERROR_LASTREAD | -20 |
| CHT8305_ERROR_GENERIC | -999 |
| | 0xFFFF | patch |
### Register map
See datasheet page 10 for details
@ -303,25 +368,26 @@ See datasheet page 10 for details
#### Must
- elaborate documentation.
- more testing (platforms)
#### Should
- test ESP32, other platforms?
- test performance.
- test other platforms
- ESP32,
- test resolution bits.
- delay ?
- test configuration functions.
- test ALERT functions.
- test write / readRegister with a single uint16_t to simplify code.
- test error handling.
#### Could
- parameter testing
- parameter defaults?
- investigate asynchronous reading
- request, ready (after 15 millis), fetch
- needs lastRequest timestamp
- configRegister => force bit 0 and 1 to 0
#### Wont

View File

@ -0,0 +1,83 @@
//
// FILE: CHT8305_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: I2C performance for CHT8305 I2C humidity & temperature sensor
// URL: https://github.com/RobTillaart/CHT8305
// Always check datasheet - front view
//
// +---------------+
// VCC ----| VCC |
// SDA ----| SDA CHT8305 | CHECK DATASHEET.
// GND ----| GND |
// SCL ----| SCL |
// ? ----| AD0 | ? depends on address to select
// | |
// IRQ ----| ALERT | only if enabled.
// +---------------+
//
// check datasheet
// VCC RED
// GND BLACK
// SDA YELLOW
// SCL WHITE
#include "CHT8305.h"
CHT8305 CHT(0x40); // CHT8305_DEFAULT_ADDRESS = 0x40
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("CHT8305_LIB_VERSION: ");
Serial.println(CHT8305_LIB_VERSION);
Serial.println();
delay(100);
Wire.begin();
CHT.begin();
delay(1000);
Serial.println("Note: reading temperature is blocking!\n");
Serial.println("SPEED\tREAD\tREAD_T\tREAD_H");
for (uint32_t speed = 100000; speed <= 800000; speed += 50000)
{
Wire.setClock(speed);
start = micros();
CHT.read();
stop = micros();
Serial.print(speed);
Serial.print("\t");
Serial.print(stop - start);
delay(1000);
start = micros();
CHT.readTemperature();
stop = micros();
Serial.print("\t");
Serial.print(stop - start);
delay(1000);
start = micros();
CHT.readHumidity();
stop = micros();
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\n");
delay(1000);
}
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,24 @@
IDE: 1.8.19
Board: Arduino
CHT8305_LIB_VERSION: 0.2.2
Note: reading temperature is blocking!
SPEED READ READ_T READ_H
100000 14824 14604 384
150000 14596 14440 276
200000 14480 14360 224
250000 14416 14312 192
300000 14368 14276 168
350000 14340 14252 156
400000 14332 14244 152
450000 14308 14236 144
500000 14300 14232 140
550000 14284 14212 132
600000 14280 14220 132
650000 14272 14208 128
700000 14268 14204 124
750000 14260 14196 120
800000 14264 14200 120

View File

@ -0,0 +1,65 @@
//
// FILE: CHT8305_plotter.ino
// AUTHOR: Rob Tillaart
// PURPOSE: Demo for CHT8305 I2C humidity & temperature sensor
// URL: https://github.com/RobTillaart/CHT8305
//
// to be used with Arduino plotter.
//
// Always check datasheet - front view
//
// +---------------+
// VCC ----| VCC |
// SDA ----| SDA CHT8305 | CHECK DATASHEET.
// GND ----| GND |
// SCL ----| SCL |
// ? ----| AD0 | ? depends on address to select
// | |
// IRQ ----| ALERT | only if enabled.
// +---------------+
//
// check datasheet
// VCC RED
// GND BLACK
// SDA YELLOW
// SCL WHITE
#include "CHT8305.h"
CHT8305 CHT(0x40); // CHT8305_DEFAULT_ADDRESS = 0x40
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("CHT8305_LIB_VERSION: ");
Serial.println(CHT8305_LIB_VERSION);
Serial.println();
Wire.begin();
Wire.setClock(400000);
CHT.begin();
delay(1000);
}
void loop()
{
if (millis() - CHT.lastRead() >= 1000)
{
// READ DATA
CHT.read();
Serial.print(CHT.getLastError());
Serial.print('\t');
Serial.print(CHT.getHumidity());
Serial.print('\t');
Serial.println(CHT.getTemperature());
}
}
// -- END OF FILE --

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -7,11 +7,15 @@ CHT8305 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
isConnected KEYWORD2
getAddress KEYWORD2
read KEYWORD2
readTemperature KEYWORD2
readHumidity KEYWORD2
lastRead KEYWORD2
getTemperature KEYWORD2
getHumidity KEYWORD2
getTemperature KEYWORD2
setConversionDelay KEYWORD2
getConversionDelay KEYWORD2
@ -50,8 +54,20 @@ setAlertLevels KEYWORD2
getAlertLevelTemperature KEYWORD2
getAlertLevelHumidity KEYWORD2
getVoltage KEYWORD2
getManufacturer KEYWORD2
getVersionID KEYWORD2
# Constants (LITERAL1)
CHT8305_LIB_VERSION LITERAL1
CHT8305_DEFAULT_ADDRESS LITERAL1
CHT8305_OK LITERAL1
CHT8305_ERROR_ADDR LITERAL1
CHT8305_ERROR_I2C LITERAL1
CHT8305_ERROR_CONNECT LITERAL1
CHT8305_ERROR_LASTREAD LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/CHT8305.git"
},
"version": "0.2.1",
"version": "0.2.2",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

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

View File

@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.1] - 2024-09-23
- extend functionality and documentation
- add return value in **setGain()** 0..4
- add param check in **bool setMeasurement(resolution,time)**
- refactored code for readability (e.g. magic numbers).
- add **bool setUVsensitivity(float s)** and **float getUVsensitivity()()**
- update keywords.txt (prepare)
## [0.1.0] - 2024-04-29
- initial version

View File

@ -3,7 +3,7 @@
// FILE: LTR390_DFR.h
// AUTHOR: Rob Tillaart
// DATE: 2024-04-29
// VERSION: 0.1.0
// VERSION: 0.1.1
// PURPOSE: Arduino library for the I2C LTR390 UV sensor (DF Robotics edition).
// URL: https://github.com/RobTillaart/LTR390_DFR
@ -12,10 +12,10 @@
#include "Wire.h"
#define LTR390_DFR_LIB_VERSION (F("0.1.0"))
#define LTR390_DFR_LIB_VERSION (F("0.1.1"))
// LTR390 ERROR CODES
// TODO
#define LTR390_OK 0x00
// DF_ROBOTICS LTR390 REGISTERS (16 bits)
@ -77,12 +77,16 @@ public:
//
void setALSMode()
{
writeRegister(LTR390_MAIN_CTRL, 0x02);
uint8_t raw = readRegister(LTR390_MAIN_CTRL);
raw &= ~0x08;
writeRegister(LTR390_MAIN_CTRL, raw);
}
void setUVSMode()
{
writeRegister(LTR390_MAIN_CTRL, 0x0A);
uint8_t raw = readRegister(LTR390_MAIN_CTRL);
raw |= 0x08;
writeRegister(LTR390_MAIN_CTRL, raw);
}
uint8_t reset()
@ -116,7 +120,9 @@ public:
//
uint32_t getALSData()
{
return readRegister(8) * 65536UL + readRegister(7);
uint32_t raw = readRegister(LTR390_ALS_DATA_1) * 65536UL;
raw += readRegister(LTR390_ALS_DATA_0);
return raw;
}
// page 22 datasheet
@ -129,7 +135,9 @@ public:
uint32_t getUVSData()
{
return readRegister(10) * 65536UL + readRegister(9);
uint32_t raw = readRegister(LTR390_UVS_DATA_1) * 65536UL;
raw += readRegister(LTR390_UVS_DATA_0);
return raw;
}
// page 22 datasheet
@ -145,20 +153,17 @@ public:
//
// MEASUREMENT CONFIGURATION
//
// experimental...
//
// TODO does not work as expected yet
//
void setGain(uint8_t gain) // 0..4
uint8_t setGain(uint8_t gain = 1) // 0..4
{
uint16_t value = gain;
if (value > 4) value = 4;
writeRegister(LTR390_GAIN, value);
_gain = 1;
if (value == 1) _gain = 3;
if (value == 2) _gain = 6;
if (value == 3) _gain = 9;
if (value == 4) _gain = 18;
if (value == 1) _gain = 3;
else if (value == 2) _gain = 6;
else if (value == 3) _gain = 9;
else if (value == 4) _gain = 18;
return value;
}
uint8_t getGain()
@ -169,17 +174,22 @@ public:
// resolution = 0..5 See datasheet P14.
// time = 0..7 See datasheet P14.
void setMeasurement(uint8_t resolution, uint8_t time)
bool setMeasurement(uint8_t resolution, uint8_t time)
{
if (resolution > 5) return false;
if (time > 7 ) return false;
uint16_t value = (resolution << 4) | time;
writeRegister(LTR390_ALS_UVS_MEAS_RATE, value);
_time = 2.000;
_time = 2.000; // time = 6 0r 7
if (time == 0) _time = 0.025;
if (time == 1) _time = 0.050;
if (time == 2) _time = 0.100;
if (time == 3) _time = 0.200;
if (time == 4) _time = 0.500;
if (time == 5) _time = 1.000;
return true;
}
uint8_t getResolution()
@ -194,28 +204,59 @@ public:
return reg & 0x07;
}
bool setUVsensitivity(float s)
{
if ((s <= 0.0) || (s > 1.0))return false;
_UVsensitivity = s;
return true;
}
float getUVsensitivity()
{
return _UVsensitivity;
}
//
// Code below this line is not tested yet.
// Use carefully, feel free to experiment.
// Please let me know if it works or not.
//
/*
void enable()
{
uint8_t raw = readRegister(LTR390_MAIN_CTRL);
raw != 0x02;
writeRegister(LTR390_MAIN_CTRL, raw);
}
void disable()
{
uint8_t raw = readRegister(LTR390_MAIN_CTRL);
raw &= ~0x02;
writeRegister(LTR390_MAIN_CTRL, raw);
}
*/
/*
//////////////////////////////////////////////
//
// MAIN STATUS
// TODO elaborate - need split? or masks?
//
uint8_t getStatus()
{
uint8_t reg = readRegister(LTR390_MAIN_STATUS);
uint8_t reg = readRegister(LTR390_MAIN_STATUS); ? no such register.
return reg & 0x38;
}
*/
/*
//////////////////////////////////////////////
//
// INTERRUPT
//
int setInterruptConfig(uint8_t value)
int setInterruptConfig(uint8_t value = 0x10)
{
return writeRegister(LTR390_INT_CFG, value);
}
@ -225,7 +266,7 @@ public:
return readRegister(LTR390_INT_CFG);
}
int setInterruptPersist(uint8_t value)
int setInterruptPersist(uint8_t value = 0x00)
{
return writeRegister(LTR390_INT_PST, value);
}
@ -234,57 +275,47 @@ public:
{
return readRegister(LTR390_INT_PST);
}
*/
/*
//////////////////////////////////////////////
//
// THRESHOLD
//
void setHighThreshold(uint32_t value)
// note registers are 16 bit.
//
void setHighThreshold(uint32_t value = 0x000FFFFF)
{
writeRegister(LTR390_ALS_UVS_THRES_UP_0, value & 0xFF);
value >>= 8;
writeRegister(LTR390_ALS_UVS_THRES_UP_1, value & 0xFF);
value >>= 8;
writeRegister(LTR390_ALS_UVS_THRES_UP_2, value & 0x0F);
writeRegister(LTR390_ALS_UVS_THRES_UP_0, value & 0xFFFF);
writeRegister(LTR390_ALS_UVS_THRES_UP_1, value >> 16);
}
uint32_t getHighThreshold()
{
uint32_t value = readRegister(LTR390_ALS_UVS_THRES_UP_2) & 0x0F;
value <<= 8;
value += readRegister(LTR390_ALS_UVS_THRES_UP_1);
value <<= 8;
uint32_t value = readRegister(LTR390_ALS_UVS_THRES_UP_1) << 16;
value += readRegister(LTR390_ALS_UVS_THRES_UP_0);
return value;
}
void setLowThreshold(uint32_t value)
void setLowThreshold(uint32_t value = 0)
{
writeRegister(LTR390_ALS_UVS_THRES_LOW_0, value & 0xFF);
value >>= 8;
writeRegister(LTR390_ALS_UVS_THRES_LOW_1, value & 0xFF);
value >>= 8;
writeRegister(LTR390_ALS_UVS_THRES_LOW_2, value & 0x0F);
writeRegister(LTR390_ALS_UVS_THRES_LOW_0, value & 0xFFFF);
writeRegister(LTR390_ALS_UVS_THRES_LOW_1, value >> 16);
}
uint32_t getLowThreshold()
{
uint32_t value = readRegister(LTR390_ALS_UVS_THRES_LOW_2) & 0x0F;
value <<= 8;
value += readRegister(LTR390_ALS_UVS_THRES_LOW_1);
value <<= 8;
uint32_t value = readRegister(LTR390_ALS_UVS_THRES_LOW_1) << 16;
value += readRegister(LTR390_ALS_UVS_THRES_LOW_0);
return value;
}
*/
// END OF PUBLIC PART
//////////////////////////////////////////////
//
// PRIVATE TODO move.
// PRIVATE
//
int writeRegister(uint8_t reg, uint16_t value)
{
@ -295,6 +326,7 @@ public:
int n = _wire->endTransmission();
if (n != 0)
{
// _error = LTR390_I2C_ERROR;
// Serial.print("write:\t");
// Serial.println(n);
}
@ -309,6 +341,7 @@ public:
int n = _wire->endTransmission();
if (n != 0)
{
// _error = LTR390_I2C_ERROR;
// Serial.print("read:\t");
// Serial.println(n);
return n;
@ -337,7 +370,5 @@ private:
};
// -- END OF FILE --

View File

@ -11,14 +11,14 @@
# LTR390_DFR
Arduino library for the I2C LTR390 UV sensor (DF Robotics edition).
Arduino library for the I2C LTR390 LUX / UV sensor (DF Robotics edition).
## Description
**Experimental**
This library is to read the LTR390 UV sensor on the DF Robotics
This library is to read the LTR390 LUX / UV sensor on the DF Robotics
break-out board.
Operating voltage range: **3.0V .. 5.0V** (tolerant).
@ -26,16 +26,16 @@ Operating voltage range: **3.0V .. 5.0V** (tolerant).
## I2C
The break-out has an address of 0x1C == 28 decimal.
The break-out has a fixed address of 0x1C == 28 decimal.
#### I2C Speed
### I2C Speed
The device should work on 100 kHz and 400 kHz I2C bus.
To be tested.
#### Multiplexing
### Multiplexing
Sometimes you need to control more devices than possible with the default
address range the device provides.
@ -54,7 +54,7 @@ too if they are behind the multiplexer.
#### Related
### Related
- https://github.com/RobTillaart/LTR390_RT (native LTR390)
- https://github.com/RobTillaart/LTR390_DFR (DF Robotics variant)
@ -66,43 +66,84 @@ too if they are behind the multiplexer.
#include "LTR390_DFR.h"
```
#### Constructor
### Constructor
- **LTR390_DFR(TwoWire \* wire = &Wire)** Constructor
with optional Wire interface.
- **bool begin()** returns true if device 0x1C can be seen on the I2C bus.
- **bool isConnected()** returns true if device 0x1C can be seen on I2C bus.
As the device has a fixed I2C address it cannot be set.
- **bool begin()** returns true if device address 0x1C can be seen on the I2C bus.
- **bool isConnected()** returns true if device address 0x1C can be seen on I2C bus.
- **uint8_t getAddress()** returns 0x1C, fixed address, for convenience.
#### Main control
### Main control
- **void setALSMode()**
- **void setUVSMode()**
- **void reset()** blocks for 100 ms.
- **void setALSMode()** set the Ambient Light Sensor mode.
- **void setUVSMode()** set the Ultra Violet Sensor mode.
- **void reset()** resets the sensor. This call blocks for 100 ms.
#### Measurement configuration
### Gain configuration
- **void setGain(uint8_t gain)** gain = 0..4,
- **uint8_t getGain()** returns set value.
- **void setMeasurement(uint8_t resolution, uint8_t time)**
- **uint8_t getResolution()**
- **uint8_t getTime()**
- **uint8_t setGain(uint8_t gain = 1)** gain = 0..4, values larger than 4 are
clipped to 4. Default value = 1.
Returns 0..4.
- **uint8_t getGain()** returns set value, 0..4.
#### Part and revision ID
| Gain | factor | Notes |
|:------:|:--------:|:-------:|
| 0 | 1 |
| 1 | 3 | default
| 2 | 6 |
| 3 | 9 |
| 4 | 18 |
### Resolution and time
- **bool setMeasurement(uint8_t resolution, uint8_t time)**
Resolution = 0..5, Time = 0..7. See table below.
Returns false if one of the parameters is out of range.
- **uint8_t getResolution()** returns 0..5, default 2.
- **uint8_t getTime()** returns 0..7, default 2.
| Reso | bits | | Time | millis | Notes |
|:------:|:------:|:-:|:------:|:--------:|:-------:|
| 0 | 20 | | 0 | 25 |
| 1 | 19 | | 1 | 50 |
| 2 | 18 | | 2 | 100 | default both.
| 3 | 17 | | 3 | 200 |
| 4 | 16 | | 4 | 500 |
| 5 | 13 | | 5 | 1000 |
| 6 | na | | 6 | 2000 |
| 7 | na | | 7 | 2000 |
14, 15 bits is not supported.
### UV sensitvity
- **bool setUVsensitivity(float s)** Sets the UV sesitivity
between 0..1. Returns false if the parameter s is out of range.
- **float getUVsensitivity()** returns set value. default 1.0.
### Part and revision ID
- **uint8_t getPartID()** returns 11.
- **uint8_t getRevisionID()** returns 2.
#### Get data
### Get data
- **uint32_t getALSData()**
- **float getLUX(float wfac = 1)** wfac = window factor,
- **uint32_t getUVSData()**
- **float getUVI(float wfac = 1)** wfac = window factor,
- **uint32_t getALSData()** returns 18 bit data
- **float getLUX(float wfac = 1.0)** wfac = window factor, typical 0..1.0.
Returns the ambient light in LUX.
- **uint32_t getUVSData()** returns 18 bit data
- **float getUVI(float wfac = 1.0)** wfac = window factor, typical 0..1.0.
Returns the UV index in ??? (TODO units).
## Future
@ -117,10 +158,12 @@ with optional Wire interface.
#### Should
- add examples
- fix / elaborate TODO's in code.
- status and error codes
- interrupts and thresholds
- add setUVsensitivity()
- add error codes
- split **getStatus()** or ??
- add **uint16_t getTimeMillis()** return time in millseconds.
- add **uint8_t getResolutionBits()** idem.
- add **uint8_t getGainFactor()** idem.
#### Could

View File

@ -13,6 +13,9 @@ setALSMode KEYWORD2
setUVSMode KEYWORD2
reset KEYWORD2
enable KEYWORD2
disable KEYWORD2
getPartID KEYWORD2
getRevisionID KEYWORD2
@ -28,6 +31,21 @@ setMeasurement KEYWORD2
getResolution KEYWORD2
getTime KEYWORD2
setUVsensitivity KEYWORD2
getUVsensitivity KEYWORD2
getStatus KEYWORD2
setInterruptConfig KEYWORD2
getInterruptConfig KEYWORD2
setInterruptPersist KEYWORD2
getInterruptPersist KEYWORD2
setHighThreshold KEYWORD2
getHighThreshold KEYWORD2
setLowThreshold KEYWORD2
getLowThreshold KEYWORD2
# Constants (LITERAL1)
LTR390_DFR_LIB_VERSION LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/LTR390_DFR.git"
},
"version": "0.1.0",
"version": "0.1.1",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=LTR390_DFR
version=0.1.0
version=0.1.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for the I2C LTR390 UV sensor (DF Robotics edition).

View File

@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.1] - 2024-09-24
- Fix #11, add schema to readme and examples
- update keywords.txt
- implement return type **int write(..)**
- fix channel test in **write()**
- update readme.md
## [0.2.0] - 2024-07-12
- fix deviceCount in **write()**.
- fix allocation buffer for channels in constructor.

View File

@ -11,7 +11,7 @@
# TLC5917
TLC5917 is an Arduino library for TLC5917 8-Channel Constant-Current LED Sink Drivers.
Arduino library for TLC5917 8-Channel Constant-Current LED Sink Drivers.
## Description
@ -24,10 +24,10 @@ This library also support more than one device in a daisy chain (see below).
The library allows to set the channels (outputs) on/off individually or as a group in one call.
Furthermore it allows to set a current gain for all devices connected.
The **TLC5916** is a derived class that is functional identical to the TLC5917.
The **TLC5916** is a derived class that is functional identical to the **TLC5917**.
When implementation proceeds this might change, the difference is in support for fetching
the status and error modi. This functionality is not supported by the library yet,
so there is no difference between the **TLC5916** and **TLC5917** for now.
the status and error modi. As this functionality is not supported by the library yet,
there is no difference between the **TLC5916** and **TLC5917** for now.
The library needs more testing with hardware.
Please share your experiences.
@ -35,11 +35,30 @@ Please share your experiences.
(Changes of the interface are definitely possible).
### Schema
Always check the datasheet!
```
TLC5917
+----u----+
GND | 1 16 | VDD
SDI | 2 15 | R-EXT
CLK | 3 14 | SDO
LE | 4 13 | OE
OUT0 | 5 12 | OUT7
OUT1 | 6 11 | OUT6
OUT2 | 7 10 | OUT5
OUT3 | 8 09 | OUT4
+---------+
```
### Breaking changes
The 0.2.0 version fixed an internal storage bug which allocated way to much memory
in version 0.1.x. So these versions can be considered obsolete.
The performance of the library **write()** call improved a lot.
in version 0.1.x. So the pre 0.2.0 versions can be considered obsolete.
The performance of the **write()** call improved a lot.
### Daisy chaining
@ -48,7 +67,7 @@ This library supports daisy chaining of multiple **TLC5917** modules.
A constructor takes the number of devices as parameter and
an internal buffer is allocated (8 channels per device).
This internal buffer is clocked into the devices with the **write()** call.
So **setChannel()** calls can be changed until last moment.
So **setChannel()** calls can change this buffer until last moment before **write()**
### Related
@ -70,7 +89,7 @@ So **setChannel()** calls can be changed until last moment.
### Constructor
- **TLC5917(uint8_t clock, uint8_t data, uint8_t latch, uint8_t outputEnable)** constructor.
Single device constructor.
Single device constructor, latch = LE pin, outputEnable = OE pin (see above).
Defines the pins used for uploading / writing the data to the device.
The outputEnable pin is explained in more detail below.
- **TLC5917(int deviceCount, uint8_t clock, uint8_t data, uint8_t latch, uint8_t outputEnable)** constructor.
@ -81,8 +100,8 @@ The outputEnable pin is explained in more detail below.
### Base
- **bool begin()** set the pinMode of the pins used and their initial values.
The TLC5917 is disabled by default, as the device has random values in its register.
- **bool begin()** sets the pinMode of the pins used and their initial values.
The TLC5917 module is disabled by default, as the device has random values in its registers.
Therefore one must call **enable()** explicitly.
- **int channelCount()** return the amount of channels == 8 x number of devices.
@ -92,16 +111,29 @@ Therefore one must call **enable()** explicitly.
- **bool setChannel(uint8_t channel, bool on)** set a channel on or off in the
internal buffer. The value is not written immediately to the device(s).
One has to call **write()** for that.
Returns false if **channel** is out of range.
- **bool setChannel(uint8_t \* array)** copy a preset of channel settings in one call.
The user has to take care that the size of array holds the right amount of bytes.
Typical amount is deviceCount (or more).
Will always return true for now.
- **bool setAll(bool on)** set all channels on or off.
- **bool getChannel(uint8_t channel)** get current state of a channel from the cached buffer.
- **void write()** writes the whole buffer (deviceCount x 8 values) to the device(s).
- **void write(int channels)** writes a part of the internal buffer (only **channels** values) to the device.
Will always return true for now.
- **bool getChannel(uint8_t channel)** returns current state of a channel from the
cached buffer. This might differ from the actual device state if channels have been
changed without a **write()**.
Returns false if **channel** is out of range.
### Write
- **int write()** writes the whole internal buffer (deviceCount x 8 values) to the device(s).
Returns the number of channels written (0 .. channelCount).
- **int write(int channels)** writes a part of the internal buffer (only **channels** values)
to the device.
Typical used to speed up if less than max number e.g. only 17 channels are used
and needs to be updated.
and needs to be updated.
**experimental, might have side effects**
Returns the number of channels written (0 .. channelCount).
**write()** must be called after setting all values one wants to change.
@ -110,7 +142,7 @@ channels as fast as possible.
See also **TLC5917_performance.ino** for an indication of time needed.
### OutputEnable line
### OutputEnable
The **outputEnable** pin (OE or blank) is used to set all channels on or off.
This allows to "preload" the registers with values and enable them all at once
@ -121,19 +153,20 @@ Default a TLC device is disabled, by **begin()**, so one should enable it "manua
- **void enable()** all channels reflect last values written.
- **void disable()** all channels are off / 0.
- **bool isEnabled()** returns status of outputEnable line.
- **bool isEnabled()** returns status of outputEnable **OE** line.
The library only supports one **enable() line**.
If you want a separate **enable()** per device you might need to connect the devices
"in parallel" instead of "in series" (daisy chained).
The outputEnable parameter in the constructor should be set to -1 (out of range value).
#### PWM
It might be possible to use a PWM pin on the **outputEnable** line to dim the LEDS.
It might be possible to use a PWM signal on the **outputEnable** pin to dim the LEDS.
This is neither tested nor supported by the library.
Note that writing to the TLC5917 needs a HIGH **outputEnable** so the PWM value needs
to be set again.
to be set again after each **write()**.
### Configure gain
@ -144,7 +177,7 @@ See datasheet page 23 for details.
- **void setSpecialMode()** switch to special mode to configure the gain.
Note that calling **setSpecialMode()** and **setNormalMode()** disables the output.
So one should enable it again if one wants to.
So one should **enable()** the output again if one wants to.
The special mode needs to be set for the following functions:
@ -161,8 +194,8 @@ Over the range 0.250 - 2.989 the max error is 0.0124
Over the range 2.989 - 3.000 the max error goes up to 0.023
So except for end of the range the error is (IMHO) small.
Returns false if out of range (n < 0.250 or n > 3.0).
- **float getVoltageGain()** see below (from cache).
- **float getCurrentGain()** see below (from cache).
- **float getVoltageGain()** see below (returns value from cache).
- **float getCurrentGain()** see below (returns value from cache).
| bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
@ -170,6 +203,7 @@ Returns false if out of range (n < 0.250 or n > 3.0).
| abbrev | CM | HC | CC0 | CC1 | CC2 | CC3 | CC4 | CC5 |
| default | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
CM == Current Multiplier
- limits the output current range.
- Low (CM = 0): 3 mA to 40 mA.
@ -199,6 +233,7 @@ and issue #9 for the LGT8F328 data
Timing in microseconds, 800 channels = 100 devices.
| Version | Function | UNO 1.8.19 | LGT8F328 | other |
|:-------:|:-----------------|:----------:|:--------:|:--------:|
| 0.2.0 | SETCHANNEL TRUE | 2572 | 1152 |
@ -207,9 +242,14 @@ Timing in microseconds, 800 channels = 100 devices.
| 0.2.0 | SETALL FALSE | 232 | - |
| 0.2.0 | WRITE optimized | 1772 | - |
| 0.2.0 | WRITE normal | 9420 | - |
| 0.2.1 | WRITE optimized | 1832 | - |
| 0.2.1 | WRITE normal | 9484 | - |
_The "WRITE optimized" is AVR only._
The 0.2.1 is slightly slower (~3%), probably due to added return values.
So setting and writing 8 channels (e.g. a single 7 segment display) takes
28.40 + 17.72 = 46.12 < 50 microseconds.
So in theory an UNO could update it roughly 20K times per second.
@ -221,10 +261,11 @@ First investigations show that **write()** could be a hardware SPI transaction.
However the **setNormalMode()**, **setSpecialMode()** and especially the
**writeConfiguration()** function are no standard 8 bit SPI transactions.
This of course includes the **gain** functions that use these.
To solve this one still has to provide the CLOCK, LATCH and OUTPUT ENABLE pins.
Especially the CLOCK pin is part of the SPI pins, and it would depend on the
board and optional number of HW SPI ports of the board.
To prevent this complexity the library does not have a hardware SPI constructor.
To prevent this complexity the library does not have a hardware SPI constructor.
It looks like it is possible to create a simplified class (stripped version)
without the gain control that might work well with HW SPI for many application.
@ -245,6 +286,11 @@ The added value is however limited as the (optimized) SW is pretty fast already.
- what is clock in practice (e.g. an ESP32 240 MHz)
- now the CurrentGain is set to the same value for all devices.
- needs array, one value (uint8_t) per device, investigate.
- investigate device count and channels unsigned int?
- use channel count in constructor, might be more correct as device count
as one could use e.g. 21 channels explicitly. Would prevent overflows
better. Impact on code?
- need to write section about latch enable LE line?
#### Could
@ -252,6 +298,10 @@ The added value is however limited as the (optimized) SW is pretty fast already.
- reading error codes from SDO
- do brightness test with analogWrite(OE, value);
- it would be mandatory to have OE be a PWM pin.
- return values for enable/disable?
- track "dirty cache", e.g. changed channels are not written yet.
- e.g. **bool writePending()**
- user can track this quite easily.
#### Wont (unless needed)
@ -260,7 +310,7 @@ The added value is however limited as the (optimized) SW is pretty fast already.
- **void getChannel(uint8_t \* array)** fill an array with current data.
- error handling in special mode
- over-temperature, open-load, short to GND, short to VLED (TLC5917 only).
- implement hardware SPI, see above.
- implement hardware SPI simplified class, see section above.
## Support

View File

@ -1,7 +1,7 @@
//
// FILE: TLC5917.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2024-03-17
// PURPOSE: Arduino library for TLC5917 8-Channel Constant-Current LED Sink Drivers.
// URL: https://github.com/RobTillaart/TLC5917
@ -102,21 +102,22 @@ bool TLC5917::getChannel(uint8_t channel)
//
// MAX speed single device 30 MHz
// multi device 15 MHz CHECK TODO
void TLC5917::write()
int TLC5917::write()
{
write(_channelCount);
return write(_channelCount);
}
void TLC5917::write(int channels)
int TLC5917::write(int channels)
{
if (channels < 0) return;
if (channels <= 0) return 0;
int devices = (channels > _channelCount) ? _channelCount / 8 : channels / 8;
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
// register level optimized AVR
// check FastShiftOut for more optimizations if needed.
uint8_t port = digitalPinToPort(_data);
volatile uint8_t *_dataOutRegister = portOutputRegister(port);
uint8_t outmask1 = digitalPinToBitMask(_data);
@ -167,6 +168,7 @@ void TLC5917::write(int channels)
// pulse latch to hold the signals
digitalWrite(_le, HIGH);
digitalWrite(_le, LOW);
return channels;
}
@ -260,6 +262,7 @@ uint8_t TLC5917::getMode()
// 9.4.3 Writing Configuration Code in Special Mode
// no AVR optimized version as fucntion is not often used (assumption).
void TLC5917::writeConfiguration(uint8_t configuration)
{
uint8_t _clk = _clock;

View File

@ -2,13 +2,13 @@
//
// FILE: TLC5917.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2024-03-17
// PURPOSE: Arduino library for TLC5917 8-Channel Constant-Current LED Sink Drivers.
// URL: https://github.com/RobTillaart/TLC5917
#define TLC5917_LIB_VERSION (F("0.2.0"))
#define TLC5917_LIB_VERSION (F("0.2.1"))
#include "Arduino.h"
@ -42,7 +42,7 @@ public:
// LE = Latch Enable
// OE = Output Enable
TLC5917(uint8_t clock, uint8_t data, uint8_t LE, uint8_t OE);
// multi device constructor
// multi device constructor
// - for daisy chaining
TLC5917(int deviceCount, uint8_t clock, uint8_t data, uint8_t LE, uint8_t OE);
virtual ~TLC5917();
@ -58,13 +58,13 @@ public:
bool getChannel(uint8_t channel);
// write the internal buffer to the TLC5917 device(s).
void write(int channels);
void write();
int write(int channels);
int write();
// control the outputEnable (OE) line.
void enable();
void disable();
bool isEnabled(); // returns status
bool isEnabled(); // returns status OE line
// GAIN configuration mode
// TODO test if this works for single device.

View File

@ -5,6 +5,19 @@
// URL: https://github.com/RobTillaart/TLC5917
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -5,6 +5,19 @@
// URL: https://github.com/RobTillaart/TLC5917
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -6,6 +6,20 @@
//
// needs investigation.
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -5,6 +5,19 @@
// URL: https://github.com/RobTillaart/TLC5917
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -6,6 +6,19 @@
// URL: https://github.com/RobTillaart/TLC5917
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -5,6 +5,19 @@
// URL: https://github.com/RobTillaart/TLC5917
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -16,7 +16,7 @@ Done...
(default write() on UNO for reference)
TLC5917_LIB_VERSION: 0.1.3
TLC5917_LIB_VERSION: 0.2.0
Channels: 800
SETCHANNEL TRUE: 2572

View File

@ -0,0 +1,31 @@
Arduino UNO
IDE: 1.8.19
(AVR optimized write() on UNO)
TLC5917_performance\TLC5917_performance.ino
TLC5917_LIB_VERSION: 0.2.1
Channels: 800
SETCHANNEL TRUE: 2572
SETCHANNEL FALSE: 2848
SETALL TRUE: 236
SETALL FALSE: 236
WRITE: 1832
Done...
(default write() on UNO for reference)
TLC5917_LIB_VERSION: 0.2.1
Channels: 800
SETCHANNEL TRUE: 2572
SETCHANNEL FALSE: 2844
SETALL TRUE: 228
SETALL FALSE: 232
WRITE: 9484
Done...

View File

@ -5,6 +5,19 @@
// URL: https://github.com/RobTillaart/TLC5917
// TLC5917
// +----u----+
// GND | 1 16 | VDD
// SDI | 2 15 | R-EXT
// CLK | 3 14 | SDO
// LE | 4 13 | OE
// OUT0 | 5 12 | OUT7
// OUT1 | 6 11 | OUT6
// OUT2 | 7 10 | OUT5
// OUT3 | 8 09 | OUT4
// +---------+
#include "TLC5917.h"

View File

@ -22,8 +22,11 @@ isEnabled KEYWORD2
setSpecialMode KEYWORD2
setNormalMode KEYWORD2
getMode KEYWORD2
writeConfiguration KEYWORD2
getConfiguration KEYWORD2
setGain KEYWORD2
setCurrentGain KEYWORD2
getVoltageGain KEYWORD2

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/TLC5917.git"
},
"version": "0.2.0",
"version": "0.2.1",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=TLC5917
version=0.2.0
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for TLC5917 8-Channel Constant-Current LED Sink Drivers.