Connect 4 i2c sensor on an Arduino?

Hello,

Is it possible to connect 4 i2c sensors on a single Arduino?

I currently have DHT22 but I would like to have something reliable.
I thought of SHT35 (if you have other suggestions ...).

The final goal is to control my dual-flow VMC using, among other things, efficiency. For that, I need 4 sensors.

PS : sorry for my English

Page for the SHT3x sensors: SHT3x (RH/T) - Digital Humidity Sensor | Sensirion

It can work with 3.3V and 5V, so it can be used with 3.3V Arduino boards and 5V Arduino boards.
It is not cheap, but accurate.
There are extensive tests with humidity and temperature sensors on this forum, but I could not find it at the moment.

A SHT35 has one address pin, and therefor two of them can be used on the same I2C bus.

Sometimes a trick is possible, to keep all sensors at a unused address and put just one at the right address and then use that one.
The datasheet tells that it is allowed to do this: "The address of the sensor can be changed dynamically during operation by switching the level on the ADDR pin. The only constraint is that the level has to stay constant starting from the I2C start condition until the communication is finished. This allows to connect more than two SHT3x-DIS onto the same bus".

Connect all the SDA and SCL together. Use four digital output pins and connect each to a ADDR pins of the sensors.
Keep them all HIGH.
When you need a sensor, make that ADDR pin low and use the sensor. When done, make the ADDR pin high again.

One cheap TCA9548A i2c multiplexer (like this) is something allow you to connect up to 8 sensors with the same i2c address. Using multiple multiplexers or cascade them allow much more. See example at HST v8 Sensors Board or follow related forum topic. SHT35 is good (I would say that all SHT2x and SHT3x is ok in general)

Hello,

Thank you for your answers @Koepel and @liutyi

If I understand correctly (I am really a beginner in the Arduino world), I have two solutions:

  • Connect my 4 probes to the Arduino and before each probe reading, set the ADDR pin to low, then switch it to HIGH
  • Use a multiplexer

But I have trouble knowing how to connect everything in both cases and which sketch to use.

Switching the address is with all SDA together and all SCL together. Selecting a sensor, is by using the ADDR pins to set one sensor to the I2C address that will be used.

The multiplexer has many different busses, SDA0 and SCL0 to the first sensor, SDA1 and SCL1 to the second sensor, and so on. Selecting a sensor is by setting the multiplexer to a certain I2C bus.

You need a function that select a sensor, and call it every time you need to do something with that sensor.
In both cases there is no need to "unselect" the last sensor.
Most libraries have a class to create one object. You need 4 objects.

I have not used this sensor myself, so I don't know the best library. Try the "Library Manager" of the Arduino IDE and if you don't like those, search on Github.
Sensirion (the manufacturer) has a library on their Github: GitHub - Sensirion/arduino-sht: Repository for Sensirion humidity and temperature sensor support on Arduino.

Hello,

I finally received my multiplexer (TCA9548A).
I tried to modify sketches found on the Internet but … I am lost.

For the connection (4 x SHT3X-DIS + TCA9548A), I relied on this tutorial: Connecting Multiple Sensors using an I2C Multiplexer - BlueDot Sensors

With this sketch :

#include <Arduino.h>
#include <Wire.h>
#include <SHTSensor.h>
#define NB_CAPTEURS 4
#define TCAADDR 0x70
SHTSensor sht;
void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}
 
void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(1000); // let serial console settle
  
  if (sht.init()) {
      Serial.print("init(): success\n");
  } else {
      Serial.print("init(): failed\n");
  }
 
  for(int i = 0; i < NB_CAPTEURS; ++i) {
    tcaselect(i);
    Serial.print("Capteur ");
    Serial.print(i);
    Serial.print(" :");
 
    sht.setAccuracy(SHTSensor::SHT_ACCURACY_MEDIUM); // only supported by SHT3x
  }
}
void loop() {
  for(int i = 0; i < NB_CAPTEURS; ++i) {
    tcaselect(i);
    Serial.print("Capteur ");
    Serial.print(i);
    Serial.print(" :");
 
    if (sht.readSample()) {
      Serial.print("SHT:\n");
      Serial.print("  RH: ");
      Serial.print(sht.getHumidity(), 2);
      Serial.print("\n");
      Serial.print("  T:  ");
      Serial.print(sht.getTemperature(), 2);
      Serial.print("\n");
    } else {
      Serial.print("Error in readSample()\n");
    }
  }
  delay(1000);
}

I have in the Console : “Error in readSample()”

With this code :

