Free shipping for orders above 60 €

How to Connect Multiple Sensors Using an I²C Multiplexer

The I²C communication protocol is great because it requires only two wires to connect your microcontroller to one, two, or multiple sensors. But this only works if each sensor has its own I²C address. Suppose you want to connect four (or more) sensors with the same fixed address. One way would be to use the SPI protocol instead, as I have described in another tutorial.

However, not every sensor or breakout board allows you to use the SPI protocol. So what can you do? Well, just use an I²C multiplexer, like the chip TCA9548A from Texas Instruments (Need a datasheet?). This device is available as a breakout board from Adafruit and you can check their great tutorial using this link: Adafruit TCA9548A 1-to-8 I²C Multiplexer Breakout.

Okay, so this thing has 8 channels, which means I can connect up to 8 sensors to the I²C bus, right? Well, yes, but way more than that! Let’s take a closer look at this device and how to use it!

I²C Multiplexer TCA9548A

This is the TCA9548A Multiplexer. You can connect it to your Arduino just like any other I²C device:

  • VIN Pin. Connect the VIN pin from the board to either 5V or 3.3V output from the Arduino.
  • GND Pin. Connect the GND pin from the board to the GND from the Arduino.
  • SDA Pin. Connect the SDA pin from this board to the SDA line from the Arduino. This would be the A4 pin from the Arduino Uno.
  • SCL Pin. Connect the SCL pin from this board to the SCL line from the Arduino. This corresponds to the A5 pin from the Arduino Uno.

Just as the name implies, the reset pin (RST Pin) is used to reset the multiplexer by connecting it to GND. It is pulled HIGH by default, so you can just leave it as it is. The pins A0A1, and A2 are used in case we need to change the I²C address from the multiplexer. In this example, just leave them unconnected.

The other 16 pins available are connected to the 8 channels from the multiplexer. So pins SD0 and SC0 correspond to the data line (SDA) and a clock line (SCL) from the first I²C bus; pins SD1 and SC1 correspond to the lines from the second I²C bus, and so forth.

Each I²C bus from the multiplexer is independent of the other, and just like the I²C bus from your Arduino, you can connect multiple devices with different I²C addresses to each bus from the multiplexer!

Getting Started!

In this simple tutorial, you will see how to connect and program the multiplexer to four environmental sensors BME280 using the same I²C address (0x77). Take a look at the picture below, this is what we are talking about. We want to connect these four boards to an Arduino Uno using the I²C protocol. In this particular case, all four sensors share the same I²C address (0x77).

Let’s connect them first to each other, then we will bring the Arduino Uno to the picture. First, connect all GND pins from all boards to each other (blue wires). Since all boards run on either 5V or 3.3V, we can use either to power all boards. So let’s connect 5V to all boards using the red wires.

Now we will connect the first sensor to the first I²C bus from the multiplexer. For that, connect the SDI pin from the sensor to the SD0 from the multiplexer. Now connect the SCK from the sensor to the SC0 from the multiplexer. 

Just repeat the same to all sensors, connecting each one to a different I²C bus from the multiplexer. As you can see, after all that we have four different I²C buses, where the white wires correspond to the clock lines and the grey wires represent the data lines.

Finally, connect the data and clock lines from the Arduino Uno to the multiplexer. In this case, pin A4 from the Arduino goes to the SDA pin from the multiplexer, while pin A5 from the Arduino connects to pin SCL from the multiplexer. As mentioned before, we are using 5V to power all boards. So the 5V pin from the Arduino goes to the VIN pin from the multiplexer, as well as the VCC pins from each board (red wires). And of course, connect all GND pins (blue wires).

The Code

The sensors and the multiplexer are now all happily connected to an Arduino Uno. So let’s start programming! The multiplexer TCA9548A does not require any library, but the BME280 sensor does. If you haven’t done it already, go ahead and download it now from the link below. If you want to connect the multiplexer to another sensor, just ignore this step.

You can now download the Arduino sketch I have written for this example from the next link. But don’t worry, we will go through the code step by step.

How many sensors do you want?

At the very beginning of our sketch, we include the Wire library to use the I²C protocol and the BlueDot BME280 library. The next step is very important. For every sensor we want to use, we need to create a different instance. In this case, we are connecting four BME280 sensors, so we create four different instances (bme280_0bme280_1bme280_2, and bme280_3). The importance of these instances will be clear below.

  #include <Wire.h>
#include "BlueDot_BME280.h" BlueDot_BME280 bme280_0;
BlueDot_BME280 bme280_1;
BlueDot_BME280 bme280_2;
BlueDot_BME280 bme280_3;

Now we define the I²C address for the multiplexer using the variable TCAADDR. If the pins A0A1, and A2 from the multiplexer board are left unconnected, then we are using the 0x70 address. Your Arduino will be seeing only this address on the I²C bus. Following that, we create the function tcaselect for the multiplexer. Through this function, we can tell the multiplexer to toggle between its eight channels and use the I²C protocol to communicate to any device connected to it. So it first communicates through pins SD0 and SC0, then through pins SD1 and SC1, all the way up to pins SD7 and SC7.

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

 

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

