espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.67k stars 7.42k forks source link

Sodaq_SHT2x Issue #2307

Closed asetyde closed 5 years ago

asetyde commented 5 years ago

Sodaq_SHT2x Issue

Read sensor with esp32 devkit gives strange value near zero with last pre-release 1.0.1 rc4 I can't see why, but I think some is linked to i2c driver

@stickbreaker cab be linked to i2c recent issue ? with rc4 bug on i2c ? I add my library under

Hardware:

Board: ESP32 Devkit Module Core Installation version: 1.0.1-rc4 IDE name: Arduino IDE Flash Frequency: 160Mhz/80mhz PSRAM enabled: no Upload Speed: 115200 Computer OS: Windows 10

my library for sht21x :

Sodaq_SHT2x.h

#ifndef SHT2X_H
#define SHT2X_H

#include <stdint.h>

class SHT2xClass
{
  private:
    uint16_t readSensor(uint8_t command);

  public:
    float GetHumidity(void);
    float GetTemperature(void);
    float GetDewPoint(void);
};

extern SHT2xClass SHT2x;

#endif

Sodaq_SHT2x.cpp

#include <stdint.h>
#include <math.h>
#include <Arduino.h>
#include <Wire.h>
#include "Sodaq_SHT2x.h"

// Specify the constants for water vapor and barometric pressure.
#define WATER_VAPOR 17.62f
#define BAROMETRIC_PRESSURE 243.5f

typedef enum {
  eSHT2xAddress = 0x40,
} HUM_SENSOR_T;

typedef enum {
  eTempHoldCmd = 0xE3,
  eRHumidityHoldCmd = 0xE5,
  eTempNoHoldCmd = 0xF3,
  eRHumidityNoHoldCmd = 0xF5,
} HUM_MEASUREMENT_CMD_T;

/******************************************************************************

Global Functions
******************************************************************************/
/**********************************************************

GetHumidity
Gets the current humidity from the sensor.
@return float - The relative humidity in %RH
**********************************************************/
float SHT2xClass::GetHumidity(void)
{
  float value = readSensor(eRHumidityNoHoldCmd);
  if (value == 0) {
    return 0; // Some unrealistic value
  }
  return -6.0 + 125.0 / 65536.0 * value;
}
/**********************************************************

GetTemperature
Gets the current temperature from the sensor.
@return float - The temperature in Deg C
**********************************************************/
float SHT2xClass::GetTemperature(void)
{
  float value = readSensor(eTempNoHoldCmd);
  if (value == 0) {
    return -273; // Roughly Zero Kelvin indicates an error
  }
  return -46.85 + 175.72 / 65536.0 * value;
}
/**********************************************************

GetDewPoint
Gets the current dew point based on the current humidity and temperature
@return float - The dew point in Deg C
**********************************************************/
float SHT2xClass::GetDewPoint(void)
{
  float humidity = GetHumidity();
  float temperature = GetTemperature();
  // Calculate the intermediate value 'gamma'
  float gamma = log(humidity / 100) + WATER_VAPOR * temperature / (BAROMETRIC_PRESSURE + temperature);
  // Calculate dew point in Celsius
  float dewPoint = BAROMETRIC_PRESSURE * gamma / (WATER_VAPOR - gamma);

  return dewPoint;
}

/******************************************************************************

Private Functions
******************************************************************************/
uint16_t SHT2xClass::readSensor(uint8_t command)
{
  uint16_t result;

  Wire.beginTransmission(eSHT2xAddress);
  Wire.write(command);
  Wire.endTransmission();
  delay(100);

  Wire.requestFrom(eSHT2xAddress, 3);
  uint32_t timeout = millis() + 300;       // Don't hang here for more than 300ms
  while (Wire.available() < 3) {
     if ((millis() - timeout) > 0) {
         return 0;
     }
  }

  //Store the result
  result = Wire.read() << 8;
  result += Wire.read();
  result &= ~0x0003;   // clear two low bits (status bits)

  //Clear the final byte from the buffer
  Wire.read();

  return result;
}

SHT2xClass SHT2x;
me-no-dev commented 5 years ago

try this:

  uint32_t start = millis();
  while (Wire.available() < 3) {
     if ((millis() - start) >= 300) { // Don't hang here for more than 300ms
         return 0;
     }
  }
asetyde commented 5 years ago

not work ..

stickbreaker commented 5 years ago

@asetyde are you using "hold master" or "no hold master" commands Hold Master commands

no Hold MasterCommands


bool SHT2xClass::waitReady(uint32_t timeouMs){
  bool ready = false;
  uint32_t tick = millis();
  while((!ready)&&(millis-tick < timeoutMs)){
    Wire.beginTransmission(eSHT2xAddress);
    ready = Wire.endTransmssion()==0;
    if(!ready && timeoutMs>0){
      delay(timeoutMs/5); // wait for sensor to complete sample
    } 
  }
return ready;
}

