I am Ajay Singh, I just started working with Arduino. What I am trying to do is read from multiple flow sensors at the same time. The Sensirion SFM3003 sensors have the same address (0x28). So I am using Adafruit multiplexer PCA9548A which has an address (0x70) and Arduino uno board.
I run the i2c scanner code and it says, "I2C device found at address 0x70 ".
Then I tried running TCA9548_I2C_scanner, and I got the following result:
"TCA Port #0
Found I2C 0x0
Found I2C 0x28
TCA Port #1
Found I2C 0x0
Found I2C 0x28
TCA Port #2
Found I2C 0x0
Found I2C 0x28
TCA Port #3
TCA Port #4
TCA Port #5
TCA Port #6
TCA Port #7".
I don't understand why it says "Found I2C 0x0" although the address should be 0x70 as given by I2C_scanner.
When I tried using the code (posted at the end of the message) using just one sensor, I got the right values of flow and temperature. But when I am using more than one sensor, I get some stage value of around -25000, although the temperature readings are still right.
Below is the code I am using:
#include <Arduino.h>
#include <Wire.h>
#include <SensirionI2CSfmSf06.h>
#define TCAADDR 0x70
/* Assign a unique ID to the sensors at the same time */
SensirionI2CSfmSf06 sfmSf06_1;
SensirionI2CSfmSf06 sfmSf06_2;
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(0x70);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(115200);
while (!Serial) {
Serial.println("Flow Sensor Test"); Serial.println("");
}
Wire.begin(); // must call this once manually before first call to tcaselect()
/* Initialise the 1st sensor */
tcaselect(1);
sfmSf06_1.begin(Wire, 0x28); // use the default address of 0x28
/* Initialise the 2nd sensor */
tcaselect(2);
sfmSf06_2.begin(Wire, 0x28);
sfmSf06_1.startO2ContinuousMeasurement();
Serial.print("flow_1");
Serial.print("\t");
Serial.print("temperature_1");
sfmSf06_2.startO2ContinuousMeasurement();
Serial.print("\t");
Serial.print("flow_2");
Serial.print("\t");
Serial.println("temperature_2");
}
void loop()
{
/* Get a new sensor event */
// sensors_event_t event;
uint16_t error1;
float flow_1 = 0;
float temperature_1 = 0;
uint16_t status_1 = 0;
tcaselect(1);
// Read Measurement
error1 = sfmSf06_1.readMeasurementData(flow_1, temperature_1, status_1);
delay(1000);
if (!error1) {
Serial.print(flow_1);
Serial.print("\t");
Serial.print(temperature_1);
Serial.print("\t");
}
uint16_t error2;
float flow_2 = 0;
float temperature_2 = 0;
uint16_t status_2 = 0;
tcaselect(2);
// Read Measurement
error2 = sfmSf06_2.readMeasurementData(flow_2, temperature_2, status_2);
//delay(1000);
if (!error2) {
Serial.print(flow_2);
Serial.print("\t");
Serial.println(temperature_2);
}
delay(500);
}
I2C address 0x00 is the "general call" address.
A Master can use that to send data to all I2C devices at once. However, it is mostly used to change specific settings for a single device.
Search the datasheet for "general call". The SFM3003 sensor uses it for a soft reset.
Thank you very much for responding. I am using the same library that you mentioned.
I changed the code to be as follows in the void loop, please correct me if I am wrong. But still, I am getting the same strange outputs of -24500 and something like that. I would appreciate further input from you. Thanks!
Could you try that example. Set the I2C multiplexer just once in setup() to one sensor.
Set the I2C multiplexer before sfmSf06.begin(Wire, ADDR_SFM3119);.
The sketch gives an identifier and serial number, so you can check if that is working.
If that works, then set the I2C multiplexer to the other sensor.
If that does not work, then try the sketch without I2C multiplexer.
Then try both.
If you have all kinds of trouble, then there are many things to check. Here are a few:
check the voltage levels (use a better USB cable).
Breadboards have bad contacts and jumper wires can be broken.
Which Arduino board do you use ? With the latest updates of the Arduino IDE ?
There should be pullup resistors after the I2C multiplexer for each (sub) I2C bus that is used.
Hi Thanks again! I am sharing the full code again.
Things to note:
I am using Arduino UNO, IDE is updated,
I have tried different wires,
I believe PCS9548A has inbuilt pullup resistors, but I have even tried using pull-up resistors of 5K with SCN and SDA to 3.3 volts and even to 5 volts.
#include <Arduino.h>
#include <Wire.h>
#include <SensirionI2CSfmSf06.h>
#define TCAADDR 0x70
/* Assign a unique ID to the sensors at the same time */
SensirionI2CSfmSf06 sfmSf06_1;
SensirionI2CSfmSf06 sfmSf06_2;
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(115200);
while (!Serial) {
Serial.println("Flow Sensor Test"); Serial.println("");
}
Wire.begin(); // must call this once manually before first call to tcaselect()
/* Initialise the 1st sensor */
tcaselect(1);
sfmSf06_1.begin(Wire, 0x28); // use the default address of 0x28
/* Initialise the 2nd sensor */
tcaselect(2);
sfmSf06_2.begin(Wire, 0x28);
sfmSf06_1.startO2ContinuousMeasurement();
Serial.print("flow_1");
Serial.print("\t");
Serial.print("temperature_1");
sfmSf06_2.startO2ContinuousMeasurement();
Serial.print("\t");
Serial.print("flow_2");
Serial.print("\t");
Serial.println("temperature_2");
}
void loop()
{
/* Get a new sensor event */
// sensors_event_t event;
uint16_t error1;
float flow_1 = 0;
float temperature_1 = 0;
uint16_t status_1 = 0;
tcaselect(1);
// Read Measurement
sfmSf06_1.startO2ContinuousMeasurement();
error1 = sfmSf06_1.readMeasurementData(flow_1, temperature_1, status_1);
delay(1000);
if (!error1) {
Serial.print(flow_1);
Serial.print("\t");
Serial.print(temperature_1);
Serial.print("\t");
}
uint16_t error2;
float flow_2 = 0;
float temperature_2 = 0;
uint16_t status_2 = 0;
tcaselect(2);
// Read Measurement
sfmSf06_2.startO2ContinuousMeasurement();
error2 = sfmSf06_2.readMeasurementData(flow_2, temperature_2, status_2);
//delay(1000);
if (!error2) {
Serial.print(flow_2);
Serial.print("\t");
Serial.println(temperature_2);
}
delay(500);
}
That sketch has the same problem. You forgot to set the I2C multiplexer in two places. You have to set the I2C multiplexer every time that you use a library function that uses the sensor.
The PCA9548A module from Adafruit: https://www.adafruit.com/product/2717
It has pullup resistors on the main I2C bus, but not on the eight (sub) I2C buses. There must be pullup resistors there.
The example that I referred to uses the library functions in a different way. I assume that the example is working. To get out of the problems, you can start with the example and add the code for the I2C multiplexer.
Thank you very much for your help. I can get the right readings now. I used the pullup resistors with individual output ports and made the changes in the code as you suggested.
There is still one problem, I am not getting the right readings at the very first time when running the code. I have to shift the V_logic pin on PCA9548A from 3v to v+ or from v+ to 3v to get the right values.
I would really appreciate it if you could provide some related solution for this.
The code I am using now is:
#include <Arduino.h>
#include <Wire.h>
#include <SensirionI2CSfmSf06.h>
#define TCAADDR 0x70 // TCA9548A address is 0x70
/* create an object for each of the sensors */
SensirionI2CSfmSf06 sfmSf06_1;
SensirionI2CSfmSf06 sfmSf06_2;
/* to select a specific I2C bus to read/write data, you just need to
send a single byte to the multiplexer with the desired output port number (0 to 7)*/
void tcaselect(uint8_t i) { // i stands for bus
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i); // send byte to select bus
Wire.endTransmission();
}
void setup()
{
Serial.begin(115200);
while (!Serial) {
Serial.println("Flow Sensor Test"); Serial.println("");
}
// Start I2C communication with the Multiplexer
Wire.begin(); // must call this once manually before first call to tcaselect()
/* Initialise the 1st sensor by calling function and pass as an argument the port bus number to control before sending the I2C commands*/
tcaselect(1);
sfmSf06_1.begin(Wire, 0x28); // use the default address of 0x28
sfmSf06_1.startO2ContinuousMeasurement();
Serial.print("flow_1");
Serial.print("\t");
Serial.print("temperature_1");
/* Initialise the 2nd sensor */
tcaselect(2);
sfmSf06_2.begin(Wire, 0x28);
sfmSf06_2.startO2ContinuousMeasurement();
Serial.print("\t");
Serial.print("flow_2");
Serial.print("\t");
Serial.println("temperature_2");
}
void loop()
{
/* Get a new sensor event */
// sensors_event_t event;
uint16_t error1;
float flow_1 = 0;
float temperature_1 = 0;
uint16_t status_1 = 0;
tcaselect(1); // set the mux to channel 2
sfmSf06_1.startO2ContinuousMeasurement(); // Read Measurement
error1 = sfmSf06_1.readMeasurementData(flow_1, temperature_1, status_1);
delay(1000);
if (!error1) {
Serial.print(flow_1);
Serial.print("\t");
Serial.print(temperature_1);
Serial.print("\t");
}
uint16_t error2;
float flow_2 = 0;
float temperature_2 = 0;
uint16_t status_2 = 0;
tcaselect(2); // set the mux to channel 3
sfmSf06_2.startO2ContinuousMeasurement(); // Read Measurement
error2 = sfmSf06_2.readMeasurementData(flow_2, temperature_2, status_2);
//delay(1000);
if (!error2) {
Serial.print(flow_2);
Serial.print("\t");
Serial.println(temperature_2);
}
delay(500);
}
You could try the example that comes with the library, to see if it has that as well.
That example differs from you sketch.
For example the .startO2ContinuousMeasurement() can be set once in setup(), and after that the data can be retrieved every second. Since you have that already in setup(), you can remove those from the loop().
You have a delay(1000); and a delay(500); in the loop(). You can combine those with a single delay at the end of the loop() function.
Some sensors have an internal buffer and give the previous data. The first data it gives can be thrown away. I don't know if that is the case with this sensor, but it is not weird.
I don't understand what you do with the V_logic pin. Will that reset the interface to the Arduino board ? Perhaps you can send a reset command via I2C.