Multiple BMP180 Pressure sensors, multiplexer, incorrect read value.

Hi

I am working on a project where i need to read three BMP180 pressure sensors and print their individual values in the serial monitor.

Components:

The code and circuit (both attached) are inspired from somewhat similar projects on the internet.

Everything seems to working correctly, except for the readings i get from the sensors(Z1, Z2, Z3):
Z1= 500.11mb Z2= 429.46mb Z3= 574.89mb

If i try to run the example code, provided by sparkfun, a single sensor reads 1019mb.

I can't seem to figure out where my data gets distorted, and why they are not reading a similiar value as they are placed just next to each other. My best guess is that something happens in the multiplexer?

Until now I have made it this far by tweaking forum discussions and tutorials to suit my project, but this issue seems to be a bit to specific, and i am moving beyound the limitation of my capabilities, so please give me some advice.

/Kenneth

SFE_BMP180_edit.ino (1.39 KB)

Hi Kenneth

Have you tried printing the temperature readings, to see if they are also incorrect?

On the SCL signal, you have an external pullup to 3.3V (R1). The quick start guide for the breakout board says it also has pullup resistors, and recommends disabling them if you have more than one device on the bus. It sounds like it will disable for both SCL and SDA, so if you do disable them, retain your external pullups R2 to R4.

On the Arduino side of the mux, you have no external pullup. Maybe it needs one to 3.3V as well.

void out1(){
  digitalWrite(EN, LOW);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);  
}

Taking EN low enables the mux, I believe? It would be cleaner to disable the mux while changing the settings on s0 to s3, since there will be a small time gap between the digitalWrite statements. Probably not causing your errors, though.

void out1(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);  
 digitalWrite(EN, LOW);
}

And in setup(), disable the mux initially.

  pinMode(EN,OUTPUT);
  digitalWrite(EN, HIGH);

Regards

Ray

This is oddly similar to what some other guy was asking recently.

In his case he removed all the pullup resistors on his boards and so had none. In your case you've added resistors that by themselves are too large, especially since the Sparkfun boards already have resistors. Too much resistance will cause the signals to have slow rise and fall times.

Get rid of those 10k resistors and see what happens. You might still have to remove the pullups on the SCL lines on two of the three boards.

You could also try a much slower I2C clock. Since the Sparkfun library calls Wire.begin() you could do it there. Immediately after that line add this line "TWBR = 200;". That will slow the clock down from 100kHz to 31kHz and maybe it will work. But it would be better to have the right resistors.

Hi Guys

Thank you for helping out!

I have tried to monitor temperature, and the same distortion appears:
Z1= 46.01 Z2= 25.07

Changing the setup of the pull-up resistors does not seem to benefit my readings. I have tried to:

  • and retain my pull-up resistors on R2, R3, and R4.
  • Place a pull-up resistor between SIG and 3.3V.

  • Changed my code according to Hackscribble's suggestions.

Currently, I only have 220ohm, 1kohm, and 10kohm resistors available. If I read the datasheet right, 10kohm is the recommended max limit. Would, working on the limit, be enough to cause problems - hence do i need to buy new resistors?

BR
Kenneth

