Bmp 180 and software i2c

All atmega328 analog pins are occupied for the LCD display. I need to connect the bm180 sensor. But I can't get the data using the library. Is there a way to connect this sensor to the digital pins?

#define SCL_PIN 7
#define SCL_PORT PORTC
#define SDA_PIN 8
#define SDA_PORT PORTC
#include "BMP085.h"
#include <SoftI2C.h>
float pressure;
BMP085 myBarometer;
void setup() {
    Serial.begin(9600);
    while (!Serial);
    myBarometer.init();
}

void loop() {
    pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP());
    Serial.print("Pressure: ");
    Serial.print(pressure, 0);
    Serial.println(" Pa");
    Serial.println();
    delay(1000);
}

You have at least pins 7 and 8 available for digital so you can move 2 pins of the LCD display to those and have A4 and A5 available for your BMP180.

2 Likes

The problem is that the board has already been created, so I would like to do without changing it.

You have three options

  1. Find a BMP085 library that supports software I2C. I did have a look around but could not find one; maybe you have more luck.
  2. Hack the current library to support SoftI2C.
  3. Modify the board by cutting some tracks and using thin wire to reroute. If this is not mass production, that should not be an issue. If it's 10+ or hundreds of boards it is and I suggest that you modify one board, test and later do a new production run.

You seem to be using GitHub - Seeed-Studio/Grove_Barometer_Sensor: test the barometer; correct?

Do you have a link to the SoftI2C library that you use?

The below is a hacked version of the library plus the example code (GitHub - Seeed-Studio/Grove_Barometer_Sensor: test the barometer). The SoftI2C library is GitHub - yasir-shahzad/SoftI2C: Software-based I2C communication library for Arduino.

This code does compile but I have no means to test.

In your sketch directory you need to create two files, softBMP085.h and softBMP085.cpp.

softBMP085.h

/*
Modified version of https://github.com/Seeed-Studio/Grove_Barometer_Sensor for use with software I2C
Modified by @sterretje
*/

#ifndef __BMP085_H__
#define __BMP085_H__

#include <Arduino.h>
#include <SoftI2C.h>
//#include <Wire.h>

const unsigned char OSS = 0;
#define BMP085_ADDRESS 0x77

class softBMP085 {
  public:
    // sterretje
    softBMP085(uint8_t pinSDA, int8_t pinSCL);
    // sterretje end

    void init(void);
    long PressureCompensate;
    float bmp085GetTemperature(unsigned short ut);
    long bmp085GetPressure(unsigned long up);
    float calcAltitude(float seaLevelPressure = 101325);
    unsigned short bmp085ReadUT(void);
    unsigned long bmp085ReadUP(void);

  private:
    // sterretje
    SoftI2C _SoftWire;
    // sterretje end

    short ac1;
    short ac2;
    short ac3;
    unsigned short ac4;
    unsigned short ac5;
    unsigned short ac6;
    short b1;
    short b2;
    short mb;
    short mc;
    short md;
    char bmp085Read(unsigned char address);
    short bmp085ReadInt(unsigned char address);
    void writeRegister(short deviceAddress, byte address, byte val);
    short readRegister(short deviceAddress, byte address);
};

#endif

softBMP085.cpp

/*
Modified version of https://github.com/Seeed-Studio/Grove_Barometer_Sensor for use with software I2C
Modified by @sterretje
*/

#include "softBMP085.h"
#include <SoftI2C.h>
//#include <Wire.h>
#include <Arduino.h>
#include <math.h>

// sterretje
softBMP085::softBMP085(uint8_t pinSDA, int8_t pinSCL) : _SoftWire(pinSDA, pinSCL)
{
}
// sterretje end

void softBMP085::init(void) {
  // sterretje
  //Wire.begin();
  _SoftWire.begin();
  // sterretje end

  ac1 = bmp085ReadInt(0xAA);
  ac2 = bmp085ReadInt(0xAC);
  ac3 = bmp085ReadInt(0xAE);
  ac4 = bmp085ReadInt(0xB0);
  ac5 = bmp085ReadInt(0xB2);
  ac6 = bmp085ReadInt(0xB4);
  b1 = bmp085ReadInt(0xB6);
  b2 = bmp085ReadInt(0xB8);
  mb = bmp085ReadInt(0xBA);
  mc = bmp085ReadInt(0xBC);
  md = bmp085ReadInt(0xBE);
}

