Arduino 读取 BMP085 大气压强模块教程

发布于: 27 January, 2014
分享:

为了能够在步态判断过程中准确地判断上楼步态与下楼步态,尝试引入气压计,通过测试上下楼气压的变化间接算出水平面高度的变化,从而判断出上楼或者下楼的步态。 当然,使用气压传感器的用途还有很多,借用一下 BMP085datasheet  上面的介绍,气压传感器还可以用到以下的场合:盲区推估;户外导航;天气预测;垂直运动速度测量。 其实气压传感器除了在一些关于气象、天气方面的应用以外,基本上都是用来测试海拔高度。从应用场合来看,盲区推估;户外导航;垂直运动速度测量也都是用到了测量海拔高度这个应用。所以要想用好气压传感器,正确理解气压和海拔高度的关系是很重要的,本文将在第二章介绍气压与海拔的一些基本关系。 希望通过阅读本文可以帮助大家很快的搭建基于气压计的项目应用

使用气压传感器之前要考虑的问题

作为一个物理量,气压的大小有着很深刻的物理含义。这里对具体的物理意义就不详细介绍了。主要说一下气压与海拔高度的关系。  

气压与海拔高度之间的关系

海拔高度与大气压力的关系在大气物理学里面有明确的定义。根据不同的大气模型,会有不同的气压与海拔的对应关系。详细资料可以参考大气物理学的书籍。 但是看大气物理学的书比家复杂,所以可以参考公式 2.-1-1。Pb 就是压力传感器测试出来的压力值,h 就是相应的海拔高度。有一点特别需要注意,就是海拔高度与压力大小的关系受温度的影响。很多情况下,压力传感器芯片的 Datasheet(规格书) 会提供压力与海拔高度的对应关系,也可以用来借鉴。  

影响压力测量的因素

影响压力测量的因素有很多,除了关键的海拔高度以及温度的影响,诸如空气的流动(诸如风,空调等等)都影响空气压力的测量。  

规格书中的重要参数

 

Tab1.0

ParameterSymbolConditionMaxUnit
Operating temperatureTA  
Supply voltage   
Supply current @1SPS At 25℃   uA
Peak current   uA
    uA
    uA
    uA
    uA
    uA
    uA
    MHz
    Ms
    Ms
    Ms
    Ms
    Ms
    hPa
    hPa
    hPa
    hPa
    
Absolute accuracy Pressure VDD=3.3V   hPa
Resolution of output data   hPa
    
    
Solder drift Minimum solder height 50uM±1..0hPa
Long term stability 12 months±1..0hPa

  

  • absolute accuracy:绝对精度,也就是在一个测量范围内的测量精度。举例来说,如果测量的气压从700hPa一直到1100hPa,理论上读数应该是变化了400hPa,但实际上的读数可能是 400hPa±absolute accuracy。
  • relative accuracy:相对精度,也就是在一个固定测量值的测量精度。举例来说,如果测量 500hPa 的气压,实际的测量值是 500hPa±relative accuracy。
  • Solder drift:焊接影响,该器件对于焊接的要求比较高,如果焊接造成了一定的器件变形,等价于器件存在了一个内部的残余应力,所以会对实际测量产生一定的偏差。

 

BMP085 的数据读取方式

从 BMP085 读取数据的方法如图 Fig4.4 所示 从 BMP085 读取数据的步骤如下: 

  1. 发送模块地址+W(表示写操作),如 Fig4.4 中的 0xEE。
  2. 送寄存器地址(register address),如 Fig4.4 中的第一个 0xF6。
  3. 重新开始 IIC 传输(Restart)。
  4. 发送模块地址+R(表示要进行读操作),如 Fig4.4 中的 0xEF。
  5. 读取测量值的高 8 位(MSB)。
  6. 读取测量值的低 8 位(LSB)。
  7. 不同寄存器地址的意义如 Tab4.2 所示

Tab4.2

寄存器名称寄存器地址
EEPROM0xAA To 0xBF
Temperature or pressure value(UT or UP)0xF6(MSB)、0x F7(LSB)  、0xF8(XLSB)

     

程序控制总结

从 Fig4.4  与 Fig4.3  可以清楚地看出 MCU 控制 BMP085 的方法,这里再进行一些简单的概括。其实对 BMP085 的控制可以概括为两句话:向固定的寄存器(0xF4)写特定值(Tab4.1 中的 control register value),从特定的寄存器(Tab4.2中的寄存器地址)读返回值。每次通讯时的 Module address 都是一个固定的值,主要是为了符合 IIC 协议。 

  1. 向固定的寄存器(0xF4)写特定值(Tab4.1 中的 control register value)其实就是向 0xF4 地址写不同的值从而完成温度测量或者不同的压力精度的测量。
  2. 从特定的寄存器(Tab4.2 中的寄存器地址)读返回值从 EEPROM 读取 Calibration  所需要的数据,共有 11 个 Word(双字节)。从 0xF6,0xF7,0xF8  读取 UT 或者 UP,具体是 UP 还是 UT 要由前面进行的操作决定(进行了温度转换就存有温度数据,进行了压力转换就存有压力数据)。

