1
\$\begingroup\$

I will first tell you how I tried two different SHT31 sensors with the following configuration and then I will tell you my experiences.

My Setup: Arduino Pro Mini with SH1106 OLED display + SGP30 TVOC sensor + SHT31. This is basically a battery operated air monitor. It displays sensor data on the screen. Schematic is as below:

schematic

My code (It says "clap" in the code but it is actually a button press):

#include <Wire.h>
#include "Adafruit_SGP30.h"
#include "U8glib.h"
#include "Adafruit_SHT31.h"
#include <EEPROM.h>

Adafruit_SGP30 sgp;
Adafruit_SHT31 sht31 = Adafruit_SHT31();

bool HeaterState = false;
int8_t counter = 0;
int8_t counter2 = 0;
float t;
float h;
float Vread;
bool SGPenabled = EEPROM.read(0);
/* return absolute humidity [mg/m^3] with approximation formula
* @param temperature [°C]
* @param humidity [%RH]
*/
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE);

uint32_t getAbsoluteHumidity(float temperature, float humidity) {
  // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
  const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
  const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
  return absoluteHumidityScaled;
}

void setup() {
  preparesecreen();  
  sht31.begin(0x44);
  if (SGPenabled) {
    sgp.begin();
    sgp.setIAQBaseline(0x99AF, 0x99AF); // (CO2_base , TVOC_base)
  }      
  attachInterrupt(0, Clap, FALLING);
  sht31.heater(false);   
}

unsigned long t1 = 0; // holds info of rapid claps
unsigned long t2 = 0; // prevents wrong trigger of single clap
unsigned long currenttime;
void Clap() {
  currenttime = millis();
 
  if (currenttime - t2 < 100) {
    t2 = currenttime; return;
  }
  
  if (!HeaterState) {
    HeaterState = true;
    counter = 80;  
  } else if (HeaterState) {
    counter = 0;  
  }
           
  if (currenttime - t1 <= 1000) {
    EEPROM.write(0,!SGPenabled);
    void(* resetFunc) (void) = 0;       
    resetFunc(); 
  } else t1 = currenttime;
  t2 = currenttime;
}

void loop() {
  t = sht31.readTemperature();
  h = sht31.readHumidity();

  if (SGPenabled) { 
    sgp.setHumidity(getAbsoluteHumidity(t, h));
    sgp.IAQmeasure();
  }
  displayMEAS(); delay(500);
  
  while (HeaterState) {
    if (sht31.isHeaterEnabled() == 0)
      sht31.heater(true);
    displayHEAT();
    counter--;
    if (counter<=0)
      HeaterState = false;
    if (counter<=40) {
      if (sht31.isHeaterEnabled())
        sht31.heater(false);
    }
    delay(1000);
  } 
}

bool first15 = true;

void displayMEAS() {
  u8g.firstPage();
  do { 
    if (SGPenabled) {
      u8g.setFont(u8g_font_6x10);
      u8g.drawStr( 0, 10, "Temp:"); u8g.drawStr( 70, 10, "Hum:");
      u8g.drawStr( 0, 45, "TVOC(ppb):"); u8g.drawStr( 70, 45, "eCO2(ppm):");
      if (!first15) {   
        u8g.setPrintPos(0, 64);
      u8g.setFont(u8g_font_fub14); // u8g_font_tpssb u8g_font_9x18B u8g_font_courB12 u8g_font_fub17
        u8g.print(sgp.TVOC);
        u8g.setPrintPos(70, 64);
        u8g.print(sgp.eCO2);
      } else {
        u8g.setPrintPos(0, 64);
        u8g.setFont(u8g_font_fub14);
        u8g.print("...");
        u8g.setPrintPos(70, 64);
        u8g.print("...");
      } 

      u8g.setPrintPos(0, 30);
      u8g.print(t); 
      u8g.setPrintPos(70, 30); 
      u8g.print(h);
  
      u8g.setFont(u8g_font_7x14B);
      u8g.drawStr( 122, 30, "%"); // Hum 

      u8g.setFont(u8g_font_fub11);
      u8g.drawStr( 52, 30, "C"); // Temp
    } else {
      u8g.setFont(u8g_font_fub11);
      u8g.drawStr( 0, 30, "Temp:           *C");
      u8g.drawStr( 10, 57, "Hum:            %");
      u8g.setFont(u8g_font_fub14);
      u8g.setPrintPos(52, 30);
      u8g.print(t); 
      u8g.setPrintPos(52, 57); 
      u8g.print(h);
    } 
    
  } while(u8g.nextPage());

  if (first15) {
    counter2++;
    if (counter2>=23)
      first15=false;
  } 
}


void displayHEAT() {
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_fub11);   
    u8g.drawStr( 15, 15, "Evaporating");  u8g.drawStr( 10, 35, "Condensation");
    u8g.setPrintPos(60, 60);

    if (counter != 0) 
      u8g.print(counter);
    else
      u8g.drawStr( 15, 60, "CANCELLED!");
  } while(u8g.nextPage());
}


