SHT3x or I2C sensor issue

Hello all.

So, I have a sketch that I've been running for a few years now that runs the environmental equipment for a greenhouse. I've been using a DHT22 sensor but I've never been happy with the humidity inaccuracies. It runs on a Mega 2560 board with a 1602 LCD shield.

Recently, I upgraded to an SHT31 sensor from Keyestudio. At first, it was great but after a week or so it just sort of stopped reading. It appears that the Arduino itself is still running, but I'm not entirely sure. Maybe it's the sensor itself? The I2C bus?

Here's the sketch...

#include <Wire.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define Addr 0x44

#define RELAY_ON 0
#define RELAY_OFF 1

#define Relay_1 25 // Relay 1/Pin 25 Dehumidifier
#define Relay_2 27 // Relay 2/Pin 27 Unused
#define Relay_3 29 // Relay 3/Pin 29 Fogger
#define Relay_4 31 // Relay 4/Pin 31 Unused
#define Relay_5 33 // Relay 5/Pin 33 A/C
#define Relay_6 35 // Relay 6/Pin 35 Unused
#define Relay_7 37 // Relay 7/Pin 37 Heat
#define Relay_8 39 // Relay 8/Pin 39 Unused

int page = 1;
boolean repeat = false;
int on_time [] = {0, 0, 0, 0};
float on_time_value = 0;
int off_time[] = {0, 0, 0, 0};
float off_time_value = 0;
boolean hold = false;
int cur_x = 13;
int cur_y = 0;
boolean toggle = 0;
float count = 0;

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  Wire.begin();
  Serial.begin(9600);
  delay(300);

  digitalWrite(Relay_1, RELAY_OFF);
  digitalWrite(Relay_2, RELAY_OFF);
  digitalWrite(Relay_3, RELAY_OFF);
  digitalWrite(Relay_4, RELAY_OFF);
  digitalWrite(Relay_5, RELAY_OFF);
  digitalWrite(Relay_6, RELAY_OFF);
  digitalWrite(Relay_7, RELAY_OFF);
  digitalWrite(Relay_8, RELAY_OFF);

  pinMode(Relay_1, OUTPUT);
  pinMode(Relay_2, OUTPUT);
  pinMode(Relay_3, OUTPUT);
  pinMode(Relay_4, OUTPUT);
  pinMode(Relay_5, OUTPUT);
  pinMode(Relay_6, OUTPUT);
  pinMode(Relay_7, OUTPUT);
  pinMode(Relay_8, OUTPUT);
  delay(400);//Changed from 4000 on 2/11/22
  
//void(* resetFunc) (void) = 0;//declare reset function at address 0

}

void loop()
{
  unsigned int data[6];

  Wire.beginTransmission(Addr);
  Wire.write(0x2C);
  Wire.write(0x06);
  Wire.endTransmission();
  delay(500);

  Wire.requestFrom(Addr, 6);
  if (Wire.available() == 6)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
    data[2] = Wire.read();
    data[3] = Wire.read();
    data[4] = Wire.read();
    data[5] = Wire.read();
  }

  float cTemp = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
  //float fTemp = (cTemp * 1.8) + 32;
  float fTemp = ((((data[0] * 256.0) + data[1]) * 315) / 65535.0) - 49;
  float humidity = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0);

  Serial.print("Relative Humidity : ");
  Serial.print(humidity);
  Serial.println(" %RH");
  Serial.print("Temperature in Celsius : ");
  Serial.print(cTemp);
  Serial.println(" C");
  Serial.print("Temperature in Fahrenheit : ");
  Serial.print(fTemp);
  Serial.println(" F");

  lcd.setCursor(0, 0);
  lcd.print("Temp - ");
  lcd.print(fTemp);
  lcd.print(" F");
  lcd.setCursor(0, 1);
  lcd.print("Hum  - ");
  lcd.print(humidity);
  lcd.print(" %");


  delay(500);

  //Dehuey trigger on Relay_1 at Pin 25
  if (humidity > 80)//No Correction
  {
    digitalWrite(Relay_1, RELAY_ON);
    Serial.print("Humidity: ");
    Serial.print(humidity);
    Serial.print("\t");
    Serial.print("Dehuey ON");
    Serial.print("\t");
  }

  if (humidity < 70)//No Correction
  {
    digitalWrite(Relay_1, RELAY_OFF);
    Serial.print("Humidity: ");
    Serial.print(humidity);
    Serial.print("\t");
    Serial.print("Dehuey OFF");
    Serial.print("\t");
  }

  //Fogger trigger on Relay_3 at Pin 29
  if (humidity < 65)//No Correction
  {
    digitalWrite(Relay_3, RELAY_ON);
    Serial.print("Humidity: ");
    Serial.print(humidity);
    Serial.print("\t");
    Serial.print("Fogger ON");
    Serial.print("\t");
  }

  if (humidity > 72)//No Correction
  {
    digitalWrite(Relay_3, RELAY_OFF);
    Serial.print("Humidity: ");
    Serial.print(humidity);
    Serial.print("\t");
    Serial.print("Fogger OFF");
    Serial.print("\t");
  }

  //A/C trigger on Relay_5 at Pin 33
  if (fTemp > 82)//No Correction
  {
    digitalWrite(Relay_5, RELAY_ON);
    Serial.print("Temperature: ");
    Serial.print(fTemp);
    Serial.print("\t");
    Serial.print("A/C ON");
    Serial.print("\t");
  }

  //A/C trigger on Relay_6 at Pin 33
  if (fTemp > 82)//No Correction
  {
    digitalWrite(Relay_6, RELAY_ON);
    Serial.print("Temperature: ");
    Serial.print(fTemp);
    Serial.print("\t");
    Serial.print("A/C ON");
    Serial.print("\t");
  }

  if (fTemp < 76)//No Correction
  {
    digitalWrite(Relay_5, RELAY_OFF);
    Serial.print("Temperature: ");
    Serial.print(fTemp);
    Serial.print("\t");
    Serial.print("A/C OFF");
    Serial.print("\t");
  }

  if (fTemp < 76)//No Correction
  {
    digitalWrite(Relay_6, RELAY_OFF);
    Serial.print("Temperature: ");
    Serial.print(fTemp);
    Serial.print("\t");
    Serial.print("A/C OFF");
    Serial.print("\t");
  }

  //Heat trigger on Relay_7 at Pin 37
  if (fTemp < 66)//No Correction
  {
    digitalWrite(Relay_7, RELAY_ON);
    Serial.print("Temperature: ");
    Serial.print(fTemp);
    Serial.print("\t");
    Serial.print("Heat ON");
    Serial.print("\t");
  }

  if (fTemp > 72)//No Correction
  {
    digitalWrite(Relay_7, RELAY_OFF);
    Serial.print("Temperature: ");
    Serial.print(fTemp);
    Serial.print("\t");
    Serial.print("Heat OFF");
    Serial.print("\t");
  }
}