例程:   //Arduino 1.0+ Only //Arduino 1.0+ Only

/*Based largely on code by  Jim Lindblom

Get pressure, altitude, and temperature from the BMP085. Serial.print it out at 9600 baud to serial monitor. */

#include

#define BMP085_ADDRESS 0x77  // I2C address of BMP085

const unsigned char OSS = 0;  // Oversampling Setting

// Calibration values int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md;

// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...) // so ...Temperature(...) must be called before ...Pressure(...). long b5;

void setup(){  Serial.begin(9600);  Wire.begin();

 bmp085Calibration(); }

void loop() {  float temperature = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first  float pressure = bmp085GetPressure(bmp085ReadUP());  float atm = pressure / 101325; // "standard atmosphere"  float altitude = calcAltitude(pressure); //Uncompensated caculation - in Meters

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

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

 Serial.print("Standard 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();//line break

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

// Stores all of the bmp085's calibration values into global variables // Calibration values are required to calculate temp and pressure // This function should be called at the beginning of the program void bmp085Calibration() {  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); }

// Calculate temperature in deg C float bmp085GetTemperature(unsigned int ut){  long x1, x2;

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

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

 return temp; }

// Calculate pressure given up // calibration values must be known // b5 is also required so bmp085GetTemperature(...) must be called first. // Value returned will be pressure in units of Pa. long bmp085GetPressure(unsigned long up){  long x1, x2, x3, b3, b6, p;  unsigned long b4, b7;

 b6 = b5 - 4000;  // Calculate B3  x1 = (b2 * (b6 * b6)>>12)>>11;  x2 = (ac2 * b6)>>11;  x3 = x1 + x2;  b3 = (((((long)ac1)*4 + x3)<>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; }

// Read 1 byte from the BMP085 at 'address' char bmp085Read(unsigned char address) {  unsigned char data;

 Wire.beginTransmission(BMP085_ADDRESS);  Wire.write(address);  Wire.endTransmission();

 Wire.requestFrom(BMP085_ADDRESS, 1);  while(!Wire.available())    ;

 return Wire.read(); }

// Read 2 bytes from the BMP085 // First byte will be from 'address' // Second byte will be from 'address'+1 int bmp085ReadInt(unsigned char address) {  unsigned char msb, lsb;

 Wire.beginTransmission(BMP085_ADDRESS);  Wire.write(address);  Wire.endTransmission();

 Wire.requestFrom(BMP085_ADDRESS, 2);  while(Wire.available()<2)    ;  msb = Wire.read();  lsb = Wire.read();

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

// Read the uncompensated temperature value unsigned int bmp085ReadUT(){  unsigned int ut;

 // Write 0x2E into Register 0xF4  // This requests a temperature reading  Wire.beginTransmission(BMP085_ADDRESS);  Wire.write(0xF4);  Wire.write(0x2E);  Wire.endTransmission();

 // Wait at least 4.5ms  delay(5);

 // Read two bytes from registers 0xF6 and 0xF7  ut = bmp085ReadInt(0xF6);  return ut; }

// Read the uncompensated pressure value unsigned long bmp085ReadUP(){

 unsigned char msb, lsb, xlsb;  unsigned long up = 0;

 // Write 0x34+(OSS<<6) into register 0xF4  // Request a pressure reading w/ oversampling setting  Wire.beginTransmission(BMP085_ADDRESS);  Wire.write(0xF4);  Wire.write(0x34 + (OSS<<6));  Wire.endTransmission();

 // Wait for conversion, delay time dependent on OSS  delay(2 + (3<> (8-OSS);

 return up; }

void writeRegister(int deviceAddress, byte address, byte val) {  Wire.beginTransmission(deviceAddress); // start transmission to device  Wire.write(address);       // send register address  Wire.write(val);         // send value to write  Wire.endTransmission();     // end transmission }

int readRegister(int deviceAddress, byte address){

 int v;  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();  return v; }

float calcAltitude(float pressure){

 float A = pressure/101325;  float B = 1/5.25588;  float C = pow(A,B);  C = 1 - C;  C = C /0.0000225577;

 return C; }  

分享:

0 留言

留言

您的留言将被人工审核,请勿发表色情、反动言论。