I am trying to measure the pressure in a wind tunnel using a multiplexer TCA9548A I2C Multiplexer and multiple pressure sensors D6F-PH5050AD3 & D6F-PH0025AD1. For the beginning I want to measure with 2 sensors (1 of each type). As soon as I get reasonable results, I want to extend this to multiple sensors. I soldered the pins to the multiplexer and ran a scanner sketch which finds the two sensors. So the connection should work. There is no real reason, why I used Port 2 and 3 for this example.
Now I have the problem that I am a beginner and do not get along with the programming. I use the code below for the measurement with the individual sensors. I have found examples of the code with multiplexer and other sensors, but can not transfer them to my case. Can someone help me? I am using an Arduino ATMEGA btw. But I could also switch to an Uno if that does make a difference.
#include "Wire.h"
#define addrs 0x6C // I2C bus address
int P;
int I;
float T;
int initialize(int i2c_addr)
{
//INITIALIZATION AFTER POWER UP
Wire.beginTransmission(i2c_addr);
Wire.write(0x0B);
Wire.write(0x00);
int x = Wire.endTransmission();
return x;
}
int pressure(int i2c_addr)
{
//MCU MODE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0); // reg 0 - address register high byte
// Wire.write(0x51); // reg 1 - address register low byte
Wire.write(0x40); // reg 1 - address register low byte
Wire.write(0x18); // reg 2 - serial control register - indicate # bytes among others (page 7 bottom)
Wire.write(0x06); // reg 3 - value to be written to SENS control register
int x = Wire.endTransmission();
delay(33);
//WRITE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0);
Wire.write(0x51);
Wire.write(0x2C);
x = Wire.endTransmission();
//READ
Wire.beginTransmission(i2c_addr);
Wire.write(0x07);
x = Wire.endTransmission();
Wire.requestFrom(i2c_addr, 2);
byte hibyte = Wire.read();
byte lobyte = Wire.read();
long raw = word( hibyte, lobyte);
//Serial.print("raw pressure:\t ");
//Serial.println(raw);
// D6F-PH5050AD3 ==> rangeMode=500 ==> int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode
// D6F-PH0505AD3 ==> rangeMode=50 ==> int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode
// D6F-PH0025AD1 ==> rangeMode=250 ==> int rd_pressure=(raw - 1024) * rangeMode / 60000L
int rangeMode = 50;
int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode;
return rd_pressure;
}
float temperature(int i2c_addr)
{
//MCU MODE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0); // reg 0 - address register high byte
// Wire.write(0x51); // reg 1 - address register low byte
Wire.write(0x40); // reg 1 - address register low byte
Wire.write(0x18); // reg 2 - serial control register - indicate # bytes among others (page 7 bottom)
Wire.write(0x06); // reg 3 - value to be written to SENS control register
int x = Wire.endTransmission();
delay(33);
//WRITE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0);
Wire.write(0x61);
Wire.write(0x2C);
x = Wire.endTransmission();
//READ
Wire.beginTransmission(i2c_addr);
Wire.write(0x07);
x = Wire.endTransmission();
Wire.requestFrom(i2c_addr, 2);
byte hibyte = Wire.read();
byte lobyte = Wire.read();
long raw = word( hibyte, lobyte);
//Serial.print("raw temperature:\t ");
//Serial.println(raw);
int temp = round((float)(raw - 10214) / 3.739); // this is the temperature multiplied by 10...
return (temp/10.0); // ...and the function returs the float temperature with 0.1°C resolution
}
void setup()
{ // Open serial communications
Wire.begin();
Serial.begin(9600);
I=initialize (addrs); // start wire connection
}
void loop()
{
P=pressure(addrs);
Serial.print("pressure:\t ");
Serial.println(P);
T=temperature(addrs);
Serial.print("temperature:\t ");
Serial.println(T);
delay(30000); //delay for 30 seconds
}
The example you posted seems to not use a multiplexer. Can you post your attempt to use the multiplexer code? It's more relevant to your need.
The scanning sketch you ran to produce the debug listing above must interface the multiplexer, are there no example sketches with that software to actually access devices via the multiplexer?
Basically, I am wondering whether you have fully explored the resources that you have already downloaded...
The Arduino Mega 2560 is a 5V Arduino board with a 5V I2C bus.
The pressure sensor is a 3.3V sensor with a 3.3V I2C bus.
The TCA9548A can translate those levels when powered with 3.3V. Do you have that ?
Do you use the TCA9548A chip, or a module ?
What kind of wires or cable do you use for the I2C bus ? How long are they ?
Do you have pullup resistors on the (sub) I2C bus that is connected to the sensor ? What value ?
In the datasheet is a repeated start when reading data. Your sketch does not have that.
I'm using 20cm jumper cables and 2kOhm resistors. I can adjust this setup when I do the measurements and I can compare the results.
But to perform measurements at all I need the right programming. And I read everything I have as data, but since I'm a beginner and I really dont know how to start programming this, I need your help.
I tried around with other sketches I found online, but I can't transfer them to my sensors. So it is unnecessary to post my attempts here, as they are probably pretty garbage.
The resistors are too low in value. I prefer 10k (or perhaps 4k7) and none on the Arduino Mega side (it has already 10k onboard pullup resistors).
I'm not 100% sure how the TCA9548A behaves when it opens a I2C channel. If you can not find 10k resistors, then you can measure the maximum sink current of the I2C bus.
In your first setup, the onboard 10k pullup resistors leak current from the 5V into the sensor. That means that your sensor is no longer reliable and can be damaged. Do you know which one you used for that test ?
My suggestion: Start with one sensor, but keep the TCA9548A as level translator. Open the first I2C channel, and make a sketch or find a library for your sensors.
The first part of your sketch could look like this:
// Library: https://github.com/bitixel/Omron_D6FPH
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor;
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin( 115200); // or 9600, set the Serial Monitor to the same value.
Serial.println( "The sketch has started");
Wire.begin(); // Start the I2C bus
tcaselect( 0); // select the first I2C bus
// From now on, the first sensor is connected to the I2C bus.
mySensor.begin(MODEL_5050AD3);
}
Show your sketch and tell what it does.
Please also tell what you did about those 2k2 pullup resistors.
I don't know why no other code than the one I posted worked for me before, but the one from the library does. With the multiplexer and 1 sensor connected to it. The Code I used now looks like this:
#include <Arduino.h>
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor;
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600); // or 9600, set the Serial Monitor to the same value.
Serial.println( "The sketch has started");
Wire.begin(); // Start the I2C bus
// From now on, the first sensor is connected to the I2C bus.
mySensor.begin(MODEL_5050AD3);
}
void loop() {
tcaselect(1);
float pressure = mySensor.getPressure();
if(isnan(pressure)){
Serial.println("Error: Could not read pressure data");
}else{
Serial.print("Differential Pressure: ");
Serial.println(pressure);
}
float temperature = mySensor.getTemperature();
if(isnan(temperature)){
Serial.println("Error: Could not read temperature data");
}else{
Serial.print("Temperature C: ");
Serial.println(temperature);
}
delay(500);
}
Then I tried to use it with 2 sensors. I thought I could just address the second sensor with tcaselect (2). The second Sensor is of course connected to the tca 2 pins. Is it because I only have 1 sensor described with the "mySensor"?
#include <Arduino.h>
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor;
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600);
Serial.println( "The sketch has started");
Wire.begin();
}
void loop()
{
tcaselect(1);
float pressure = mySensor.getPressure();
if(isnan(pressure)){
Serial.println("Error: Could not read pressure data");
}else{
Serial.print("Differential Pressure1: ");
Serial.println(pressure);
}
float temperature = mySensor.getTemperature();
if(isnan(temperature)){
Serial.println("Error: Could not read temperature data");
}else{
Serial.print("Temperature C1: ");
Serial.println(temperature);
}
Serial.println(temperature);
tcaselect(2);
if(isnan(pressure)){
Serial.println("Error: Could not read pressure data");
}else{
Serial.print("Differential Pressure2: ");
Serial.println(pressure);
}
if(isnan(temperature)){
Serial.println("Error: Could not read temperature data");
}else{
Serial.print("Temperature C2: ");
Serial.println(temperature);
}
Serial.println(temperature);
delay(1500);
}
With this code I get two values, but always from the same sensor, instead of the different values of the sensors.
Then it's important to say, that I used 1 sensor of the type D6FPH5050AD3 and and of the type D6FPH0025AD1, which would not matter, because I can still see if the code would basically work and I will measure later with several sensors of the same type.
In my setup() example, I have a Wire.begin() to start the I2C bus, then a tcaselect() to select the first (sub) I2C bus, then a mySensor.begin() that starts the sensor at the first (sub) I2C bus.
In neither of your examples you have that.
I'm sorry. Somehow a few lines got lost while I was trying different ways. The first code should look like this. The two lines tcaselect() and mySensor.begin should be in both setups of course. But how do I start the second I2C Bus then? where do I have to use the tcaselect(2)?
#include <Arduino.h>
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor;
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600);
Serial.println( "The sketch has started");
Wire.begin();
tcaselect(1);
mySensor.begin(MODEL_5050AD3);
}
void loop() {
float pressure = mySensor.getPressure();
if(isnan(pressure)){
Serial.println("Error: Could not read pressure data");
}else{
Serial.print("Differential Pressure: ");
Serial.println(pressure);
}
float temperature = mySensor.getTemperature();
if(isnan(temperature)){
Serial.println("Error: Could not read temperature data");
}else{
Serial.print("Temperature C: ");
Serial.println(temperature);
}
delay(500);
}
What was the result ? Did you get the pressure and temperature ?
Suppose you have 8 sensors, then you need 8 objects, 8 calls to .begin (each with its own I2C bus selected), 8 calls for the pressure and temperature (each with its own I2C bus selected).
8 objects:
Omron_D6FPH mySensor[8];
8 calls to begin
for( int i=0; i<8; i++)
{
tcaselect(i);
mySensor[i].begin(MODEL_5050AD3);
}
8 calls for the pressure and temperature
for( int i=0; i<8; i++)
{
tcaselect(i);
float pressure = mySensor[i].getPressure();
float temperature = mySensor[i].getTemperature();
..
}
Thank you very much! This is the code that works for me:
#include <Arduino.h>
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor[2];
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
if (i > 1) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600);
Serial.println( "The sketch has started");
Wire.begin();
for(int i=0; i<2; i++)
{
tcaselect(0);
mySensor[0].begin(MODEL_0025AD1);
}
for(int i=1; i<2; i++)
{
tcaselect(1);
mySensor[1].begin(MODEL_5050AD3);
}
}
void loop()
{
for(int i=0; i<2; i++)
tcaselect(0);
float pressure = mySensor[0].getPressure();
if(isnan(pressure)){
Serial.println("Error: Could not read pressure data");
}else{
Serial.print("Differential Pressure 0: ");
Serial.println(pressure);
}
float temperature = mySensor[0].getTemperature();
if(isnan(temperature)){
Serial.println("Error: Could not read temperature data");
}else{
Serial.print("Temperature 0: ");
Serial.println(temperature);
}
Serial.println(temperature);
for(int i=1; i<2; i++)
{
tcaselect(1);
float pressure = mySensor[1].getPressure();
if(isnan(pressure)){
Serial.println("Error: Could not read pressure data");
}else{
Serial.print("Differential Pressure 1: ");
Serial.println(pressure);
}
float temperature = mySensor[1].getTemperature();
if(isnan(temperature)){
Serial.println("Error: Could not read temperature data");
}else{
Serial.print("Temperature 1: ");
Serial.println(temperature);
}
delay(2000);
}}
This is the result it shows:
Since I only have these 2 sensors I will order more. Then I will do some test measurements with 8 sensors and try to use a second multiplexer with up to 12 sensors in total.
Could you make the text of the code look better ? Put every space, every indent, every comma at the right place.
When using an array, a variable is used as a index.
int myData[8];
for( index = 0; index < 8; index++)
{
int value = myData[index];
}
If one sensor is a "D1" type and the other sensor a "D3" type, then you can solve that inside the for-loop. You can put that information in an array as well
After a long break I continue to worki on this project again.
I optimized the code and now it looks like this:
#include <Arduino.h>
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor[8];
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
if (i > 7) return;
Wire.beginTransmission(TCAADDR);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600);
Serial.println( "The sketch has started");
Wire.begin();
for (int i = 0; i < 8; i++)
{
tcaselect(i);
mySensor[i].begin(MODEL_5050AD3);
}
}
void loop()
{
for (int i = 0; i < 8; i++) // Loop für alle Sensoren
{
tcaselect(i);
float pressure = mySensor[i].getPressure();
if (isnan(pressure)) {
Serial.println("Error: Could not read pressure data");
} else {
Serial.print("Differential Pressure : sensor ");
Serial.println(i);
Serial.println(pressure);
}
float temperature = mySensor[i].getTemperature();
if (isnan(temperature)) {
Serial.println("Error: Could not read temperature data");
} else {
Serial.print("Temperature : sensor ");
Serial.println(i);
Serial.println(temperature);
}
}
delay(2000);
}
Now I want to use more than 8 sensors. For this I have another multiplexer and one more sensor connected on the SD0 and SCL0. So I have 9 sensors in total to test the new code.
In this forum I found this section of a code that should allow me to use another multiplexer:
So the full new code with this section looks like this:
#include <Arduino.h>
#include <Wire.h>
#include <Omron_D6FPH.h>
Omron_D6FPH mySensor[9];
#define TCAADDR 0x70
void tcaselect(uint8_t i) {
byte address = TCAADDR;
static byte previousAddress = 0x99;
while (i > 7)
{i -= 8; address++;
}
if (address != previousAddress) {
if (previousAddress != 0x99) {
Wire.beginTransmission(previousAddress);
Wire.write(0);
Wire.endTransmission();
}
previousAddress = address;
}
Wire.beginTransmission(address);
Wire.write(1 << i);
Wire.endTransmission();
}
void setup()
{
Serial.begin(9600);
Serial.println( "The sketch has started");
Wire.begin();
for (int i = 0; i < 9; i++)
{
tcaselect(i);
mySensor[i].begin(MODEL_5050AD3);
}
}
void loop()
{
for (int i = 0; i < 9; i++) // Loop für alle Sensoren
{
tcaselect(i);
float pressure = mySensor[i].getPressure();
if (isnan(pressure)) {
Serial.println("Error: Could not read pressure data");
} else {
Serial.print("Differential Pressure : sensor ");
Serial.println(i);
Serial.println(pressure);
}
float temperature = mySensor[i].getTemperature();
if (isnan(temperature)) {
Serial.println("Error: Could not read temperature data");
} else {
Serial.print("Temperature : sensor ");
Serial.println(i);
Serial.println(temperature);
}
}
delay(2000);
}
With this code I tried around. I changed the "previous adress" and the if term to from 0x99 to 0x70, and now it reads out all of the 9 sensors. But my problem is, that the value of sensor 8 is also showed for sensor 9. I think I just didnt understand this part. Don't I have to "define" the second multiplexer and it's adress (0x71)?
If I remember it correctly, then the multiplexer can be turned off by writing zero. I see now that you have that already.
You need to write a function that selects one of the multiplexers and writes zero to the other. I don't understand what the 0x99 is doing.
is channel between 0 up to 7 ?
{
disable second multiplexer at 0x71
select channel from first multiplexer at 0x70
}
else
{
convert channel 8...15 to 0...7
disable the first multiplexer at 0x70
select channel from second multiplexer at 0x71
}
To be honest since I'm a beginner it is not easy for me to "set both multiplexers correct". That's why I'm asking you. You have already helped me a lot. Thank you for that! But I'm still struggling with the two multiplexers.
What I wrote in Reply #13, but then in code
I would like to change the name of the function, because it does no longer select the channel of a single multiplexer.
I wrote this without thinking, it might be wrong:
void SuperSelect( int channel)
{
if( channel >= 0 && channel <= 7)
{
// Disable the second multiplexer.
Wire.beginTransmission(0x71);
Wire.write(0x00);
Wire.endTransmission();
// A channel of the first multiplexer is selected.
Wire.beginTransmission(0x70);
Wire.write(1 << channel);
Wire.endTransmission();
}
else( if channel >=8 && channel <= 15)
{
// Disable the first multiplexer.
Wire.beginTransmission(0x70);
Wire.write(0x00);
Wire.endTransmission();
// A channel of the second multiplexer is selected.
Wire.beginTransmission(0x71);
Wire.write(1 << (channel - 8));
Wire.endTransmission();
}
else
{
Serial.println( "Wrong channel for multiplexers");
}
}
Maybe you are thinking that sometimes the correct multiplexer is already enabled and the other multiplexer is already disabled, so maybe sometimes the other multiplexer does not have to be disabled again. Those are optimization, that is something for later. This code is the most basic way to select a channel over two multiplexers. It does what you expects that it does. That's all that is needed.
So since this code doesn't work for me either, I'm starting to doubt if the connection is even correct. Here is an example how the whole thing would look like with 2 sensors at the first multiplexer and 1 at the second (just imagine 8 sensors at the first multiplexer). How exactly do you declare one microcontoller as 0X70 and the other as 0x71? Or is it because of the order. And does the connection of SDC and SCL work as seen in the black circle? Or am I just dumb and using a wrong wiring the whole time? (I thought I've seen this wiring online and and considered it right.
That is what you should use.
Have you given a link to where you bought the module ? Did you follow the tutorial that came with it ? Do you know if your module has pullup or pulldown resistors for A0, A1 and A2 ?
In your picture, the SDA is shortcut to SCL at the left multiplexer. The multiplexer on the right has SD0 shortcut to A1. Neither multiplexers has the A0,A1,A2 properly set.