Using multiple SHT20 I2C temperature & humidity sensors with Arduino

Hi there,

I'm trying to use three I2C humidity & temperature sensors for my setup and a bit confused on wiring and coding them reading materials on the web. The sensors are a developed type of SHT2x sensor like the one below:

It seems it has built-in resistors so that I do not need to use resistors as been suggested for regular I2C connections for SDA and SCL. Is that right?

My main issue in wiring these to arduino is that I'm not sure if I can connect them all with the same pin addresses. Based on I2C reference materials on the web, it seems I could have them parallel to the arduino. Please advise if this is incorrect.

And to be able to recognize each by arduino are they detectable by arduino if they are parallel?
I tried to find some references specifically for this type of sensor but I couldn't. I appreciate if anyone can help me solving my problem for wiring and coding of these sensors.

Thanks!

Every device on the I2C bus must have a unique address.
If you can't change the address of a sensor, then an I2C multiplexer could be a solution.
Leo..

Thanks for your reply Wawa!
So I need this part between Arduino and the sensors, is that right? Is there a wiring map I can follow for this?

You can connect up to eight sensors with the same I2C address to that board.
Wiring/code should be on the page I linked to.
Leo..

Okay, I have connected my SHT20 sensors and one SHT10 to the multiplexer. Now it's all set with distinct addresses for my Arduino. I tried to find the proper code for it, but it's a bit confusing..

Anyone can suggest a reference for defining this i2c bus connection for Arduino?

Thanks.

Which I2C address. The one for the muxer or the sensors.
Which Arduino.

Please read the "How to post" sticky.
And post your coding attempts (with code tags).
Leo..

The Arduino is Mega and each sensor is connected to one SD and SC channel on multiplexer, then the master SDA and SCL channels on the multiplexer are going to SDA and SCL pins on Arduino.. Just like the wiring on page you shared in your previous reply. There was no shared code in that page though.

This is an example I found for the coding, but I'm not sure I can change this one for my purpose. What I need from Arduino is to constantly read data (temperautre and RH) from all sensors and based on their mean value act to control other devices connected to it. The whole setup is like an environmental chamber.

Is it possible to use sht1x in the same way as sht2x? I mean could we connect data pin and clock pin (in sht1x) to SDA and SCL channels (the same as sht2x in i2c bus connection)?

The muxer is basically a set of switches that connects only one sensor at the time to the Mega.

So tell the muxer to switch to sensor 1, and then read that sensor.
Then switch the muxer to sensor 2, and read that sensor.
etc.

We first need to see a picture of YOUR setup, to check if you have done it right.
Then post your best coding attempts.
Here we usually don't write code for you. We just help you fix the code you have.
Leo..

Tried to upload the code I prepared based on the references for using multiplexer. Now the problem is when I upload the code successfully without no error message, Arduino does nothing and the lcd freezes in its initial resetting mode. I tried to track the faulty line in the code and it seems in the setup() when I call tcaselect() command, this problem comes up.

The wiring for the multiplexer is according to the link you shared earlier.

Attached is the code for the reference. I had to use the Arduino to control a lot of stuff for my setup, so you may find it quite messy.. Please let me know if you need more references to be able to check the code.

Thanks in advance for your help!

WVT_for_80.ino (13.3 KB)

Can't see your code.
Read the last sentence of post#5 again.

Below is the code..
I just deleted some parts in the loop section (which were for controlling components by the Arduino) as the forum has character limit.

// section of the operateMainMenu() function below.
String menuItems[] = {"Time", "Sampling Time"};

// Navigation button variables
int readKey;
int savedDistance = 0;

// Menu control variables
int menuPage = 0;
int maxMenuPages = round(((sizeof(menuItems) / sizeof(String)) / 2) + .5);
int cursorPosition = 0;

// Creates 3 custom characters for the menu display
byte downArrow[8] = {

};

byte upArrow[8] = {

};

