BMP085 and Mbed code

28 Jul 2012

Please i ran this code for my pressure sensor BMP085 which is connected to my MBED, but I kept on getting constant values.

Can any one please understand it and correct the code, or better still give a better code to use.

  1. include "mbed.h"
  2. include "math.h" I2C i2c(p9, p10); Serial pc(USBTX, USBRX); tx, rx

int I2C_ADDRESS = 0xEE; sensor address

oversampling setting 0 = ultra low power 1 = standard 2 = high 3 = ultra high resolution const unsigned char oversampling_setting = 3; oversampling for measurement const unsigned char pressure_conversiontime[4] = { 4.5, 7.5, 13.5, 25.5 }; delays for oversampling settings 0, 1, 2 and 3

sensor registers from the BOSCH BMP085 datasheet 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;

variables to keep the values float temperature = 0; float pressure = 0;

void writeRegister(unsigned char r, unsigned char v) { char cmd1[2]; cmd1[0] = r; cmd1[1] = v; i2c.write(I2C_ADDRESS,cmd1, 2); }

read a 16 bit register int readIntRegister(unsigned char r) { char cmd1[2]; char cmd2[1]; unsigned char msb, lsb; cmd2[0] = r; i2c.write(I2C_ADDRESS,cmd2, 1); i2c.read(I2C_ADDRESS, cmd1, 2); return (((int)cmd1[0]<<8) | ((int)cmd1[1])); }

read uncompensated temperature value unsigned int readUT() { writeRegister(0xf4,0x2e); wait(0.0045); the datasheet suggests 4.5 ms return readIntRegister(0xf6);

}

read uncompensated pressure value long readUP() { writeRegister(0xf4,0x34+(oversampling_setting<<6)); wait(pressure_conversiontime[oversampling_setting]*0.001);

unsigned char msb, lsb, xlsb; char cmd1[3]; char cmd0[1]; cmd0[0] = 0xf6; i2c.write(I2C_ADDRESS,cmd0, 1); i2c.read(I2C_ADDRESS, cmd1, 3); return (((long)cmd1[0]<<16) | ((long)cmd1[1]<<8) | ((long)cmd1[2])) >>(8-oversampling_setting);

}

Below there are the utility functions to get data from the sensor.

read temperature and pressure from sensor void readSensor() {

long ut= readUT(); long up = readUP();

int x1, x2, x3, b3, b5, b6, p; unsigned int b4, b7; calculate true temperature x1 = ((long)ut - ac6) * ac5 >> 15; x2 = ((long) mc << 11) / (x1 + md); b5 = x1 + x2; temperature = (b5 + 8) >> 4;

calculate true pressure b6 = b5 - 4000; x1 = (b2 * (b6 * b6 >> 12)) >> 11; x2 = ac2 * b6 >> 11; x3 = x1 + x2;

if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1; if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2); if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1; if (oversampling_setting == 0) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 2;

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 >> oversampling_setting); p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

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

}

void getCalibrationData() { pc.printf("Reading Calibration Data"); ac1 = readIntRegister(0xAA); pc.printf("AC1: %d\r\n",ac1);

ac2 = readIntRegister(0xAC); pc.printf("AC2: %d\r\n",ac2);

ac3 = readIntRegister(0xAE); pc.printf("AC3: %d\r\n",ac3);

ac4 = readIntRegister(0xB0); pc.printf("AC4: %d\r\n",ac4);

ac5 = readIntRegister(0xB2); pc.printf("AC5: %d\r\n",ac5);

ac6 = readIntRegister(0xB4); pc.printf("AC6: %d\r\n",ac6);

b1 = readIntRegister(0xB6); pc.printf("B1: %d\r\n",b1);

b2 = readIntRegister(0xB8); pc.printf("B2: %d\r\n",b2);

mb = readIntRegister(0xBA); pc.printf("MB: %d\r\n",mb);

mc = readIntRegister(0xBC); pc.printf("MC: %d\r\n",mc);

md = readIntRegister(0xBE); pc.printf("MD: %d\r\n",md);

}

float altitud(float p) { float To=298; float ho=0; float Po=101325; ecuacion float c=(To-0.0065*ho); float e=(p/Po); float d=exp(0.19082*log(e)); float b=c*d; float alt=153.84615*(To-b); return(alt); }

int main(){ pc.baud(9600); getCalibrationData(); while(1) { readSensor(); pc.printf("Temperature: %.f Pressure: %.f Altitud: %.1f\r",temperature,pressure, altitud(pressure)); wait(1);

} }

28 Jul 2012

Please add <<code>> and <</code>> around your code in the post to make it readable.

When you get constant data it usually means there is something wrong with the hardware. Check the I2C signals SCL and SDA, are the correct pins p9,p10 connected to the correct sensor pins. Are the pull-up resistors in place. Do you have powersupply and ground connected to the sensor. What about xclr,is it floating? Measure the voltage levels. Use a scope or logic analiser if available.

28 Jul 2012

Indeed code tags would have been nice. Two things to add to Wim's post. The first thing I do when working with a new I2C sensor is simply writing to a random register, and looking what the write function returns. So for example something like this:

char wreg = 0xf4;
int ret = i2c.write(I2C_ADDRESS, &wreg, 1);
pc.printf("Return = %d\n\r", ret);

You should get zero back, then there is communication. If not, refer to Wim's post.