uint16_t SHT2xClass::readSensor(uint8_t command)
{
  uint16_t result=0;
  if(waitReady(100)){ // wait up to 100ms for sensor to answer, could be in previous sample cycle
      Wire.beginTransmission(eSHT2xAddress);
      Wire.write(command);
      uint8_t err = Wire.endTransmission();
      if(err==0){ // command accepted
        switch(command &0x10){
          case 0x10 : // Hold Master command (SCL stretching)
            Wire.setTimeOut(100); // chip specified max is 85ms for 14bit res (V.4 May 2014 datasheet)
            break;
          case 0 : // wait for sensor to complete conversion, polling for ready
            Wire.setTimeout(50); // default i2c timeout
            waitReady(100);
            break;
          default :;
        }
        err=Wire.requestFrom(eSHT2xAddress,3);
        if(err == 0) {// no data
          log_w("read Sensor command(0x%02X) fail =%d(%s)",command,Wire.lastError(),Wire.getErrorText(Wire.lastError()))
          return 0;
        }
        if(err == 3){// got three bytes in buffer
          //Store the result
          result = Wire.read() << 8;
          result += Wire.read();
          result &= ~0x0003;   // clear two low bits (status bits)
          // don't care about last byte, next requestFrom() will overwrite
          return result;
    } else { // Command not accepted
          log_w("write Sensor command(0x%02X) fail =%d(%s)",command,Wire.lastError(),Wire.getErrorText(Wire.lastError()))
          return 0;
   }
} else { // sensor never answered
          log_e("Sensor at 0x%02X did not ACK, err = %d(%s)",eSHT2xAddress),Wire.lastError(),Wire.getErrorText(Wire.lastError()))
          return 0;
}
}

I haven't compiled this so there could be syntax errors. Try it.

Chuck.

asetyde commented 5 years ago

Ok tomorrow i test it (GMT+1)

I've many devices with i2c , SHT21x , VEML7700 , CAP1296 (Microchip touch) , i see sometimes a temporaly freeze on i2c, therefore also udp sometimes delay

asetyde commented 5 years ago