byte menuCursor[8] = {

};
// ***** Main Code **
#include <Wire.h>
#include <LiquidCrystal.h>
extern "C" {
#include "utility/twi.h" // from Wire library, so we can do bus scanning
}
#include "DFRobot_SHT20.h"
DFRobot_SHT20 sht20;

#define TCAADDR 0x70
void tcaselect (uint8_t i) {
if (i > 7) return;

Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}

//Variables and setpoints
int chk;
float HUM; //Stores humidity value
float Temp; //Stores temperature value
#define HiTEMP 24.85
#define LoTEMP 24.2
#define Compen 0.2 // the temperature defference which is supposed to be Compensated by heating pad
#define HumSETPOINT 50 // These values are based on trial and error for acheiving the best humidity conditions
#define HumRESOLUTION 0.5

// A 1602 SainSmart LCD Keypad module has been used in this setup
LiquidCrystal lcd (8, 9, 4, 5, 6, 7); // Initialize the library with the numbers of the interface pins

// Units SETUP *************************************************
int fan = 1; // The pin number that fan is connected to
int HumFan = 13;
int HumFanSpeed = 22;
int SolHum = 2;
int SolMain = 3;
int SolEx =11;
int WB = 53;
int Hpad = 52;
#define HUMIDIFIER 12 //setting humidifier to pin 12
#define ON false //turns ON the Relay Board Contact
#define OFF true //turn OFF the Relay Board Contact
#define SensorHum 40 //For the water level switch in the humidifier
#define SensorMain 42 //For the water level switch in the main chamber
#define SensorEx 44 //For the water level switch in external water bath

//*********************** LCD Initials ************************
// define some values used by the panel and buttons
int lcd_key = 0;
int adc_key_in = 0;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5

// read the buttons
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the sensor
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
// For V1.1 us this threshold
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 250) return btnUP;
if (adc_key_in < 450) return btnDOWN;
if (adc_key_in < 650) return btnLEFT;
if (adc_key_in < 850) return btnSELECT;
return btnNONE; // when all others fail, return this...
}

#define MILLIS_OVERFLOW 34359738

// To control solenoid valve a time control is required

// ********* Clock Variables ***
unsigned long currentMillis, previousMillis, elapsedMillis;
int seconds, minutes, hours;
boolean start= true;
boolean a = false;

void setup() {

Wire.begin(); //Initialize I2C Harware
Serial.begin(115200);
//INITIALIZING SENSORs
tcaselect(4);
sht20.initSHT20();
Serial.println("SHT20 Blue!");
sht20.checkSHT20();
tcaselect(6);
sht20.initSHT20();
Serial.println("SHT20 Green!");
sht20.checkSHT20();
tcaselect(7);
sht20.initSHT20();
Serial.println("SHT20 Yellow!");
sht20.checkSHT20();
//
**************************

pinMode(fan, OUTPUT);
Serial.begin(9600);
pinMode(HUMIDIFIER, OUTPUT);
digitalWrite(HUMIDIFIER, OFF);
pinMode(HumFan, OUTPUT);
digitalWrite(HumFan, OFF);
pinMode(SolMain, OUTPUT);
pinMode(SolHum, OUTPUT);
pinMode(SolEx, OUTPUT);
pinMode(WB, OUTPUT);
digitalWrite(WB, OFF);
pinMode(Hpad, OUTPUT);
digitalWrite(Hpad, OFF);

lcd.begin(16, 2);
lcd.clear();

//FAN Initialization ****
analogWrite(fan, 255); // Fan needs to work very slowly and this is just to initialize the fan
delay(500);
analogWrite(fan, 25);
}

