OK, now to code up the example with a TCA9548A multiplexer and three BME280s, all with I2C addresses of 0x77.

Here's the code:

// SPDX-FileCopyrightText: 2022 Carter Nelson for Adafruit Industries
//
// SPDX-License-Identifier: MIT

#include <Adafruit_BME280.h>

#define TCAADDR 0x70

// For each device, create a separate instance.
Adafruit_BME280 bme1;  // BME280 #1
Adafruit_BME280 bme2;  // BME280 #2
Adafruit_BME280 bme3;  // BME280 #3

// Helper function for changing TCA output channel
void tcaselect(uint8_t channel) {
  if (channel > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << channel);
  Wire.endTransmission();  
}

void setup() {
  Serial.begin(9600);
  while(!Serial);
  Serial.println(F("Three BME280 Example"));

  // NOTE!!! VERY IMPORTANT!!!
  // Must call this once manually before first call to tcaselect()
  Wire.begin();
  
  // Before using any BME280, call tcaselect to set the channel.
  tcaselect(0);      // TCA channel for bme1
  bme1.begin();      // use the default address of 0x77

  tcaselect(1);      // TCA channel for bme2
  bme2.begin();      // use the default address of 0x77

  tcaselect(2);      // TCA channel for bme3
  bme3.begin();      // use the default address of 0x77
}


void loop() {
  float pressure1, pressure2, pressure3;

  // Read each device separately
  tcaselect(0);
  pressure1 = bme1.readPressure();
  tcaselect(1);
  pressure2 = bme2.readPressure();
  tcaselect(2);
  pressure3 = bme3.readPressure();

  Serial.println("------------------------------------");
  Serial.print("BME280 #1 Pressure = "); Serial.println(pressure1);
  Serial.print("BME280 #2 Pressure = "); Serial.println(pressure2);
  Serial.print("BME280 #3 Pressure = "); Serial.println(pressure3);

  delay(1000);
}

With that sketch running on the Arduino board, the output in the Serial Monitor will look like this:

Similar to the two BME280s example, a separate instance is created for each sensor:

Adafruit_BME280 bme1;  // BME280 #1
Adafruit_BME280 bme2;  // BME280 #2
Adafruit_BME280 bme3;  // BME280 #3

A helper function is used to make switching TCA9548A channels easy. Note that the code is no different than what was discussed above about setting TCA9548A output channels:

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

While simple, this function is using the Wire bus directly. Therefore, it is very important to remember to call Wire.begin(); before the first call to tcaselect(). It only needs to be called once.

// NOTE!!! VERY IMPORTANT!!!
// Must call this once manually before first call to tcaselect()
Wire.begin();

Also important is noting that tcaselect() must be called each time to set the output channel to the specific BME280. This is done in setup() before calling begin() on each sensor:

tcaselect(0);      // TCA channel for bme1
bme1.begin();      // use the default address of 0x77

tcaselect(1);      // TCA channel for bme2
bme2.begin();      // use the default address of 0x77

tcaselect(2);      // TCA channel for bme3
bme3.begin();      // use the default address of 0x77

And also in the loop() before reading each sensor:

tcaselect(0);
pressure1 = bme1.readPressure();
tcaselect(1);
pressure2 = bme2.readPressure();
tcaselect(2);
pressure3 = bme3.readPressure();

Yes, that is a bit klunky. Code lines to deal with the TCA9548A must be interleaved in with the sensor reading code. Think in terms of "I want to use the sensor on TCA9548A channel X, so first must switch the TCA9548A to channel X." The tcaselect() function is what does that switching.

This guide was first published on May 04, 2022. It was last updated on May 04, 2022.

This page (Arduino) was last updated on May 19, 2022.

Text editor powered by tinymce.