Keep all (onboard) 4k7 pullups for dataline.
Total pullup for clockline no lower than 2k ( 4k7 // 4k7 id s OK) remove one pullup-resistor
Dont add external pullups
Run multiplexer off 5V (no risk for the sensors data/clk)
U can expect variation in readings from the sensors..:
...........

from BMP 180 datasheet:

3.4 Calibration coefficients
The 176 bit E2PROM is partitioned in 11 words of 16 bit each. These contain 11 calibration
coefficients. Every sensor module has individual coefficients. Before the first calculation of
temperature and pressure, the master reads out the E2PROM data

Does the library useone set of factors for all sensors? or individual sets?

Hi again

I have tried to use 4,7kohm resistors, and it does not affect the resulting output.

I did a test where I isolated each of my sensors to see if I could get correct results. By doing so, my temperature readings became correct, but my pressure readings was still incorrect.

Z1: Temp = 23,1, Pressure = 508
Z2: Temp = 24,3, Pressure = 561
Z3: Temp = 23,7, Pressure = 514

Does this indicate that the problem is within my code?

Does the library useone set of factors for all sensors? or individual sets?

I honestly don't know, but the intention of my code is to seperate the sensors by creating unique variables for each sensor. I define 3 sensors p1,p2, and p3 and assign them individual variables p1(T1;P1), p2(T2;P2),p3(T3,P3)

#include <SFE_BMP180.h>
#include <Wire.h>

SFE_BMP180 p1,p2,p3;

int EN = 13;
int s0 = 12;
int s1 = 11;
int s2 = 10;
int s3 = 9;



void out1(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(EN,LOW);  
}

void out2(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, LOW);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(EN,LOW);  
}

void out3(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(EN,LOW);  
}



void setup()
{
  out1();
  out2();
  out3();

  //pinMode(EN,OUTPUT);
  pinMode(s0,OUTPUT);
  pinMode(s1,OUTPUT);
  pinMode(s2,OUTPUT);
  pinMode(s3,OUTPUT);
  
  Serial.begin(9600);
  
  p1.begin();
  p2.begin();
  p3.begin();
}



void loop()
{
  
  //Sensor 1
  out1();
  
  double T1,P1;

  p1.startTemperature();
  p1.getTemperature(T1);
  p1.startPressure(3);
  p1.getPressure(P1,T1);

  Serial.print("Z1= ");
  Serial.print(P1);

  delay(10);


  // Sensor 2
  out2();
  
  double T2,P2;
  
  p2.startTemperature();
  p2.getTemperature(T2);
  p2.startPressure(3);
  p2.getPressure(P2,T2);

  Serial.print("\tZ2= ");
  Serial.print(P2);

  delay(10);

  // Sensor 3
  out3();
  
  double T3,P3;

  p3.startTemperature();
  p3.getTemperature(T3);
  p3.startPressure(3);
  p3.getPressure(P3,T3);

  Serial.print("\tZ3= ");
  Serial.println(P3);
 
  delay(10);
  
}

It seems to be conflicting with the sensor library, but i can't really figure out where, and how to move forward.

The sparkfun library stores the calibration coefficients inside the class, so they are separate for each device.

But your code has problems.

Your multiplex functions (out1, etc) control channels 1, 2, 3. But your schematic shows the devices connected to channels 0, 1, 2. In setup you select channels 1, 2 and 3 in quick succession (why?) but don't select the appropriate channel before calling begin() for that device. The devices are all getting initialized when channel 3 is selected -- which is connected to nothing. So the calibration coefficients aren't getting loaded. I'm amazed the whole thing doesn't just hang.

Hi

My posted circuit was wrong (Sorry). My sensors are connected to C1, C2, and C3 (See attachement), so the code referes to the correct channels. Again, sorry for the inconvenience!

In setup you select channels 1, 2 and 3 in quick succession (why?)

I followed and twisted this tutorial to my needs: Multiplexer Setup

...but don't select the appropriate channel before calling begin() for that device

Is this what you propose?:

void setup()
{
   
  //pinMode(EN,OUTPUT);
  pinMode(s0,OUTPUT);
  pinMode(s1,OUTPUT);
  pinMode(s2,OUTPUT);
  pinMode(s3,OUTPUT);
  
  Serial.begin(9600);
  
  out1();
  p1.begin();
   
  out2();
  p2.begin();
    
  out3();
  p3.begin();
}

By doing so, and declaring pinMode() before begin() the project moved a bit closer to success (WOOOOHOOOO!!!!).

Now i get the correct temperature values, but my pressure readings are still incorrect -

Z1= 515.46mb, 23.98C Z2= 511.62mb, 23.77C Z3= 565.34mb, 23.98C