void loop() {
lcd.print("Hello..");
digitalWrite(SolMain, OFF); // After reseting the setup each time Select Bottun should be pressed to reset the time for Solenoid Valve Control
digitalWrite(SolHum, OFF);
digitalWrite(SolEx, OFF);

if (lcd_key == btnSELECT || start == false ) {
setClock();
start = false;
}

//READING Humidity and Temperature*******
//There are 3 SHT20 sensors connected to channels # 4,6 and 7 of the multiplexer
//Channel #5 is connected to a SHT10 which is left idle as it does seem to be compatible with i2c bus connections
lcd.setCursor(0, 1); // set the cursor to column 0, line 1
for (int i=1;i<5;i++){
if(i=2){return; //skiping sht10 for now
}
else
{
tcaselect(i+3);
Temp =+ sht20.readTemperature();
HUM =+ sht20.readHumidity();
}
}
delay(100);
float hum = HUM/3;
float temp = temp/3;

//Controlling Humidity *********
//deleted
// Controlling Water Bath
//deleted
// Controlling Heating Pad
//deleted

// LCD Display and Menu
lcd_key = read_LCD_buttons(); // read the buttons

switch (lcd_key) // depending on which button was pushed, we perform an action
{
case btnRIGHT:
{
mainMenuDraw();
drawCursor();
lcd.setCursor(0, 0);
lcd.print("Elapsed Time:");
lcd.setCursor(7,1);
lcd.print(hours);
lcd.print(":");
lcd.print(minutes);
lcd.print(":");
lcd.print(seconds);

break;
}
case btnLEFT:
{
mainMenuDraw();
drawCursor();
lcd.setCursor(0, 0);
lcd.print("Fan Speed:");
lcd.setCursor(7,1);
break;
}
case btnSELECT:
{
mainMenuDraw();
drawCursor();
if (lcd_key == btnSELECT && start == false) {
lcd.setCursor(0,0);
lcd.print("TEST Running !");
}
else {
lcd.setCursor(0,0);
lcd.print("TEST STARTED!");
delay(2500);
a = true;
}
break;
}
case btnUP:
{
mainMenuDraw();
drawCursor();
if (a == true){
lcd.setCursor(0, 0);
lcd.print("Next Sampling:");
lcd.setCursor(7,1);

lcd.print(59 - minutes);
lcd.print(":");
lcd.print(59 - seconds);
}
else{
lcd.setCursor(0, 0);
lcd.print("TEST Has Not ");
lcd.setCursor(0, 1);
lcd.print("Been Started Yet!");
}
break;
}
case btnNONE:
{
mainMenuDraw();
drawCursor();
lcd.setCursor(0,0);
lcd.print("Temp: ");
lcd.setCursor(0,1);
lcd.print("Humidity: ");
lcd.setCursor(10,0);
lcd.print(temp,1);
lcd.setCursor(14,0);
lcd.print("C");
lcd.setCursor(10,1);
lcd.print(hum,1);
lcd.setCursor(14,1);
lcd.print("%");
if (a == true){
lcd.setCursor(15,1);
lcd.print((char)126);

}
break;
}
}

Serial.print(hours);
Serial.print(":");
Serial.print(minutes);
Serial.print(":");
Serial.print(seconds);
Serial.print(",");
Serial.print(hum);
Serial.print(",");
Serial.println(temp);

delay(500);
if (minutes == 0 && seconds == 0 )
{
/Solenoid Valves Control****/
//deleted
}
}

// ********** Menu FUNCTIONS *******************
// This function will generate the 2 menu items that can fit on the screen. They will change as you scroll through your menu. Up and down arrows will indicate your current menu position.
void mainMenuDraw() {
Serial.print(menuPage);
lcd.clear();
lcd.setCursor(1, 0);
lcd.print(menuItems[menuPage]);
lcd.setCursor(1, 1);
// lcd.print(menuItems[menuPage + 1]);
if (menuPage == 0) {
// lcd.setCursor(15, 1);
// lcd.write(byte(2));
} else if (menuPage > 0 and menuPage < maxMenuPages) {
lcd.setCursor(15, 1);
lcd.write(byte(2));
lcd.setCursor(15, 0);
lcd.write(byte(1));
} else if (menuPage == maxMenuPages) {
lcd.setCursor(15, 0);
lcd.write(byte(1));
}
}

