You have a microcontroller and two identical sensors, meaning that they have the same I2C address. Without a multiplexer or the possibility to configure the I2C address of the sensor you cannot attach them to the same I2C bus. However, the STM32 Nucleo 64 F401RE Board offers several separate I2C buses allowing to connect each sensor to its individual I2C bus to avoid the address conflict.
The IngredientsIn this example we use an STM32 Nucleo 64 F401RE Board, which supports multiple I2C buses. As sensors we have two Sensirion SCD41 CO2 sensor evaluation boards. You can use any two sensors, whether they are the same product or different sensors with the same I2C address. The evaluation boards are convenient, as we can connect them with the cables included in the Evaluation Kit, allowing us to wire everything without soldering on a breadboard.
General working principleThe two SCD41 sensors we want to connect have an I2C address of 0x62, which cannot be changed. Therefore, to communicate with both sensors from the microcontroller, we will use a separate I2C bus for each sensor. Each I2C bus requires one pin for the SDA line and one for the SCL line. On the software side we need to initialize a "TwoWire" instance per I2C bus and configure the pins. "TwoWire" is part of the standard Wire library. As a final step, we will create two instances of our sensor driver class and initialize one with the standard I2C bus and the other with the custom I2C bus.
WiringThe STM32 Nucleo 64 F401RE board has predefined I2C pins. We connect to the Arduino Pin Header of the board and use the predefined pins for I2C1 and I2C2.
More info about the STM32 Nucleo 64 F401RE Board can be found on st.com.
Pull-up resistors
Having pull-up resistors in place on each pair of I2C lines, namely data (SDA) and clock (SCL) lines, is important for a good signal quality and robust communication. You can read more about it on I2C Pull-Up Resistors Intro.
The Nucleo board nor the development kit board has pull-up resistors built in. Thus, we need to wire a resistor into each of the I2C communication lines. Four 8.26kOhm resistors were used in this example and the wiring was done using a breadboard.
Wiring diagram
Names R.1 to R.4 stand for resistors with a value of 8.26kOhm.
- SEK-SCD41 A Pin 1 to R.1 (SCL, yellow)
- R.1 to Nucleo Arduino Connector Pin 15 (SCL, yellow)
- R.1 to Nucleo Arduino Connector 3V3
- SEK-SCD41 A Pin 2 to Nucleo Arduino Connector GND
- SEK-SCD41 A Pin 3 to Nucleo Arduino Connector 3V3 (Sensor supply voltage, red cable)
- SEK-SCD41 A Pin 4 to R.2 (SDA, green)
- R.2 to Nucleo Arduino Connector Pin 14 (SDA, green)
- R.2 to Nucleo Arduino Connector 3V3
- SEK-SCD41 B Pin 1 to R.3 (SCL, yellow)
- R.3 to Nucleo Arduino Connector Pin 6 (SCL, yellow)
- R.3 to Nucleo Arduino Connector 3V3
- SEK-SCD41 B Pin 2 to Nucleo Arduino Connector GND (Ground, black cable)
- SEK-SCD41 B Pin 3 to Nucleo 3.3V (Sensor supply voltage, red cable)
- SEK-SCD41 B Pin 4 to R.4 (SDA, green)
- R.4 to Nucleo Arduino Connector Pin 3 (SDA, green)
- R.4 to Nucleo Arduino Connector 3V3
What we have to remember for the configuration in the software later is the pins we used for the I2C buses.
Software setupFirst, you need to include the Wire library:
#include <Wire.h>
For configuring the I2C buses with the correct pins, we need to instantiate two `TwoWire ` instances and pass the pins to be used for the I2C communication.
Their scope should be global, thus the definition is outside `setup()` and `loop()`.
// I2C Bus A on Pins 14 (SDA) / 15 (SCL)
const int sda_A = 14;
const int scl_A = 15;
TwoWire i2cBusA(sda_A, scl_A);
// I2C Bus B on Pins 3 (SDA) / 6 (SCL)
const int sda_B = 3;
const int scl_B = 6;
TwoWire i2cBusB(sda_B, scl_B);
Then, the code sending the commands to the sensors over the I2C Bus needs to know which bus to use for which sensor. Thus, you need to configure the sensors instances accordingly. First, create a driver instance per sensor. Their scope should be global, such that they can be referred to from within `setup()` and `loop()`.
SensirionI2cScd4x sensorA;
SensirionI2cScd4x sensorB;
Then, in the `setup()` function, assign the I2C Buses to the sensors:
sensorA.begin(i2cBusA, SCD41_I2C_ADDR_62);
sensorB.begin(i2cBusB, SCD41_I2C_ADDR_62);
You can now send any I2C command to the sensor, such as initiating the measurement and retrieving values.
sensorA.startMeasurement();
sensorB.startMeasurement();
....
Example sketchYou find a complete example sketch for ESP32 on GitHub arduino-i2c-different-buses-example. Look out for the Nucleo specific example.
Comments
Please log in or sign up to comment.