It seems, that something happens between the temperature reading and pressure reading. The algorithm for how the pressure is calculated in library shows that it is dependant on temperature. But as it is correct, some of the later input variables could be the problem?

You're not using the sparkfun library correctly. The temperature and pressure conversions take time so you either have to wait the maximum time or else poll the device to see if it is finished. The sparkfun library takes the first approach and even tells you how long to wait. It may be because the temperature conversion is a lot faster that you are apparently getting a good value for that.

Look at the example code...

jboyton - I love you!... It works.

I went back and copied the loop() function from the example code into my code. The status variable combined with the if functions was what i was missing!

In case anyone should have a similar problem, here is my code:

#include <SFE_BMP180.h>
#include <Wire.h>

SFE_BMP180 p1,p2,p3;

int EN = 13;
int s0 = 12;
int s1 = 11;
int s2 = 10;
int s3 = 9;

void out1(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(EN, LOW);  
}

void out2(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, LOW);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(EN, LOW);  
}

void out3(){
  digitalWrite(EN, HIGH);
  digitalWrite(s0, HIGH);
  digitalWrite(s1, HIGH);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  digitalWrite(EN, LOW);  
}


void setup()
{
  //pinMode(EN,OUTPUT);
  pinMode(s0,OUTPUT);
  pinMode(s1,OUTPUT);
  pinMode(s2,OUTPUT);
  pinMode(s3,OUTPUT);
  
  Serial.begin(9600);
  
  out1();
  p1.begin();
    
  out2();
  p2.begin();
  
  out3();
  p3.begin();
}

void loop()
{

//Read Sensor 1
  out1();
  
  char status;
  double T1,P1;

  status = p1.startTemperature();
  if (status != 0)
  {
    delay(status);

    status = p1.getTemperature(T1);
    if (status != 0)
    {
      Serial.print("Z1: ");
      Serial.print(T1,2);

      status = p1.startPressure(3);
      if (status != 0)
      {
        delay(status);

        status = p1.getPressure(P1,T1);
        if (status != 0)
        {
          Serial.print(" ");
          Serial.print(P1,2);
        }
      }
    }
  }
 
//Read Sensor 2
  out2();
 
  double T2,P2;

  status = p2.startTemperature();
  if (status != 0)
  {
    delay(status);

    status = p2.getTemperature(T2);
    if (status != 0)
    {
      Serial.print("\tZ2: ");
      Serial.print(T2,2);

      status = p2.startPressure(3);
      if (status != 0)
      {
        delay(status);

        status = p2.getPressure(P2,T2);
        if (status != 0)
        {
          Serial.print(" ");
          Serial.print(P2,2);
        }
      }
    }
  }

  
//Read Sensor 3
  out3();

  //char status;
  double T3,P3;

  status = p3.startTemperature();
  if (status != 0)
  {
    delay(status);

    status = p3.getTemperature(T3);
    if (status != 0)
    {
      Serial.print("\tZ3: ");
      Serial.print(T3,2);

      status = p3.startPressure(3);
      if (status != 0)
      {
        delay(status);

        status = p3.getPressure(P3,T3);
        if (status != 0)
        {
          Serial.print(" ");
          Serial.println(P3,2);
        }
      }
    }
  }
  delay(5000);
}

Thank you for your help - i really appreciate it!

Hi Kenneth;
I appreciate your nice posting and information, which I am using with joy!
By the way, I am increasing the # of BMP180 modifying your code. It works up to 4 parts simply repeating necessary code, but, somehow not for 5 parts.
Do you have any idea why not 5 while it works up to 4? By the way, I noticed that it works without using resisters, so I eliminated all those in my wiring. Would this be the issue for connecting 5 parts?
Again, it works up to 4 parts, so I don't think that I made mistake in code and wiring for 5 parts checking multiple times....
Thanks,
Caleb

  • memory usage .. check with freemem.
  • how many pullup resistors? Keep total pullup in range 2k2..10k