I forgot to add that I have the sensor connected as follows...

Pwr & Gnd - Connected to 5V & Gnd at the pins with the Digital pins on the end.
SDA - Pin 20
SCL - Pin 21

To be able to quickly see if the program is still running you can add a heartbeat LED that blinks
at 1 Hz

Another way would be to use the second harware-serial interface of the Mega2560 to connect to
a laptop for datalogging purposes
or to connect a ESP8266 to this second serial interface to transmit data by WiFi

How about using a SHT31 library ?

I have looked through all the documentaion of the adafruit library

it offers reading the status, checking if onchip heating is on
and a reset function

the keystudio demo-code commnicates the "hard way"

best regards Stefan

1 Like

Thanks Stefan. I will try the Adafruit code now. The only reason I used the Keyestudio code was that I tried to use, I'm not sure which but another code and it wouldn't read at all. When I dropped the KS code in, it read so I assumed it was ok.

Could I just check the serial status on the USB with my laptop and IDE? Would that be the same? I don't have an ESP2866 yet but I want to add it for wireless logging. The only reason I hadn't was because I thought I read that they were difficult to get working.

Off to test that Ada code. Will report back in a few.

using the second serial interface requires a USB-to-TTL-adapter.

If you don't use the "first" serial interface yes of course you can use the standard-serial interface for status-messages and for debugging.

The ESP8266 can be used in different ways.

  • using the factory delivered AT-firmware
    which I never did because every little bit has to be done with AT-commands

  • programming the ESP8266 just the exact same way as any arduino with the IDE

You have to install the ESP8266-supporting with the board-manager and additional libraries
but now this is pretty easy.

I would recommend a ESP8266 WeMos D1 mini or a ESP8266 nodeMCU-board
price-range $4 to $8
Or if you can afford a few more bucks $10 to $12 taking the ESP32 which has even more RAM more ADC-channels and an RTC onboard

I use the ESP32 as the Arduino-replacement. Whenever I need a lot of low-frequency IO-pins I use MCP23017 I²C-expanders

Just in case I have many PWM-channels the Mega2560 would be a choice but there are IC like the PCA9685 that offer 16-channel PWM over I2C too.

best regards Stefan

1 Like

Ok. Code uploaded and it is all working well at the moment. Being that it stops reading at random, I'll have to play the waiting game for a spell. Thank you very much for the advice and direction.

I am considering these modules as they come with the programmer. I imagine that takes the place of the TTL adapter.

If I had known more a few years back when I built these that I could just use the more powerful ESP8266 and add-ons for I/O, water under the bridge now I suppose.

I'll update again when it either decides to act up again or seems to be working for a decent while. I have another 4 coming in soon so I'll at least be able to see if it's a bad module.

Hi FourRings,

I explicitly say avoid any kind of ESP-01 because they have only 2 IO-pins!
by the way Amazon is not the cheapest source for electronic components.

I recommend Wemos D1 Mini

or nodeMCU

search on ebay for "Wemos D1 Mini" or ESP8266 nodeMCU

best regards Stefan

1 Like

Ahh, I see. So what is the difference between an ESP-01 and the ESP-12?