// When called, this function will erase the current cursor and redraw it based on the cursorPosition and menuPage variables.
void drawCursor() {
for (int x = 0; x < 2; x++) { // Erases current cursor
lcd.setCursor(0, x);
lcd.print(" ");
}

}

void setClock()
{
currentMillis = millis();
if (currentMillis < previousMillis){
elapsedMillis += MILLIS_OVERFLOW - previousMillis + currentMillis;
} else {
elapsedMillis += currentMillis - previousMillis;
}

if (elapsedMillis > 999){
seconds++;
elapsedMillis = elapsedMillis - 1000;
}

if (seconds == 60){
minutes++;
seconds = 0;
}
if (minutes == 60){
hours++;
minutes = 0;
}
if (hours == 24){
hours = 0;
}

previousMillis = currentMillis;
}

Sorry, I assumed your problem was opening the attachment. Tried to separate each block, is it fine now?

//A Menu function

String menuItems[] = {"Time", "Sampling Time"}; // section of the operateMainMenu() function below. 

// Navigation button variables
int readKey;
int savedDistance = 0;

// Menu control variables
int menuPage = 0;
int maxMenuPages = round(((sizeof(menuItems) / sizeof(String)) / 2) + .5);
int cursorPosition = 0;

// Creates 3 custom characters for the menu display
byte downArrow[8] = {

};

byte upArrow[8] = {

};

byte menuCursor[8] = {

};

// LIBRARIES and Variable definitions

#include <Wire.h> 
#include <LiquidCrystal.h>
extern "C" { 
#include "utility/twi.h"  // from Wire library, so we can do bus scanning
}
#include "DFRobot_SHT20.h"
DFRobot_SHT20  sht20;


#define TCAADDR 0x70
void tcaselect (uint8_t i) {
if (i > 7) return;

Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}

//Variables and setpoints
int chk;
float HUM; //Stores humidity value
float Temp; //Stores temperature value
#define HiTEMP 24.85
#define LoTEMP 24.2
#define Compen 0.2  // the temperature defference which is supposed to be Compensated by heating pad 
#define HumSETPOINT 50 // These values are based on trial and error for acheiving the best humidity conditions
#define HumRESOLUTION 0.5

// A 1602 SainSmart LCD Keypad module has been used in this setup
LiquidCrystal lcd (8, 9, 4, 5, 6, 7);   // Initialize the library with the numbers of the interface pins

// Defining COMPONENTs to be controlled

int fan = 1;  // The pin number that fan is connected to
int HumFan = 13;
int HumFanSpeed = 22;
int SolHum = 2;
int SolMain = 3;
int SolEx =11;
int WB = 53;
int Hpad = 52;
#define HUMIDIFIER 12  //setting humidifier to pin 12
#define ON false      //turns ON the Relay Board Contact
#define OFF true      //turn OFF the Relay Board Contact
#define SensorHum  40   //For the water level switch in the humidifier
#define SensorMain  42  //For the water level switch in the main chamber
#define SensorEx  44    //For the water level switch in external water bath

// LCD Initials

int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// READING the LCD buttons

int read_LCD_buttons()
{
adc_key_in = analogRead(0);      // read the value from the sensor 
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
// For V1.1 us this threshold
if (adc_key_in < 50)   return btnRIGHT;  
if (adc_key_in < 250)  return btnUP; 
if (adc_key_in < 450)  return btnDOWN; 
if (adc_key_in < 650)  return btnLEFT; 
if (adc_key_in < 850)  return btnSELECT;  
return btnNONE;  // when all others fail, return this...
}

#define MILLIS_OVERFLOW 34359738

// To control solenoid valve a time control is required

// ********* Clock Variables ***
unsigned long currentMillis, previousMillis, elapsedMillis;
int seconds, minutes, hours;
boolean start= true;
boolean a = false;

//SETUP