If you do get zero back something else is the issue. Knowing which constant values you are getting could help. One possible problem is your read function, according to the datasheet you need to send a restart after writing which register you want to read, so the code becomes:

int readIntRegister(unsigned char r)
{
  char cmd1[2];
  char cmd2[1];
  //unsigned char msb, lsb;
  cmd2[0] = r;
  i2c.write(I2C_ADDRESS,cmd2, 1, true);   //Added the true here
  i2c.read(I2C_ADDRESS, cmd1, 2);
  return (((int)cmd1[0]<<8) | ((int)cmd1[1]));
}

And for everyone else, his code with code tags: (Yes it is kinda long, still better than without code tags)

#include "mbed.h"
#include "math.h"
I2C i2c(p9, p10); 
Serial pc(USBTX, USBRX); // tx, rx

int I2C_ADDRESS = 0xEE;  // sensor address

// oversampling setting
// 0 = ultra low power
// 1 = standard
// 2 = high
// 3 = ultra high resolution
const unsigned char oversampling_setting = 3; //oversampling for measurement
const unsigned char pressure_conversiontime[4] = { 
  4.5, 7.5, 13.5, 25.5 };  // delays for oversampling settings 0, 1, 2 and 3   

// sensor registers from the BOSCH BMP085 datasheet
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;

// variables to keep the values
float temperature = 0;
float pressure = 0;


void writeRegister(unsigned char r, unsigned char v)
{
  char cmd1[2];
  cmd1[0] = r;
  cmd1[1] = v;
  i2c.write(I2C_ADDRESS,cmd1, 2);
}

// read a 16 bit register
int readIntRegister(unsigned char r)
{
  char cmd1[2];
  char cmd2[1];
  //unsigned char msb, lsb;
  cmd2[0] = r;
  i2c.write(I2C_ADDRESS,cmd2, 1);
  i2c.read(I2C_ADDRESS, cmd1, 2);
  return (((int)cmd1[0]<<8) | ((int)cmd1[1]));
}

// read uncompensated temperature value
unsigned int readUT() {
  writeRegister(0xf4,0x2e);
  wait(0.0045); // the datasheet suggests 4.5 ms
  return readIntRegister(0xf6);
  
}

// read uncompensated pressure value
long readUP() {
  writeRegister(0xf4,0x34+(oversampling_setting<<6));
  wait(pressure_conversiontime[oversampling_setting]*0.001);

  //unsigned char msb, lsb, xlsb;
  char cmd1[3];
  char cmd0[1];
  cmd0[0] = 0xf6;
  i2c.write(I2C_ADDRESS,cmd0, 1);
  i2c.read(I2C_ADDRESS, cmd1, 3); 
  return (((long)cmd1[0]<<16) | ((long)cmd1[1]<<8) | ((long)cmd1[2])) >>(8-oversampling_setting);
  
}

// Below there are the utility functions to get data from the sensor.

// read temperature and pressure from sensor
void readSensor() {

  long ut= readUT();
  long up = readUP();


  int x1, x2, x3, b3, b5, b6, p;
  unsigned int b4, b7;
  //calculate true temperature
  x1 = ((long)ut - ac6) * ac5 >> 15;
  x2 = ((long) mc << 11) / (x1 + md);
  b5 = x1 + x2;
  temperature = (b5 + 8) >> 4;
 
  //calculate true pressure
  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;

  if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1;
  if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2);
  if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1;
  if (oversampling_setting == 0) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 2;
 
  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 >> oversampling_setting);
  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

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



void  getCalibrationData() {
  pc.printf("Reading Calibration Data");
  ac1 = readIntRegister(0xAA);
  pc.printf("AC1: %d\r\n",ac1);
  
  ac2 = readIntRegister(0xAC);
  pc.printf("AC2: %d\r\n",ac2);
  
  ac3 = readIntRegister(0xAE);
  pc.printf("AC3: %d\r\n",ac3);
  
  ac4 = readIntRegister(0xB0);
  pc.printf("AC4: %d\r\n",ac4);
  
  ac5 = readIntRegister(0xB2);
  pc.printf("AC5: %d\r\n",ac5);
 
  ac6 = readIntRegister(0xB4);
  pc.printf("AC6: %d\r\n",ac6);
 
  b1 = readIntRegister(0xB6);
  pc.printf("B1: %d\r\n",b1);
 
  b2 = readIntRegister(0xB8);
  pc.printf("B2: %d\r\n",b2);

  mb = readIntRegister(0xBA);
  pc.printf("MB: %d\r\n",mb);

  mc = readIntRegister(0xBC);
  pc.printf("MC: %d\r\n",mc);
 
  md = readIntRegister(0xBE);
  pc.printf("MD: %d\r\n",md);

}

float altitud(float p)
{
    float To=298;
    float ho=0;
    float Po=101325; 
    //ecuacion
    float c=(To-0.0065*ho);
    float e=(p/Po);
    float d=exp(0.19082*log(e));  
    float b=c*d;
    float alt=153.84615*(To-b); 
    return(alt);
}





int main(){ 
  pc.baud(9600); 
  getCalibrationData();
while(1)
{
  readSensor();
  pc.printf("Temperature: %.f   Pressure: %.f  Altitud: %.1f\r",temperature,pressure, altitud(pressure));
  wait(1);

}
} 
11 Aug 2012

I've recently used this library with much success.... http://mbed.org/users/okini3939/code/bmp085_lib/