#include <Arduino.h>
#include <Wire.h>
#include "SHTSensor.h"
#define NB_CAPTEURS 4
#define TCAADDR 0x70
SHT3xAnalogSensor sht3xAnalog(A4, A5);
void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}
void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(9600);
  delay(1000); // let serial console settle
  for(int i = 0; i < NB_CAPTEURS; ++i) {
    tcaselect(i);
    Serial.print("Capteur ");
    Serial.print(i);
    Serial.print(" :");
  }
  
}
void loop() {
  
  for(int i = 0; i < NB_CAPTEURS; ++i) {
    tcaselect(i);
    Serial.print("Capteur ");
    Serial.print(i);
    Serial.print(" :");
  Serial.print("SHT3x Analog:\n");
  Serial.print("  RH: ");
  Serial.print(sht3xAnalog.readHumidity(), 2);
  Serial.print("\n");
  Serial.print("  T:  ");
  Serial.print(sht3xAnalog.readTemperature(), 2);
  Serial.print("\n");
  }
  delay(1000);
}

I have crazy numbers in the console.

Try not to rush to the end result.

The I2C Scanner sketch is always the start to check if a I2C bus is working.

Run the I2C Scanner to check if you can see the TCA9548A.
Then add to the setup() function the selection of a certain I2C bus with a sensor attached. Test if the I2C Scanner can find that.
Do that for every I2C bus.

Then you can try to get the numbers from one sensor.

Each sensor needs its own object.

SHTSensor sht;   // This is one object for one sensor.

Do not tie all analog output to each other, that can’t be right.
If you do a tcaselect(), then a certain I2C bus is selected. The analog section is not part of that. I suggest to stay with the I2C interface.

Adafruit has a nice tutorial: Overview | Adafruit TCA9548A 1-to-8 I2C Multiplexer Breakout | Adafruit Learning System.

Hello @Koepel,

The 2iC Scanner result :

--- Scan started ---
I2C device found at address 0x70  !
--- Scan finished --

I will see the documentation. But it is very difficult starting with a knowledge of 0. But I will try.

The TCA9548A is visible on the I2C bus.
Then copy the tcaselect() function into the I2C Scanner sketch and select one of the eight I2C busses in setup(). Try to find the sensor that is on that bus.

Like this?

#include "I2CScanner.h"
#define NB_SENSORS 4
#define TCAADDR 0x70

I2CScanner scanner;

void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}


void setup() 
{
	Serial.begin(9600);
	while (!Serial) {};


   for(int i = 0; i < NB_SENSORS; ++i) {
     tcaselect(1);
     scanner.Init();
   }

}

void loop() 
{

  for(int i = 0; i < NB_SENSORS; ++i) {
     tcaselect(i);
     Serial.print("Sensor ");
     Serial.print(i);
     Serial.print(" :");
     scanner.Scan();
     delay(5000);
  }
}

The result :

Sensor 0 :--- Scan started ---
I2C device found at address 0x44  !
I2C device found at address 0x70  !
--- Scan finished ---

Sensor 1 :--- Scan started ---
I2C device found at address 0x70  !
--- Scan finished ---

Sensor 2 :--- Scan started ---
I2C device found at address 0x70  !
--- Scan finished ---

Sensor 3 :--- Scan started ---
I2C device found at address 0x70  !
--- Scan finished --

I now know why the code on page was not working. It’s just because the speed of Serial.begin was not going … I guess …

With Serial.begin (115200) :

⸮⸮^R@⸮⸮⸮⸮͋⸮

With Serial.begin(9600) :

TCAScanner ready!
TCA Port #0
Found I2C 0x0
Found I2C 0x44
TCA Port #1
TCA Port #2
TCA Port #3
TCA Port #4
TCA Port #5
TCA Port #6
TCA Port #7

done

But I don’t know why he can’t find my sensors.

The serial baudrate in the sketch has to be same as in the serial monitor. You can set it in the serial monitor in the bottom-right corner.

You use "I2CScanner.h" and scanner.Init() and so. Can you tell what that is ? I guess someone made a library for the I2C Scanner.

Ah ok for serial baudrate.
Thank you.

For I2CScanner.h et scanner.Init(), in the library manager I searched and installed “i2cscanner”.
The code is an exemple from the Menu > File > Examples > I2CScanner > Scanner.

With this code, I have the same result :

 // --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>
#define NB_SENSORS 4
#define TCAADDR 0x70


void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");

}


void loop()
{
  byte error, address;
  int nDevices;

  for(int i = 0; i < NB_SENSORS; ++i) {
     tcaselect(i);

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
  }
}

Result :

I2C Scanner
Scanning...
I2C device found at address 0x44  !
I2C device found at address 0x70  !
done

Scanning...
I2C device found at address 0x70  !
done

Scanning...
I2C device found at address 0x70  !
done

Scanning...
I2C device found at address 0x70  !
done

Scanning...
I2C device found at address 0x44  !
I2C device found at address 0x70  !
done

Scanning...
I2C device found at address 0x70  !
done