void setup() {

Wire.begin(); //Initialize I2C Harware
Serial.begin(115200);

//*************INITIALIZING SENSORs*****
tcaselect(4);
sht20.initSHT20();
Serial.println("SHT20 Blue!");
sht20.checkSHT20();
tcaselect(6);
sht20.initSHT20();
Serial.println("SHT20 Green!");
sht20.checkSHT20();
tcaselect(7);
sht20.initSHT20();
Serial.println("SHT20 Yellow!");
sht20.checkSHT20();
//**********************************
  
pinMode(fan, OUTPUT);
Serial.begin(9600);
pinMode(HUMIDIFIER, OUTPUT);
digitalWrite(HUMIDIFIER, OFF);
pinMode(HumFan, OUTPUT);
digitalWrite(HumFan, OFF);
pinMode(SolMain, OUTPUT);
pinMode(SolHum, OUTPUT);
pinMode(SolEx, OUTPUT);
pinMode(WB, OUTPUT);
digitalWrite(WB, OFF);
pinMode(Hpad, OUTPUT);
digitalWrite(Hpad, OFF);

lcd.begin(16, 2);
lcd.clear();

//FAN Initialization ****
analogWrite(fan, 255); // Fan needs to work very slowly and this is just to initialize the fan 
delay(500);
analogWrite(fan, 25);
}

//Main LOOP

void loop() {
lcd.print("Hello..");
digitalWrite(SolMain, OFF); // After reseting the setup each time Select Bottun should be pressed to reset the time for Solenoid Valve Control
digitalWrite(SolHum, OFF);
digitalWrite(SolEx, OFF);

if (lcd_key == btnSELECT || start == false ) {
 setClock();
 start = false; 
}

//READING Humidity and Temperature
//There are 3 SHT20 sensors connected to channels # 4,6 and 7 of the multiplexer
//Channel #5 is connected to a SHT10 which is left idle as it doesn't seem to be compatible with i2c bus connections 
lcd.setCursor(0, 1); // set the cursor to column 0, line 1
for (int i=1;i<5;i++){
   if(i=2){return;  //skiping sht10 for now   
          }
   else
{
tcaselect(i+3);
Temp =+ sht20.readTemperature();
HUM =+ sht20.readHumidity();
}
}
delay(100);
float hum = HUM/3;
float temp = temp/3;  

//Controlling Humidity *********
//deleted
// Controlling Water Bath
//deleted
// Controlling Heating Pad
//deleted

// LCD Display and Menu 
lcd_key = read_LCD_buttons();  // read the buttons

switch (lcd_key)               // depending on which button was pushed, we perform an action
{
case btnRIGHT:
  {
  mainMenuDraw();
  drawCursor();
  lcd.setCursor(0, 0);
  lcd.print("Elapsed Time:");
  lcd.setCursor(7,1);
  lcd.print(hours);
  lcd.print(":");
  lcd.print(minutes);
  lcd.print(":");
  lcd.print(seconds);

  break;
  }
case btnLEFT:
  {
  mainMenuDraw();
  drawCursor();
  lcd.setCursor(0, 0);
  lcd.print("Fan Speed:");
  lcd.setCursor(7,1);
  break;
  }
case btnSELECT:
  {
  mainMenuDraw();
  drawCursor();
  if (lcd_key == btnSELECT && start == false) {
  lcd.setCursor(0,0);
  lcd.print("TEST Running !");
  }
  else {
  lcd.setCursor(0,0);
  lcd.print("TEST STARTED!");
  delay(2500);
  a = true;
  }
  break;
  }
  case btnUP:
  {
  mainMenuDraw();
  drawCursor();
  if (a == true){
  lcd.setCursor(0, 0);
  lcd.print("Next Sampling:");
  lcd.setCursor(7,1);

  lcd.print(59 - minutes);
  lcd.print(":");
  lcd.print(59 - seconds);
  }
  else{
  lcd.setCursor(0, 0);
  lcd.print("TEST Has Not ");
  lcd.setCursor(0, 1);
  lcd.print("Been Started Yet!");
  }
  break;
  }
  case btnNONE:
  {
    mainMenuDraw();
    drawCursor();
    lcd.setCursor(0,0);
    lcd.print("Temp: ");
    lcd.setCursor(0,1);
    lcd.print("Humidity: ");
    lcd.setCursor(10,0);
    lcd.print(temp,1);
    lcd.setCursor(14,0);
    lcd.print("C");
    lcd.setCursor(10,1);
    lcd.print(hum,1);
    lcd.setCursor(14,1);
    lcd.print("%"); 
    if (a == true){
     lcd.setCursor(15,1);
     lcd.print((char)126);

    }
  break;
  }
} 

Serial.print(hours);
Serial.print(":");
Serial.print(minutes);
Serial.print(":");
Serial.print(seconds);
Serial.print(",");
Serial.print(hum);
Serial.print(",");
Serial.println(temp);

delay(500);
if (minutes == 0 && seconds == 0 )
{
/**********Solenoid Valves Control**************/     
 //deleted
}
}