i correct it some imperfection but result now is t: -273.00000 and hum 0 :(

asetyde commented 5 years ago
// .h
#ifndef SHT2X_H
#define SHT2X_H

#include <stdint.h>

class SHT2xClass
{
  private:
    uint16_t readSensor(uint8_t command);
    bool waitReady(uint32_t timeouMs);

  public:
    float GetHumidity(void);
    float GetTemperature(void);
    float GetDewPoint(void);
};

extern SHT2xClass SHT2x;

#endif
asetyde commented 5 years ago
// .cpp

#include <stdint.h>
#include <math.h>
#include <Arduino.h>
#include "Sodaq_SHT2x.h"
#include <Wire.h>

// Specify the constants for water vapor and barometric pressure.
#define WATER_VAPOR 17.62f
#define BAROMETRIC_PRESSURE 243.5f

typedef enum {
    eSHT2xAddress = 0x40,
} HUM_SENSOR_T;

typedef enum {
    eTempHoldCmd        = 0xE3,
    eRHumidityHoldCmd   = 0xE5,
    eTempNoHoldCmd      = 0xF3,
    eRHumidityNoHoldCmd = 0xF5,
} HUM_MEASUREMENT_CMD_T;

/******************************************************************************
 * Global Functions
 ******************************************************************************/

/**********************************************************
 * GetHumidity
 *  Gets the current humidity from the sensor.
 *
 * @return float - The relative humidity in %RH
 **********************************************************/
float SHT2xClass::GetHumidity(void)
{
    float value = readSensor(eRHumidityNoHoldCmd);
    if (value == 0) {
        return 0;                       // Some unrealistic value
    }
    return -6.0 + 125.0 / 65536.0 * value;
}

/**********************************************************
 * GetTemperature
 *  Gets the current temperature from the sensor.
 *
 * @return float - The temperature in Deg C
 **********************************************************/
float SHT2xClass::GetTemperature(void)
{
    float value = readSensor(eTempNoHoldCmd);
    if (value == 0) {
        return -273;                    // Roughly Zero Kelvin indicates an error
    }
    return -46.85 + 175.72 / 65536.0 * value;
}

/**********************************************************
 * GetDewPoint
 *  Gets the current dew point based on the current humidity and temperature
 *
 * @return float - The dew point in Deg C
 **********************************************************/
float SHT2xClass::GetDewPoint(void)
{
  float humidity = GetHumidity();
  float temperature = GetTemperature();

  // Calculate the intermediate value 'gamma'
  float gamma = log(humidity / 100) + WATER_VAPOR * temperature / (BAROMETRIC_PRESSURE + temperature);
  // Calculate dew point in Celsius
  float dewPoint = BAROMETRIC_PRESSURE * gamma / (WATER_VAPOR - gamma);

  return dewPoint;
}

/******************************************************************************
 * Private Functions
 ******************************************************************************/

uint16_t SHT2xClass::readSensor(uint8_t command)
{
    uint16_t result = 0;
    if (waitReady(100)) { // wait up to 100ms for sensor to answer, could be in previous sample cycle
        Wire.beginTransmission(eSHT2xAddress);
        Wire.write(command);
        uint8_t err = Wire.endTransmission();
        if (err == 0) { // command accepted
            switch (command & 0x10) {
            case 0x10: // Hold Master command (SCL stretching)
                Wire.setTimeOut(100); // chip specified max is 85ms for 14bit res (V.4 May 2014 datasheet)
                break;
            case 0: // wait for sensor to complete conversion, polling for ready
                Wire.setTimeout(50); // default i2c timeout
                waitReady(100);
                break;
            default:;
            }
            err = Wire.requestFrom(eSHT2xAddress, 3);
            if (err == 0) {// no data
                char data[200]="";
                snprintf(data,200,"read Sensor command(0x%02X) fail =%d(%s)", command, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
                Serial.println(data);
                return 0;
            }
            if (err == 3) {// got three bytes in buffer
              //Store the result
                result = Wire.read() << 8;
                result += Wire.read();
                result &= ~0x0003;   // clear two low bits (status bits)
                // don't care about last byte, next requestFrom() will overwrite
                return result;
            }
            else { // Command not accepted
                char data[200] = "";
                snprintf(data, 200, "write Sensor command(0x%02X) fail =%d(%s)", command, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
                Serial.println(data);
                return 0;
            }
        }
        else { // sensor never answered
            char data[200] = "";
            snprintf(data, 200, "Sensor at 0x%02X did not ACK, err = %d(%s)", eSHT2xAddress, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
            Serial.println(data);
            return 0;
        }
    }
}

bool SHT2xClass::waitReady(uint32_t timeoutMs){
  bool ready = false;
  uint32_t tick = millis();
  while((!ready)&&(tick < timeoutMs)){
    Wire.beginTransmission(eSHT2xAddress);
    ready = Wire.endTransmission() == 0 ;
    if(!ready && timeoutMs>0){
      delay(timeoutMs/5); // wait for sensor to complete sample
    } 
  }
return ready;
}

SHT2xClass SHT2x;
stickbreaker commented 5 years ago
bool SHT2xClass::waitReady(uint32_t timeoutMs){
  bool ready = false;
  uint32_t tick = millis();
  while((!ready)&&(millis()-tick < timeoutMs)){
    Wire.beginTransmission(eSHT2xAddress);
    ready = Wire.endTransmission() == 0 ;
    if(!ready && timeoutMs>0){
      delay(timeoutMs/5); // wait for sensor to complete sample
    } 
  }
return ready;
}

Try this.

Chuck.

asetyde commented 5 years ago

reply :

read Sensor command(0xF5) fail =2(ACK) read Sensor command(0xF3) fail =2(ACK) [INFO] Sensor SHT21 fail values !! Temp : -273.000000 Hum : 0.00000

stickbreaker commented 5 years ago

try running this sketch. post its results. i2c scan.ino

The ACK error says the device(sensor) never answered the read command. Based on this you have a hardware fault.

The i2c_scan.ino will probe the i2c bus and list all devices that answer. Run it so that we can confirm the sensor is operational.

Chuck.

asetyde commented 5 years ago

I come back to original library with 1.0.1 final realese, all work perfect . Sensor is ok (scan code)

Thanks for support Chuck as always

asetyde commented 5 years ago

as sensor VEML770 and SHT21x @me-no-dev all work

asetyde commented 5 years ago

However SHT21X sensor seems not work correctly, I'm very tired about it, continues bug on i2c peripherals every update. Seems temperature air too high and humidity freezed. 10 days of monitor, consider about code that I come to you previous mod on sht21x library .

stickbreaker commented 5 years ago

@asetyde I found that the SHT2n sensor are compatible with the Si7013, Si7020, Si7021. I adjusted Adafruits_Si7021 library to also work with the SHT25. Try my library adafruit_Si7021. It seems to work fine with a SHT25

Chuck.

asetyde commented 5 years ago

i load code and now I order some devices to check temp and humidity reliability

asetyde commented 5 years ago

I update with test result

asetyde commented 5 years ago

It's working but I think sensor read 4/5 degree up than real value, I try to understand if esp is cause but is up on 13cm on my device and I think it's not correlated

asetyde commented 5 years ago

I think sensor temperature work is fixed and not influence

stickbreaker commented 5 years ago

@asetyde If your problem is solved, please close this issue.

Chuck.