After starting the serial communication (at a baud rate of 9600, but you can go faster if you want), and enabling the I²C protocol through the Wire.begin() function, we initialize the first BME280 sensor. Then we tell the multiplexer to connect to the sensor on pins SD0 and SC0, using the function tcaselect(0). After that, for every variable and every function we use the instance related to the first sensor (bme280_0). We are initializing the first sensor with this configuration.

//*************INITIALIZING FIRST SENSOR*******************************
tcaselect(0);
bme280_0.parameter.communication = 0;
bme280_0.parameter.I2CAddress = 0x77; //Choose I2C Address
bme280_0.parameter.sensorMode = 0b11; //Choose sensor mode
bme280_0.parameter.IIRfilter = 0b100; //Setup for IIR Filter
bme280_0.parameter.humidOversampling = 0b101; //Setup Humidity Oversampling
bme280_0.parameter.tempOversampling = 0b101; //Setup Temperature Oversampling
bme280_0.parameter.pressOversampling = 0b101; //Setup Pressure Oversampling
if (bme280_0.init() != 0x60)
{ Serial.print(F("BME280 Nr.1 detected?\t")); Serial.println(F("No")); }
else
{ Serial.print(F("BME280 Nr.1 detected?\t")); Serial.println(F("Yes")); }
//**********************************************************************

Now copy and paste!

We now repeat the procedure for the second, third, and fourth sensors. Note that we begin the initialization with the function tcaselect and that each sensor has its instance (bme280_1bme280_2, and bme280_3) and its own set of parameters. That means we can use a different configuration for each sensor.

//*************INITIALIZING SECOND SENSOR*******************************
tcaselect(1);
bme280_1.parameter.communication = 0;
bme280_1.parameter.I2CAddress = 0x77; //Choose I2C Address
bme280_1.parameter.sensorMode = 0b11; //Choose sensor mode
bme280_1.parameter.IIRfilter = 0b100; //Setup for IIR Filter
bme280_1.parameter.humidOversampling = 0b101; //Setup Humidity Oversampling
bme280_1.parameter.tempOversampling = 0b101; //Setup Temperature Oversampling
bme280_1.parameter.pressOversampling = 0b101; //Setup Pressure Oversampling
if (bme280_1.init() != 0x60)
{ Serial.print(F("BME280 Nr.2 detected?\t")); Serial.println(F("No")); }
else
{ Serial.print(F("BME280 Nr.2 detected?\t")); Serial.println(F("Yes")); }
//**********************************************************************
//*************INITIALIZING THIRD SENSOR*******************************
tcaselect(2);
bme280_2.parameter.communication = 0;
bme280_2.parameter.I2CAddress = 0x77; //Choose I2C Address
bme280_2.parameter.sensorMode = 0b11; //Choose sensor mode
bme280_2.parameter.IIRfilter = 0b100; //Setup for IIR Filter
bme280_2.parameter.humidOversampling = 0b101; //Setup Humidity Oversampling
bme280_2.parameter.tempOversampling = 0b101; //Setup Temperature Oversampling
bme280_2.parameter.pressOversampling = 0b101; //Setup Pressure Oversampling
if (bme280_2.init() != 0x60)
{ Serial.print(F("BME280 Nr.3 detected?\t")); Serial.println(F("No")); }
else
{ Serial.print(F("BME280 Nr.3 detected?\t")); Serial.println(F("Yes")); }
//**********************************************************************
//*************INITIALIZING FOURTH SENSOR*******************************
tcaselect(3);
bme280_3.parameter.communication = 0;
bme280_3.parameter.I2CAddress = 0x77; //Choose I2C Address
bme280_3.parameter.sensorMode = 0b11; //Choose sensor mode
bme280_3.parameter.IIRfilter = 0b100; //Setup for IIR Filter
bme280_3.parameter.humidOversampling = 0b101; //Setup Humidity Oversampling
bme280_3.parameter.tempOversampling = 0b101; //Setup Temperature Oversampling
bme280_3.parameter.pressOversampling = 0b101; //Setup Pressure Oversampling
if (bme280_3.init() != 0x60)
{ Serial.print(F("BME280 Nr.4 detected?\t")); Serial.println(F("No")); }
else
{ Serial.print(F("BME280 Nr.4 detected?\t")); Serial.println(F("Yes")); }
//**********************************************************************

After initializing the sensors, we go to the loop function and start the measurements. First of all, we start with the tcaselect(0) function. We are using three functions to read values for temperature (function readTempC), humidity (readHumidity), and pressure (readPressure). Just as before, use the instance bme280_0 before each function to address the first sensor.

tcaselect(0);
Serial.print(F("Duration1[s]=\t"));
Serial.print(float(millis())/1000);
Serial.print("\t");
Serial.print(F("Temperature1[C]=\t"));
Serial.print(bme280_0.readTempC());
Serial.print(F("Humidity1[%]=\t"));
Serial.print(bme280_0.readHumidity());
Serial.print("\t");
Serial.print(F("Pressure1[hPa]=\t"));
Serial.print(bme280_0.readPressure());
Serial.print("\t");
Serial.println();

Repeating the same for the remaining three sensors, we get the rest of the code. Now upload the code and open the serial monitor at 9600 baud speed to get the temperature, humidity, and pressure of all four sensors.

Let's Run the Code!

Leave a Reply

Your email address will not be published. Required fields are marked *