Sorry for sounding the noob here. Although I was in IT for many years, programming just managed to give me headaches! I've limped along reasonably well for the past few years but it's still a struggle. I do want to become proficient, as it's all very intriguing to me and I can just imagine all the things I'd like to do,

Also, what's best to use for programming the ESP-12? Any generic USB-to-TTL converter?

Ok. So now the SHT sensor is varying pretty wildly. turning on and off equipment way faster than it ever had. I'm watching the temp and humidity go up and down pretty quickly in a random fashion. When I check the numbers to the static readers I have in there, they're way off.

I have to put the old code back in for the time being until I get this resolved. Ugh, I thought going from DHT sensors to the SHT was going to make my life easier.

The difference is:
I haven't looked up the specs of the ESP-01 because I don't use them. It might be that they have less flash-memory.

The Wemos D1 mini and nodeMCU have their USB-to-COM-adapter onboard.
Despite to the ESP-01 which needs an extra USB-to-COM-adapter
The ESP8266-modules soldered on the Wemos D1 mini / nodeMCU have a better shielding and an onboard LED which I always use as a heartbeat-signal.

example use: fast blinking while WiFi-connection is not yet established but attempting to do
slow blinking if WiFi-connection is established

best regards Stefan

1 Like

The values going up / down can have various reasons. It is possible that this is caused by
too long I2C-wires. I2C is designed for very short wiring 5 to 20 cm on the same PCB.
Anything that goes beyond 1m is difficult.
If you have very long wires there are special chips for long-distance I2C-wiring which would be inserted inbetween so that the "standard" I2C-wiring becomes short

I2C-Sensor---short-wire--special-long-distance-chip-------------looooooong-distance---special-long-distance-chip---short-I2C-wire----Arduino

if your I2C-wires are short and no EMV is around it might be that your code has a bug like out-of-boarder writing to arrays or using String (instead of SafeString)

If you have a spare-SHT31-Keystudio-sensor and a any spare-Arduino connect a testset of them and log the readings to the a serial monitor-software that can store the received data on hardidsk. Let this setup run for a day to see if this produces the same errors.

best regards Stefan

1 Like

Good enough reasons for me. I'll grab them and start doing some testing.

It's odd that they were reading fine before the Adafruit code. They just stopped reading was the issue. The wires are about 30cm long, or so. I can shorten them but again, they were reading normally, when they were reading.

Now that I've uploaded my previous code, the wild swings are gone but so is the accuracy of the sensor. Both temp and humidity are off 10-13% across the board now. This is very odd. I won't be able to test with another sensor as I don't have them on hand yet. Maybe I made a poor choice in sensors?

So, I shortened the wires and it didn't seem to make a difference until I hard reset the mega. I tried doing that with the Adafruit code, but no luck. I'm back to the original code I had for now

Can you show a photo of your project ?
The SHT31 works at 3.3V and at 5V. The Arduino Mega has onboard pullup resistors of 10k and the Keyestudio module has pullup resistors of 10k. It should work, there are not many things that can go wrong.

Things to watch out for:

  • The I2C can not deal with crosstalk between SDA and SCL. Do not put a SDA wire next to a SCL wire for some distance (the I2C bus might stop working when SDA and SCL are next to each other in a flat ribbon cable).
  • Motors can introduce spikes in the I2C bus. Relays can also cause electronic noise. It depends if the coils use the same 5V power and the same GND as the Arduino.
  • Keep the wires short, up to 50 cm should work.
  • The GND wire is the most important part of the I2C bus. The GND to the Keyestudio module should not be used for other things.

A timeout was added to the Wire library. It is still undocumented, but easy to add. That might help to keep the Arduino going in case of noise on the I2C bus.

1 Like

The SDA & SCL lines are in the ribbon together. I'll have to see about pulling them apart a bit later and see if the freezing goes away. No motors nearby and it seems like the wires and the sensors are far enough away from relays and mains voltage.

Here are the pics. Please excuse the ugliness!


The SDA can be paired with GND, but that increases the capacitance. The same for SCL. More capacitance means a lower clock speed might be needed and perhaps a stronger pullup.

With crosstalk between SDA and SCL, there is nothing you can do.

The official I2C document is UM10204.pdf : https://www.nxp.com/docs/en/user-guide/UM10204.pdf
:point_right: Read section 7.5 on page 54 :point_left:

You can go up to 3mA for a standard I2C bus.
Arduino Mega internal : about 50k pullup ?
Arduino Mega onboard : 10k pullup
Sensor module : 10k pullup
Your pullup is now: 50k // 10k // 10k = 4k5
Your current is now: 5V / 4k5 = 1.1 mA

That means you can lower the impedance of the I2C bus by adding pullup resistors of 2k7 (or 3k9 or 4k7).

1 Like

Thanks. I'll give that a read. For the time being, I'll separate the wires and see how that plays out.

So a bit of an update. I separated the SDA & SCL wires and ensured that they are nowhere near each other or any relays, mains voltage, etc. Still froze. So I connected my laptop to read the serial monitor and for about a second, there was nothing. Then all of a sudden it came to life, both on the monitor and on the Mega itself. Not sure what this means.