void preparesecreen() {
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255); // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3); // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1); // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
}

Experiences:

  1. The whole system works normal when SHT31 is brand new for some time.
  2. SHT31 stops working after some time where I reupload adjusted codes and it halts the code at sht31.begin(0x44).
  3. The system works normally when SHT31 is unplugged, the code doesn't halt, it displays "nan" for temperature and humidity of course.
  4. The test code for SHT31 by Adafruit also halts at sht31.begin(0x44) and it doesn't give error an message.
  5. Many libraries are tried but all of them halt at the start, only the "sht31 test" can be read from serial monitor.
  6. SHT31 does work for a single time when it has been unpowered for a long time, but it halts the code after the first reading, the readings are reasonable if I can feel the temperature correctly.

My Diagnosis: The sensor is electrically fine, it is not broken. Maybe the OLED secreen or SGP30 is incompatible to work with SHT31. Maybe a register is being wrongly written for SHT31 and it stops it. A code fix would remedy the problem.

Physical Photo: The connections seem loose, I will definitely not going to use jumpers again. I will connect JST to headers always. But in this case I checked with a multimeter, and everything is fine.

Physical

My Request: I would be glad if a hard coder could solve the issue by making changes in the Adafruit library. As is obvious from my code, my coding skills are far from great.

Plus: There is a similar problem here; Adafruit stuff was unable to solve it and the problem is left unsolved: Adafruit forum question link

\$\endgroup\$
7
  • \$\begingroup\$ What makes you think it is the code? I’d suggest you test each device one by one. Don’t use interrupts for your pushbutton - could be what is causing your problem. \$\endgroup\$
    – Kartman
    Oct 1, 2022 at 1:16
  • \$\begingroup\$ I tried each device one by one, only the SHT31 gives error with its own test code. I don't think button interrupt is relevant to this but why wouldn't I use it? There is no interrupts in test code anyway. I thought it is the code because the sensor gives reading for single time and this is the second sensor I am testing, can they all be broken in the same way? \$\endgroup\$ Oct 1, 2022 at 1:18
  • \$\begingroup\$ Have you measured voltages? Rule out the obvious problems first. Write a sketch only for the sht31. Have it flash a led if it is ok. Basically wind the hardware and software back to the minimum required. Then work logically through the code to identify where it stops. \$\endgroup\$
    – Kartman
    Oct 1, 2022 at 2:13
  • \$\begingroup\$ Change your initialisation code as per this part of the example, or run the example sketch with all others connected and without other sensor/display connected. Also have you try to change the address to 0x45? \$\endgroup\$
    – hcheung
    Oct 1, 2022 at 2:56
  • \$\begingroup\$ How can I change the initialisation code? sht31.begin() is only one that I know. I measured voltages, the Arduino provides 5V correctly. I tried to disconnect OLED and SGP30 but the code still at the same point. Changing the Address means I must connect AD pin to VCC. The current I2C address worked for some time so it can't be wrong I guess. \$\endgroup\$ Oct 1, 2022 at 10:11

1 Answer 1

1
\$\begingroup\$

Rule #1: always create a minimal reproducible example - this includes the hardware setup. "Rip" your setup apart, connect only the sensor directly to the arduino and build a scetch only for reading those values and e.g. print it via uart.

Rule #2: if an electrical system sometimes works and then stops working it is very likely that it is a connection issue. If it is not a connection issue the second best guess is, that some specs are violated (e.g. line load, pull up/down strength, power/thermal ratings).

Rule #3: we humans are blind (regarding electricity). If you can get some looking glasses i.e. an oscilloscope to "see". Many USB scopes actually allow to decode protocols on the fly which can be super handy to identify issues with e.g. I2C.

LT;DR: build a minimal setup and keep in mind that I2C works with pull-ups and open drain IOs. Chose the pull-ups accordingly to your setup and expected line capacity and ideally, check with an scope what is actually happing on those lines.

\$\endgroup\$
2
  • \$\begingroup\$ I have no access to scopes currently but even I had, what will I exactly look for, I am guessing I will see bunch of square waves with different duty cycles, so what? Also the pullup resistors of I2C are built-in sensors and OLED giving 3.4 kohm in total for both SCL and SDA (10k on each device giving 3.4k as parallel) and I tried the system with only Arduino and SHT31 with its own test code provided by Adafruit, it stucks in the same way. \$\endgroup\$ Oct 1, 2022 at 22:36
  • 1
    \$\begingroup\$ you will see when the system will be stuck (is it during the start or stop or adress or does the clk suddently stops within a word or the sensor stops to NACK or...) + if the signals degrade over time which can give important information if e.g. its a supply or grounding or line load issue. \$\endgroup\$ Oct 2, 2022 at 7:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.