PS : in my previous post, you can see my assembly in attachment.

I didn’t know that someone made a library from the I2C Scanner sketch. Thanks.

Using the changed I2C Scanner sketch code that you showed, you should scan all eight I2C busses.

Could you change the for-loop ?

This is how it is:

  for (int i = 0; i < NB_SENSORS; ++i) {
    tcaselect(i);

Change it to this:

  for (int i = 0; i < 8; ++i)  // Scan all eight I2C busses
  {
    Serial.print( "Selecting bus #");
    Serial.print( i);
    Serial.print( ". ");
    tcaselect(i);

I hope you will see all four sensors :stuck_out_tongue:

Not more :frowning: :

I2C Scanner
Selecting bus #0. Scanning...
I2C device found at address 0x44  !
I2C device found at address 0x70  !
done

Selecting bus #1. Scanning...
I2C device found at address 0x70  !
done

Selecting bus #2. Scanning...
I2C device found at address 0x70  !
done

Selecting bus #3. Scanning...
I2C device found at address 0x70  !
done

Selecting bus #4. Scanning...
I2C device found at address 0x70  !
done

Selecting bus #5. Scanning...
I2C device found at address 0x70  !
done

Selecting bus #6. Scanning...
I2C device found at address 0x70  !
done

Selecting bus #7. Scanning...
I2C device found at address 0x70  !
done

The complete code :

#include <Wire.h>
#define NB_SENSORS 4
#define TCAADDR 0x70


void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");

}


void loop()
{
  byte error, address;
  int nDevices;

  
  for (int i = 0; i < 8; ++i)  // Scan all eight I2C busses
  {
    Serial.print( "Selecting bus #");
    Serial.print( i);
    Serial.print( ". ");
    tcaselect(i);

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
  }
}

:confused: I don’t understand why I read only one sensor.

I tested this code :

#include <Wire.h>

#include <SHTSensor.h>

#define TCAADDR 0x70
const byte NBSENSORS = 4;

SHTSensor sht;
// To use a specific sensor instead of probing the bus use this command:
// SHTSensor sht(SHTSensor::SHT3X);

void setup() {
  // put your setup code here, to run once:

  Wire.begin();

  Serial.begin(115200);
  delay(1000); // let serial console settle

  for (byte i = 0; i < NBSENSORS; i++)
  {
    tcaselect(i);     // sélectionne le sht qui va bien

    if (sht.init()) {
      Serial.print("init(): success\n");
    } else {
      Serial.print("init(): failed\n");
    }
    sht.setAccuracy(SHTSensor::SHT_ACCURACY_MEDIUM); // only supported by SHT3x
  }
}

void loop() {

  for (byte i = 0; i < NBSENSORS; i++)
  {
    tcaselect(i);

    Serial.print("SHT: ");
    Serial.println(i);
    if (sht.readSample()) {
      Serial.print("  RH: ");
      Serial.print(sht.getHumidity(), 2);
      Serial.print("\n");
      Serial.print("  T:  ");
      Serial.print(sht.getTemperature(), 2);
      Serial.print("\n");
    } else {
      Serial.print("Error in readSample()\n");
    }
  }

  delay(1000);
}

void tcaselect(uint8_t i) {
  if (i > 7) return;

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

The result :

init(): success
init(): success
init(): success
init(): success
SHT: 0
  RH: 69.52
  T:  22.30
SHT: 1
Error in readSample()
SHT: 2
Error in readSample()
SHT: 3
Error in readSample()

Oh! I know why!
I'm stupid!

I hadn't noticed that on the prototyping board, the lines + and - were separated in the middle.
At the moment, I have read two probes. We just have to find out why the last two are not read.

Yes!

init(): success
init(): success
init(): success
init(): success
SHT: 0
  RH: 63.52
  T:  24.35
SHT: 1
  RH: 63.53
  T:  24.22
SHT: 2
  RH: 63.84
  T:  24.32
SHT: 3
  RH: 62.53
  T:  24.37

Instead of wiring the 3rd and 4th probes to SD2 / SC2 and SD3 / SC3, I had them connected to SD7 / SC7 and SD6 / SC6.

Thank you very much Koepel for your time.

Nice :smiley:

When you want a for-loop for just 4 sensors, and connect them to any of the busses, then you can put those busses in a array.
Suppose the sensors are at bus 0, 1, 6, 7.

const int NBSENSORS = 4;
const int bus[NBSENSORS] = { 0, 1, 6, 7 };

for( int i = 0; i < NBSENSORS; i++)
{
  tcaselect( bus[i] );
  ...

Ok, thank you.
I will try.

EDIT : I changed ... It's much cleaner!
And that will serve me for the future I think. I will send the data to a server via HTTP. I did this (with the help of someone) with DHT22 sensors.