I have just started to use the TCA9548 i2c multiplexer from AdaFruit as I need to read more than 1 SFM3300 flow sensor and it's not possible to change the address of the sensors. I managed to get this sort of "working" pretty quick but almost every other sensor reading was wrong, more specifically the flow variable called "flow4" in my code was often reading to the serial terminal as "433" when every correct reading was much higher, what's interesting is that "4" is the multiplexer register that I set just before reading into "flow4" and "33" is what the sensor often reads as it's 0 reading, so it's almost like the call to the multiplexer channel is interfering with the first new sensor reading... Anyway I solved this problem by discarding the first reading of each flow sensor but I would be grateful if somebody could show me a better way of solving this problem as I don't really understand why this problem exists as various example codes that I have found have not had to discard any readings. My working code is below.
// Code to test the TCA9548 readings 2 SFM3300 flow sensors over i2c
#include <Wire.h>
#define sfm3300i2c 0x40 // #include <Adafruit_Sensor.h>
#define TCAADDR 0x70 // address of i2c multiplexer
#define flowSensorMultiplexPin4 4 // i2c pin of multiplexer
#define flowSensorMultiplexPin6 6 // i2c pin of multiplexer
void setupFlowSensor() {
Wire.beginTransmission(sfm3300i2c);
Wire.write(0x10); // start continuous measurement
Wire.write(0x00); // command 0x1000
Wire.endTransmission();
}
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR); // address the multiplexer
Wire.write(1 << i); // address the right multiplexer address
Wire.endTransmission();
}
// ***** Reads air flow sensor. Output in ml/min *****
long getFlow() {
static unsigned long flowTimer = 0;
static bool firstFlowRead = true;
static float flow = 0; // variabe for flow readings mL/min
if (millis() - flowTimer >= 1 || firstFlowRead) { // reads every milisecond apart from first reading
firstFlowRead = false;
if (2 == Wire.requestFrom(sfm3300i2c, 2)) { // read SLM (Standard Liter per Minute)
uint16_t a = Wire.read(); // only two bytes need to be read
uint8_t b = Wire.read(); // if we don't care about CRC
a = (a << 8) | b;
//float flow = ((float)a - 32768) / 120; // L/min
//flow = ((float)a - 32768) / 120 * 1000; // mL/min
flow = ((float)a - 32768.0) * 8.33333; // same as line above but without division in ml/min
flowTimer = millis();
} else { // use large number to flag incorrect readings
flow = 500000; // faulty sensor reading
}
}
return long(flow); // in mL/min
}
void setup(void) {
Wire.begin();
Serial.begin(115200);
tcaselect(flowSensorMultiplexPin4);
setupFlowSensor();
tcaselect(flowSensorMultiplexPin6);
setupFlowSensor();
}
void loop(void) {
static long flow6 = 0;
static long flow4 = 0;
for (int i = 0; i <= 2; i++) {
tcaselect(flowSensorMultiplexPin6);
flow6 = getFlow();
}
for (int i = 0; i <= 2; i++) {
tcaselect(flowSensorMultiplexPin4);
flow4 = getFlow();
}
Serial.print(flow4);
Serial.print(",");
Serial.print(flow6);
Serial.print(",");
Serial.println(2000);
}