// Read 1 byte from the BMP085 at 'address'
// Return: the read byte;
char softBMP085::bmp085Read(unsigned char address) {
  // sterretje
  /*
    Wire.beginTransmission(BMP085_ADDRESS);
    Wire.write(address);
    Wire.endTransmission();

    Wire.requestFrom(BMP085_ADDRESS, 1);
    while (!Wire.available());
    return Wire.read();
  */
  _SoftWire.beginTransmission(BMP085_ADDRESS);
  _SoftWire.write(address);
  _SoftWire.endTransmission();

  _SoftWire.requestFrom(BMP085_ADDRESS, 1);
  while (!_SoftWire.available());
  return _SoftWire.read();
  // sterretje end
}

// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
short softBMP085::bmp085ReadInt(unsigned char address) {
  unsigned char msb, lsb;
  // sterretje
  /*
    Wire.beginTransmission(BMP085_ADDRESS);
    Wire.write(address);
    Wire.endTransmission();
    Wire.requestFrom(BMP085_ADDRESS, 2);
    while (Wire.available() < 2);
    msb = Wire.read();
    lsb = Wire.read();
  */

  _SoftWire.beginTransmission(BMP085_ADDRESS);
  _SoftWire.write(address);
  _SoftWire.endTransmission();
  _SoftWire.requestFrom(BMP085_ADDRESS, 2);
  while (_SoftWire.available() < 2);
  msb = _SoftWire.read();
  lsb = _SoftWire.read();
  // sterretje end

  return (short) msb << 8 | lsb;
}

// Read the uncompensated temperature value
unsigned short softBMP085::bmp085ReadUT() {
  unsigned short ut;

  // sterretje
  /*
    Wire.beginTransmission(BMP085_ADDRESS);
    Wire.write(0xF4);
    Wire.write(0x2E);
    Wire.endTransmission();
    delay(5);
  */
  // sterretje end

  _SoftWire.beginTransmission(BMP085_ADDRESS);
  _SoftWire.write(0xF4);
  _SoftWire.write(0x2E);
  _SoftWire.endTransmission();
  delay(5);

  ut = bmp085ReadInt(0xF6);
  return ut;
}
// Read the uncompensated pressure value
unsigned long softBMP085::bmp085ReadUP() {
  unsigned char msb, lsb, xlsb;
  unsigned long up = 0;

  // sterretje
  /*
    Wire.beginTransmission(BMP085_ADDRESS);
    Wire.write(0xF4);
    Wire.write(0x34 + (OSS << 6));
    Wire.endTransmission();
  */
  _SoftWire.beginTransmission(BMP085_ADDRESS);
  _SoftWire.write(0xF4);
  _SoftWire.write(0x34 + (OSS << 6));
  _SoftWire.endTransmission();
  // sterretje end
  delay(2 + (3 << OSS));

  // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
  msb = bmp085Read(0xF6);
  lsb = bmp085Read(0xF7);
  xlsb = bmp085Read(0xF8);
  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8 - OSS);
  return up;
}

void softBMP085::writeRegister(short deviceAddress, byte address, byte val) {
  // sterretje
  /*
    Wire.beginTransmission(deviceAddress); // start transmission to device
    Wire.write(address);       // send register address
    Wire.write(val);         // send value to write
    Wire.endTransmission();     // end transmission
  */
  _SoftWire.beginTransmission(deviceAddress); // start transmission to device
  _SoftWire.write(address);       // send register address
  _SoftWire.write(val);         // send value to write
  _SoftWire.endTransmission();     // end transmission
  // sterretje end
}