// Menu FUNCTIONS

// This function will generate the 2 menu items that can fit on the screen. They will change as you scroll through your menu. Up and down arrows will indicate your current menu position.
void mainMenuDraw() {
Serial.print(menuPage);
lcd.clear();
lcd.setCursor(1, 0);
lcd.print(menuItems[menuPage]);
lcd.setCursor(1, 1);
//  lcd.print(menuItems[menuPage + 1]);
if (menuPage == 0) {
//    lcd.setCursor(15, 1);
//    lcd.write(byte(2));
} else if (menuPage > 0 and menuPage < maxMenuPages) {
 lcd.setCursor(15, 1);
 lcd.write(byte(2));
 lcd.setCursor(15, 0);
 lcd.write(byte(1));
} else if (menuPage == maxMenuPages) {
 lcd.setCursor(15, 0);
 lcd.write(byte(1));
}
}

// When called, this function will erase the current cursor and redraw it based on the cursorPosition and menuPage variables.
void drawCursor() {
for (int x = 0; x < 2; x++) {     // Erases current cursor
 lcd.setCursor(0, x);
 lcd.print(" ");
}


}

//SetClock Function

void setClock()
{
 currentMillis = millis();
 if (currentMillis < previousMillis){
 elapsedMillis += MILLIS_OVERFLOW - previousMillis + currentMillis;
} else {
 elapsedMillis += currentMillis - previousMillis;
}

if (elapsedMillis > 999){
 seconds++;
 elapsedMillis = elapsedMillis - 1000;
}

if (seconds == 60){
 minutes++;
 seconds = 0;
}
if (minutes == 60){
 hours++;
 minutes = 0;
}
if (hours == 24){
 hours = 0;
}

previousMillis = currentMillis;      
}

Does it seem I am trying to do something highly complicated??

example of multiple i2c sensors use with multiplexors in arduino project

https://wiki.liutyi.info/display/ARDUINO/v5+Sensor+Board+project

Simplified code without CRC check. no libraries for sensors used

Thanks for your reply Liutyi!

So you mean the problem is probably using the library?

I'm trying to understand the code you wrote in the github, but it's highly complicated for me to understand which part I should use for my application. Would you please give me a general pathway to go through this code? My understanding is that the most tricky part is the defining of multiplexer before setup part in the code and if I can construct the required libraries for arduino to work with muxer before the void setup, I can get the results, is that correct?

for some sensors like BMExxx using library and mux cause some issues. but for SHTx it works.

I know v5 code is hard to read (for myself also)

See a simple example of v1 (both setup and code)

https://wiki.liutyi.info/display/ARDUINO/v1+draft+multiple+humidity+sensors+comparision

https://github.com/liutyi/arduino-humidity-sensors-test/blob/master/mega-sd-tft-480x320-i2c-sensors.ino