* Add files via upload Added ENS16x library enabling read-out of ENS160 and ENS161 sensor component (follow-up of CCS811 and iAQcore) Added ENS210 library to read out ENS210 temperature & humidity sensor * Add files via upload Add air quality sensor readout for ENS160 and ENS161 checking two possible I2C addresses (follow up sensor for CCS811 and iAQcore) Add temperature and humidity sensor readout checking two possible I2C addresses * Update BUILDS.md Add USE_ENS16x and USE_ENS210 * Update decode-status.py Add USE_ENS16x and ENS210 * Update I2CDEVICES.md Add USE_ENS16x and USE_ENS210 * Update my_user_config.h Add USE_ENS16x and USE_ENS210 * Update support_features.ino Add USE_ENS16x and USE_ENS210 * Update tasmota_configurations.h Add USE_ENS16x and ENS210 * Update tasmota_configurations_ESP32.h Add USE_ENS16x and USE_ENS210 * Update xsns_111_ens16x.ino Corrected I2X number * Update xsns_112_ens210.ino Corrected I2C number * Disable USE_ENS16x and USE_ENS210 by default * Added code size information * cut down in libs * optimize tasmota side * fix ens16x web display * final fix on alternate addresses * update code & RAM usage --------- Co-authored-by: Barbudor <barbudor@barbudor.net>
649 lines
19 KiB
C++
649 lines
19 KiB
C++
/*
|
|
ScioSense_ENS210.h - Library for the ENS210 relative humidity and temperature sensor with I2C interface from ScioSense
|
|
2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams
|
|
2018 Aug 28 v2 Christoph Friese Adjusted I2C communication
|
|
2017 Aug 01 v1 Maarten Pennings Created
|
|
*/
|
|
|
|
#include "ScioSense_ENS210.h"
|
|
#include <assert.h>
|
|
|
|
// Compute the CRC-7 of 'val' (should only have 17 bits)
|
|
// https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Computation
|
|
static uint32_t crc7( uint32_t val )
|
|
{
|
|
// Setup polynomial
|
|
uint32_t pol= CRC7POLY;
|
|
// Align polynomial with data
|
|
pol = pol << (DATA7WIDTH-CRC7WIDTH-1);
|
|
// Loop variable (indicates which bit to test, start with highest)
|
|
uint32_t bit = DATA7MSB;
|
|
// Make room for CRC value
|
|
val = val << CRC7WIDTH;
|
|
bit = bit << CRC7WIDTH;
|
|
pol = pol << CRC7WIDTH;
|
|
// Insert initial vector
|
|
val |= CRC7IVEC;
|
|
// Apply division until all bits done
|
|
while( bit & (DATA7MASK<<CRC7WIDTH) ) {
|
|
if( bit & val ) val ^= pol;
|
|
bit >>= 1;
|
|
pol >>= 1;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
ScioSense_ENS210::ScioSense_ENS210(uint8_t slaveaddr) {
|
|
this->_slaveaddress = slaveaddr;
|
|
}
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
void ScioSense_ENS210::setI2C(uint8_t sda, uint8_t scl) {
|
|
this->_sdaPin = sda;
|
|
this->_sclPin = scl;
|
|
}
|
|
#endif
|
|
|
|
// Init I2C communication, resets ENS210 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID.
|
|
// Stores solder correction.
|
|
bool ScioSense_ENS210::begin(bool debug) {
|
|
bool result;
|
|
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
debugENS210 = debug;
|
|
#endif
|
|
|
|
//init I2C
|
|
_i2c_init();
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.println("ens210 debug - I2C init done");
|
|
}
|
|
#endif
|
|
|
|
// Record solder correction
|
|
this->_soldercorrection= 0;
|
|
this->_available = false;
|
|
this->_singleMode = true;
|
|
this->_t_data = -1;
|
|
this->_h_data = -1;
|
|
this->_partID = 0;
|
|
|
|
this->lowpower(false);
|
|
|
|
result = this->getversion();
|
|
|
|
if(this->_partID == ENS210_PARTID ) {
|
|
this->_available = true;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
void ScioSense_ENS210::changeAddr(uint8_t oldAddr, uint8_t newAddr) {
|
|
uint8_t i2cbuf[2];
|
|
|
|
_i2c_init();
|
|
|
|
//Disable low power mode --> always on
|
|
uint8_t result = this->write8(oldAddr, 0x10, 0x00);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Low Power off result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// read status register
|
|
result = this->read(oldAddr, 0x11, i2cbuf, 1);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Read status result: 0x");
|
|
Serial.println(result,HEX);
|
|
for (uint8_t i=0; i<1; i++) {
|
|
Serial.print("\t0x");
|
|
Serial.print(i2cbuf[i],HEX);
|
|
}
|
|
Serial.println();
|
|
#endif
|
|
delay(100);
|
|
|
|
// enable low level access. PASSWORD_WRITE_ENABLE
|
|
result = this->write8(oldAddr, 0x10, 0x30);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("PASSWORD_WRITE_ENABLE result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// read status register
|
|
result = this->read(oldAddr, 0x11, i2cbuf, 1);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Read status result: 0x");
|
|
Serial.println(result,HEX);
|
|
for (uint8_t i=0; i<1; i++) {
|
|
Serial.print("\t0x");
|
|
Serial.print(i2cbuf[i],HEX);
|
|
}
|
|
Serial.println();
|
|
#endif
|
|
delay(100);
|
|
|
|
// low level access password. Password is 00 00 00 00
|
|
uint8_t passwdCmd[4] = {0x00, 0x00, 0x00, 0x00};
|
|
result = this->write(oldAddr, 0x48, passwdCmd, 5);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Write password result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// read low-level mode sensor output data
|
|
result = this->read(oldAddr, 0x46, i2cbuf, 2);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Read low level result: 0x");
|
|
Serial.println(result,HEX);
|
|
for (uint8_t i=0; i<2; i++) {
|
|
Serial.print("\t0x");
|
|
Serial.print(i2cbuf[i],HEX);
|
|
}
|
|
Serial.println();
|
|
#endif
|
|
delay(100);
|
|
|
|
// write values to parameter field and data1&2 field
|
|
uint8_t newAddrCmd[5] = {0x00,0x00,0x22,0x00,0x41};
|
|
newAddrCmd[4] = newAddr;
|
|
result = this->write(oldAddr, 0x41, newAddrCmd, 5);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Write parameters result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// write SEN_CMD to execute low-level command specified, 0xCE means “APB_WRITE”
|
|
result = this->write8(oldAddr, 0x40, 0xCE);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Execute result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// Read low-level mode sensor output data to check if programming succeeded. Expected response: 0x00 0xAC
|
|
result = this->read(oldAddr, 0x46, i2cbuf, 2);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Read back result: 0x");
|
|
Serial.println(result,HEX);
|
|
for (uint8_t i=0; i<2; i++) {
|
|
Serial.print("\t0x");
|
|
Serial.print(i2cbuf[i],HEX);
|
|
}
|
|
Serial.println();
|
|
#endif
|
|
delay(100);
|
|
|
|
// reset ENS210
|
|
result = this->write8(oldAddr, 0x10, 0xFF);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Reset result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// reset ENS210
|
|
result = this->write8(oldAddr, 0x10, 0xFF);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Reset result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
|
|
// reset ENS210
|
|
result = this->write8(newAddr, 0x10, 0xFF);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
Serial.print("Reset result: 0x");
|
|
Serial.println(result,HEX);
|
|
#endif
|
|
delay(100);
|
|
}
|
|
#endif //#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
|
|
// Sends a reset to the ENS210. Returns false on I2C problems.
|
|
bool ScioSense_ENS210::reset(void) {
|
|
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SYS_CTRL, 0x80);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - reset: 0x");
|
|
Serial.println(result,HEX);
|
|
}
|
|
#endif
|
|
delay(ENS210_BOOTING); // Wait to boot after reset
|
|
return result==0;
|
|
}
|
|
|
|
|
|
// Sets ENS210 to low (true) or high (false) power. Returns false on I2C problems.
|
|
bool ScioSense_ENS210::lowpower(bool enable) {
|
|
uint8_t power = enable ? 0x01: 0x00;
|
|
uint8_t result = this->write8(this->_slaveaddress, ENS210_REG_SYS_CTRL, power);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - lowpower: 0x");
|
|
Serial.println(result,HEX);
|
|
}
|
|
#endif
|
|
delay(ENS210_BOOTING); // Wait boot-time after power switch
|
|
return result==0;
|
|
}
|
|
|
|
|
|
// Reads PART_ID and UID of ENS210. Returns false on I2C problems.
|
|
bool ScioSense_ENS210::getversion() {
|
|
bool ok;
|
|
uint8_t i2cbuf[8];
|
|
uint8_t result;
|
|
|
|
// Must disable low power to read PART_ID or UID
|
|
ok= lowpower(false); if(!ok) goto errorexit;
|
|
|
|
// Read the PART_ID
|
|
result = this->read(this->_slaveaddress, ENS210_REG_PART_ID, i2cbuf, 2);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - PART_ID I2C result: 0x");
|
|
Serial.println(result, HEX);
|
|
}
|
|
#endif
|
|
//this->_partID = (uint16_t)(i2cbuf[1]*256U + i2cbuf[0]*1U);
|
|
this->_partID = (uint16_t)(((uint16_t)i2cbuf[1] << 8) | ((uint16_t)i2cbuf[0]));
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("PART_ID: 0x");
|
|
Serial.println(this->_partID,HEX);
|
|
}
|
|
#endif
|
|
|
|
// Read the REV
|
|
result = this->read(this->_slaveaddress, ENS210_REG_REV, i2cbuf, 2);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - REV I2C result: 0x");
|
|
Serial.println(result, HEX);
|
|
}
|
|
#endif
|
|
this->_rev = (uint16_t)(((uint16_t)i2cbuf[1] << 8) | ((uint16_t)i2cbuf[0]));
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("REV: 0x");
|
|
Serial.println(this->_rev,HEX);
|
|
}
|
|
#endif
|
|
|
|
// Read the UID
|
|
result = this->read(_slaveaddress, ENS210_REG_UID,i2cbuf,8);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - UID 0x");
|
|
Serial.println(result,HEX);
|
|
}
|
|
#endif
|
|
this->_uID = (uint64_t)((uint64_t)i2cbuf[7]<<56 | (uint64_t)i2cbuf[6]<<48 | (uint64_t)i2cbuf[5]<<40 | (uint64_t)i2cbuf[4]<<32 | (uint64_t)i2cbuf[3]<<24 | (uint64_t)i2cbuf[2]<<16 | (uint64_t)i2cbuf[1]<<8 | (uint64_t)i2cbuf[0]);
|
|
|
|
//for( int i=0; i<8; i++) ((uint8_t*)this->_uID)[i]=i2cbuf[i]; //((uint8_t*)this->_uID)[i]=i2cbuf[i];
|
|
this->_uIDhi = (uint32_t)(this->_uID >> 32);
|
|
this->_uIDlo = (uint32_t)(this->_uID & 0xFFFFFFFF);
|
|
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("UID hi 0x");
|
|
Serial.print(this->_uIDhi,HEX);
|
|
Serial.print(" - 0x");
|
|
Serial.println(this->_uIDlo,HEX);
|
|
}
|
|
#endif
|
|
|
|
// Go back to default power mode (low power enabled)
|
|
ok= lowpower(true); if(!ok) goto errorexit;
|
|
|
|
// Success
|
|
return true;
|
|
|
|
errorexit:
|
|
// Try to go back to default mode (low power enabled)
|
|
ok= lowpower(true);
|
|
|
|
// Hopefully enabling low power was successful; but there was an error before that anyhow
|
|
return false;
|
|
}
|
|
|
|
// Configures ENS210 measurement mode
|
|
// false for continuous mode / true for single shot measurement. Returns false on I2C problems.
|
|
bool ScioSense_ENS210::setSingleMode(bool enable)
|
|
{
|
|
this->_singleMode = enable;
|
|
uint8_t mode = enable ? 0x00: 0x03;
|
|
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_RUN, mode);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - start mode 0x");
|
|
Serial.print(mode,HEX);
|
|
Serial.print(" - result 0x");
|
|
Serial.println(result,HEX);
|
|
}
|
|
#endif
|
|
return result==0;
|
|
}
|
|
|
|
// Performs one single shot temperature and relative humidity measurement.
|
|
void ScioSense_ENS210::measure() //int * t_data, int * t_status, int * h_data, int * h_status )
|
|
{
|
|
bool ok;
|
|
// Set default status for early bail out
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) Serial.println("Start measurement");
|
|
#endif
|
|
this->_t_status = ENS210_STATUS_I2CERROR;
|
|
this->_h_status = ENS210_STATUS_I2CERROR;
|
|
|
|
// Start a single shot measurement
|
|
if (this->_singleMode)
|
|
{
|
|
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_RUN, 0x00);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - start single 0x");
|
|
Serial.println(result,HEX);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//Trigger measurement
|
|
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_START, 0x03);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - trigger measurement 0x");
|
|
Serial.println(result,HEX);
|
|
}
|
|
#endif
|
|
|
|
// Wait for measurement to complete
|
|
if (this->_singleMode) delay(ENS210_THCONV_SINGLE_MS);
|
|
else delay(ENS210_THCONV_CONT_MS);
|
|
|
|
// Get the measurement data
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) Serial.println("Start measurement");
|
|
#endif
|
|
ok = readValue(); if(!ok) return;
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) Serial.println("Measurement ok");
|
|
#endif
|
|
}
|
|
|
|
// Reads measurement data from the ENS210. Returns false on I2C problems.
|
|
bool ScioSense_ENS210::readValue() //uint32_t *t_val, uint32_t *h_val)
|
|
{
|
|
uint8_t i2cbuf[6];
|
|
uint8_t valid;
|
|
uint32_t crc;
|
|
uint32_t payload;
|
|
uint8_t crc_ok;
|
|
|
|
// Read T_VAL and H_VAL
|
|
uint8_t result = this->read(_slaveaddress, ENS210_REG_T_VAL, i2cbuf, 6);
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("ens210 debug - readValue:");
|
|
Serial.println(result);
|
|
Serial.print(i2cbuf[0],HEX); Serial.print("\t");
|
|
Serial.print(i2cbuf[1],HEX); Serial.print("\t");
|
|
Serial.print(i2cbuf[2],HEX); Serial.print("\t");
|
|
Serial.print(i2cbuf[3],HEX); Serial.print("\t");
|
|
Serial.print(i2cbuf[4],HEX); Serial.print("\t");
|
|
Serial.print(i2cbuf[5],HEX); Serial.println("\t");
|
|
}
|
|
#endif
|
|
// Retrieve and pack bytes into t_val and h_val
|
|
uint32_t t_val= (uint32_t)((uint32_t)i2cbuf[2]<<16 | (uint32_t)i2cbuf[1]<<8 | (uint32_t)i2cbuf[0]);
|
|
this->_t_data = (t_val>>0) & 0xffff;
|
|
valid = (t_val>>16) & 0x1;
|
|
crc = (t_val>>17) & 0x7f;
|
|
payload = (t_val>>0 ) & 0x1ffff;
|
|
crc_ok = crc7(payload)==crc;
|
|
if( !crc_ok ) this->_t_status = ENS210_STATUS_CRCERROR;
|
|
else if( !valid ) this->_t_status = ENS210_STATUS_INVALID;
|
|
else this->_t_status = ENS210_STATUS_OK;
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("_t_data 0x");
|
|
Serial.print(t_val,HEX);
|
|
Serial.print(" - 0x");
|
|
Serial.println(this->_t_data,HEX);
|
|
Serial.print("Valid: ");
|
|
Serial.print(valid);
|
|
Serial.print(" Status: ");
|
|
Serial.println(this->_t_status);
|
|
}
|
|
#endif
|
|
|
|
uint32_t h_val= (uint32_t)((uint32_t)i2cbuf[5]<<16 | (uint32_t)i2cbuf[4]<<8 | (uint32_t)i2cbuf[3]);
|
|
this->_h_data = (h_val>>0) & 0xffff;
|
|
|
|
valid = (h_val>>16) & 0x1;
|
|
crc = (h_val>>17) & 0x7f;
|
|
payload = (h_val>>0 ) & 0x1ffff;
|
|
crc_ok= crc7(payload)==crc;
|
|
if( !crc_ok ) this->_h_status= ENS210_STATUS_CRCERROR;
|
|
else if( !valid ) this->_h_status= ENS210_STATUS_INVALID;
|
|
else this->_h_status= ENS210_STATUS_OK;
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("_h_data 0x");
|
|
Serial.print(h_val,HEX);
|
|
Serial.print(" - 0x");
|
|
Serial.println(this->_h_data,HEX);
|
|
Serial.print("Valid: ");
|
|
Serial.print(valid);
|
|
Serial.print(" Status: ");
|
|
Serial.println(this->_h_status);
|
|
}
|
|
#endif
|
|
|
|
// Success
|
|
return true;
|
|
}
|
|
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
// Converts a status (ENS210_STATUS_XXX) to a human readable string.
|
|
const char * ScioSense_ENS210::status_str( int status )
|
|
{
|
|
switch( status ) {
|
|
case ENS210_STATUS_I2CERROR : return "i2c-error";
|
|
case ENS210_STATUS_CRCERROR : return "crc-error";
|
|
case ENS210_STATUS_INVALID : return "data-invalid";
|
|
case ENS210_STATUS_OK : return "ok";
|
|
default : return "unknown-status";
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
// Convert raw `t_data` temperature to Kelvin (also applies the solder correction).
|
|
// The output value is in Kelvin multiplied by parameter `multiplier`.
|
|
float ScioSense_ENS210::getTempKelvin()
|
|
{
|
|
// Force 32 bits
|
|
float t = this->_t_data & 0xFFFF;
|
|
// Compensate for soldering effect
|
|
t-= _soldercorrection;
|
|
// Return m*K. This equals m*(t/64) = (m*t)/64
|
|
// Note m is the multiplier, K is temperature in Kelvin, t is raw t_data value.
|
|
// Uses K=t/64.
|
|
return t/64; //IDIV(t,64);
|
|
}
|
|
#endif
|
|
|
|
// Convert raw `t_data` temperature to Celsius (also applies the solder correction).
|
|
// The output value is in Celsius multiplied by parameter `multiplier`.
|
|
float ScioSense_ENS210::getTempCelsius()
|
|
{
|
|
//assert( (1<=multiplier) && (multiplier<=1024) );
|
|
// Force 32 bits
|
|
float t= this->_t_data & 0xFFFF;
|
|
// Compensate for soldering effect
|
|
t-= _soldercorrection;
|
|
// Return m*C. This equals m*(K-273.15) = m*K - 27315*m/100 = m*t/64 - 27315*m/100
|
|
// Note m is the multiplier, C is temperature in Celsius, K is temperature in Kelvin, t is raw t_data value.
|
|
// Uses C=K-273.15 and K=t/64.
|
|
return t/64 - 27315L/100; //IDIV(t,64) - IDIV(27315L,100);
|
|
}
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
// Convert raw `t_data` temperature to Fahrenheit (also applies the solder correction).
|
|
float ScioSense_ENS210::getTempFahrenheit()
|
|
{
|
|
float t= this->_t_data & 0xFFFF;
|
|
// Compensate for soldering effect
|
|
t-= _soldercorrection;
|
|
// Return m*F. This equals m*(1.8*(K-273.15)+32) = m*(1.8*K-273.15*1.8+32) = 1.8*m*K-459.67*m = 9*m*K/5 - 45967*m/100 = 9*m*t/320 - 45967*m/100
|
|
// Note m is the multiplier, F is temperature in Fahrenheit, K is temperature in Kelvin, t is raw t_data value.
|
|
// Uses F=1.8*(K-273.15)+32 and K=t/64.
|
|
return 9*t/320 - 45967/100; //IDIV(9*t,320) - IDIV(45967L,100);
|
|
// The first multiplication stays below 32 bits (t:16, multiplier:11, 9:4)
|
|
// The second multiplication stays below 32 bits (multiplier:10, 45967:16)
|
|
}
|
|
#endif
|
|
|
|
// Convert raw `h_data` relative humidity to %RH.
|
|
float ScioSense_ENS210::getHumidityPercent()
|
|
{
|
|
float h= this->_h_data & 0xFFFF;
|
|
// Return m*H. This equals m*(h/512) = (m*h)/512
|
|
// Note m is the multiplier, H is the relative humidity in %RH, h is raw h_data value.
|
|
// Uses H=h/512.
|
|
return h/512; //IDIV(h, 512);
|
|
}
|
|
|
|
|
|
// Convert raw `h_data` absolute humidity to %RH.
|
|
#define MOLAR_MASS_OF_WATER 18.01534
|
|
#define UNIVERSAL_GAS_CONSTANT 8.21447215
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
float ScioSense_ENS210::getAbsoluteHumidityPercent()
|
|
{
|
|
//taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
|
|
//precision is about 0.1°C in range -30 to 35°C
|
|
//August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04)
|
|
//Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97)
|
|
//reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html // Use Buck (1981)
|
|
|
|
return (6.1121 * pow(2.718281828,(17.67* this->getTempCelsius())/(this->getTempCelsius() + 243.5))* this->getHumidityPercent() *MOLAR_MASS_OF_WATER)/((273.15+ this->getTempCelsius() )*UNIVERSAL_GAS_CONSTANT);
|
|
}
|
|
#endif
|
|
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
// Sets the solder correction (default is 50mK) - only used by the `toXxx` functions.
|
|
void ScioSense_ENS210::correction_set(int correction)
|
|
{
|
|
assert( -1*64<correction && correction<+1*64 ); // A correction of more than 1 Kelvin does not make sense (but the 1K is arbitrary)
|
|
this->_soldercorrection = correction;
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
/* General functions */
|
|
/****************************************************************************/
|
|
|
|
void ScioSense_ENS210::_i2c_init() {
|
|
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
|
|
if (this->_sdaPin != this->_sclPin)
|
|
Wire.begin(this->_sdaPin, this->_sclPin);
|
|
else
|
|
#endif
|
|
Wire.begin();
|
|
}
|
|
/**************************************************************************/
|
|
|
|
uint8_t ScioSense_ENS210::read8(uint8_t addr, byte reg)
|
|
{
|
|
uint8_t ret;
|
|
this->read(addr, reg, &ret, 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint8_t ScioSense_ENS210::read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num)
|
|
{
|
|
uint8_t pos = 0;
|
|
uint8_t result = 0;
|
|
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("I2C read address: 0x");
|
|
Serial.print(addr, HEX);
|
|
Serial.print(" - register: 0x");
|
|
Serial.println(reg, HEX);
|
|
}
|
|
#endif
|
|
|
|
//on arduino we need to read in 32 byte chunks
|
|
while(pos < num){
|
|
|
|
uint8_t read_now = 32; //min((uint8_t)32, (uint8_t)(num - pos));
|
|
Wire.beginTransmission((uint8_t)addr);
|
|
|
|
Wire.write((uint8_t)reg + pos);
|
|
result = Wire.endTransmission();
|
|
Wire.requestFrom((uint8_t)addr, read_now);
|
|
|
|
//for(int i=0; i<read_now; i++){
|
|
for(int i=0; i<num; i++){
|
|
buf[pos] = Wire.read();
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("Pos: ");
|
|
Serial.print(pos);
|
|
Serial.print(" - Value: 0x");
|
|
Serial.println(buf[pos], HEX);
|
|
}
|
|
#endif
|
|
pos++;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
|
|
uint8_t ScioSense_ENS210::write8(uint8_t addr, byte reg, byte value)
|
|
{
|
|
uint8_t result = this->write(addr, reg, &value, 1);
|
|
return result;
|
|
}
|
|
|
|
uint8_t ScioSense_ENS210::write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num)
|
|
{
|
|
#ifndef ENS210_DISABLE_DEBUG
|
|
if (debugENS210) {
|
|
Serial.print("I2C write address: 0x");
|
|
Serial.print(addr, HEX);
|
|
Serial.print(" - register: 0x");
|
|
Serial.print(reg, HEX);
|
|
Serial.print(" - value: 0x");
|
|
for (int i = 0; i<num; i++) {
|
|
Serial.print(" 0x");
|
|
Serial.print(buf[i], HEX);
|
|
}
|
|
Serial.println();
|
|
}
|
|
#endif
|
|
|
|
Wire.beginTransmission((uint8_t)addr);
|
|
Wire.write((uint8_t)reg);
|
|
Wire.write((uint8_t *)buf, num);
|
|
uint8_t result = Wire.endTransmission();
|
|
return result;
|
|
}
|
|
|