short softBMP085::readRegister(short deviceAddress, byte address) {
  short v;
  // sterretje
  /*
    Wire.beginTransmission(deviceAddress);
    Wire.write(address); // register to read
    Wire.endTransmission();

    Wire.requestFrom(deviceAddress, 1); // read a byte

    while (!Wire.available()) {
    // waiting
    }

    v = Wire.read();
  */
  _SoftWire.beginTransmission(deviceAddress);
  _SoftWire.write(address); // register to read
  _SoftWire.endTransmission();

  _SoftWire.requestFrom(deviceAddress, 1); // read a byte

  while (! _SoftWire.available()) {
    // waiting
  }

  v =  _SoftWire.read();
  // sterretje

  return v;
}

float softBMP085::calcAltitude(float seaLevelPressure) {
  float pressure = bmp085GetPressure(bmp085ReadUP());//Get the temperature
  float altitude = 44330.0 * (1.0 - pow(pressure / seaLevelPressure, 0.1903));

  return altitude;
}

float softBMP085::bmp085GetTemperature(unsigned short ut) {
  long x1, x2;

  x1 = (((long)ut - (long)ac6) * (long)ac5) >> 15;
  x2 = ((long)mc << 11) / (x1 + md);
  PressureCompensate = x1 + x2;

  float temp = ((PressureCompensate + 8) >> 4);
  temp = temp / 10;

  return temp;
}

long softBMP085::bmp085GetPressure(unsigned long up) {
  long x1, x2, x3, b3, b6, p;
  unsigned long b4, b7;
  b6 = PressureCompensate - 4000;
  x1 = (b2 * (b6 * b6) >> 12) >> 11;
  x2 = (ac2 * b6) >> 11;
  x3 = x1 + x2;
  b3 = (((((long)ac1) * 4 + x3) << OSS) + 2) >> 2;

  // Calculate B4
  x1 = (ac3 * b6) >> 13;
  x2 = (b1 * ((b6 * b6) >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (unsigned long)(x3 + 32768)) >> 15;

  b7 = ((unsigned long)(up - b3) * (50000 >> OSS));
  if (b7 < 0x80000000) {
    p = (b7 << 1) / b4;
  } else {
    p = (b7 / b4) << 1;
  }

  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  p += (x1 + x2 + 3791) >> 4;

  long temp = p;
  return temp;
}

Example

#include "softBMP085.h"
//#include <Wire.h>
float temperature;
float pressure;
float atm;
float altitude;
softBMP085 myBarometer(8, 7);  // SDA, SCL


void setup() {
  Serial.begin(9600);
  while (!Serial);
  myBarometer.init();

}

void loop() {
  temperature = myBarometer.bmp085GetTemperature(
                  myBarometer.bmp085ReadUT()); //Get the temperature, bmp085ReadUT MUST be called first
  pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP());//Get the temperature

  /*
      To specify a more accurate altitude, enter the correct mean sea level
      pressure level.  For example, if the current pressure level is 1019.00 hPa
      enter 101900 since we include two decimal places in the integer value。
  */
  altitude = myBarometer.calcAltitude(101900);

  atm = pressure / 101325;

  Serial.print("Temperature: ");
  Serial.print(temperature, 2); //display 2 decimal places
  Serial.println(" Celsius");

  Serial.print("Pressure: ");
  Serial.print(pressure, 0); //whole number only.
  Serial.println(" Pa");

  Serial.print("Ralated Atmosphere: ");
  Serial.println(atm, 4); //display 4 decimal places

  Serial.print("Altitude: ");
  Serial.print(altitude, 2); //display 2 decimal places
  Serial.println(" m");

  Serial.println();

  delay(1000); //wait a second and get values again.
}

I've commented nearly every change in the library; you can clean up once you see how it was modified.

Instead of a BMP085 class there is a softBMP085 class. The constructor takes the two pins (SDA and SCL) that you want to use.

As said, I can not test so if it does not work it's up to you to try to figure it out.

1 Like

It would have been sensible to use an i2c backpack for the LCD. Then it would have been able to share hardware SDA+SCL pins with the BMP180.

Agreed, the problem here is that the board was created too early, before the circuit design was truly complete.

1 Like

The code you attached works perfectly. Thank you so much for helping solve my problem!