【雕爷学编程】Arduino动手做(67)---BMP180气压传感器

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来---小小的进步或是搞不掂的问题,希望能够抛砖引玉。

【Arduino】168种传感器模块系列实验(资料+代码+图形+仿真)

实验六十七: GY-68 BMP180 新款 BOSCH温度模块气压传感器(替代BMP085)


BMP180

是博世Sensortec的新数字气压传感器,具有很高的性能,使应用先进的移动设备,如智能手机、平板电脑和体育设备。它遵循了BMP085带来了很多改进,像小尺寸和数字接口的扩张。超低功耗降至3μA使BMP180节电为您的移动设备的领导者。BMP180也是杰出的非常稳定的性能,最好有独立电源供电。BMP180是一款高精度、小体积、超低能耗的压力传感器,可以应用在移动设备中它的性能卓越,绝对精度最低可以达到0.03hPa,并且耗电极低,只有3μA。BMP180采用强大的8-pin陶瓷无引线芯片承载(LCC)超薄封装,可以通过I2C总线直接与各种微处理器相连。



BMP180主要特点

压力范围:300~1100hPa(海拔9000米~-500米)

电源电压:1.8V~3.6V(VDDA),1.62V~3.6V(VDDD) VIN需要5V

LCC8封装:无铅陶瓷载体封装(LCC)

低功耗:5μA,在标准模式

高精度:低功耗模式下,分辨率为0.06hPa(0.5米)

高线性模式下,分辨率为0.03hPa(0.25米)

含温度输出

I2C接口

温度补偿

无铅,符合RoHS规范

MSL 1反应时间:7.5ms

待机电流:0.1μA

无需外部时钟电路


BMP180技术数据

压力范围300……1100 hPa

均方根噪声中表达压力0.06 hPa typ。(超低功耗模式)

0.02 hPa typ。(超高分辨率模式)

均方根噪声中表达高度0.5 m,typ。(超低功耗模式)

0.17米,typ。(超高分辨率模式)

相对精度的压力

VDD = 3.3 v 950……1050 hPa / hPa±0.12

@ 25°C / m±1.0

700年……900 hPa / hPa±0.12

25…40°C / m±1.0

绝对精度

p = 300…1100 hpa

(温度= 0…+ 65°C,VDD = 3.3。-4.0 V)压力:……+ 2.0 hPa

温度:±1°C,typ。

平均电流消耗(1 Hz刷新率数据)

峰值电流3μA典型(超低功耗模式)

32μA,典型的(高级模式)

650μA,典型的

待机电流1.62……3.6 V

电源电压vddio 1.62……3.6 V

电源电压vdd 1.8……3.6 V

操作温度。

范围全面准确”40…+ 85°C

0…+ 65°C

conv压力。5毫秒,典型的(标准模式)

I2C传输速率3.4 MHz,马克斯。


BMP180典型应用

GPS精准导航(航位推算,上下桥检测等)

室内室外导航

休闲、体育和医疗健康等监测

天气预报

垂直速度指示(上升/下沉速度)

风扇功率控制

体育设备,如高度剖面


BMP180气压模块是一款高精度、小体积、低能耗的压力传感器,可以应用在移动设备中,它的性能卓越,绝对精度最低可以达到0.03hPa,并且耗电极低,只有3μA。BMP180采用强大的8-pin陶瓷无引线芯片承载(LCC)超薄封装,可以通过I2C总线直接与各种微处理器相连。


特性曲线


模块电原理图


需要用的 “SFE_BMP180” 库文件如下

SFE_BMP180.h

/*

【Arduino】66种传感器模块系列实验(68)

实验六十八:BMP180 新款 BOSCH温度模块气压传感器(代替BMP085)

SFE_BMP180.h

*/

#ifndef SFE_BMP180_h

#define SFE_BMP180_h

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

class SFE_BMP180

{

  public:

      SFE_BMP180(); 

      char begin();

        shorted?)

      

      char startTemperature(void);

        

      char getTemperature(double &T);

        startTemperature command

        

      char startPressure(char oversampling);

        

      char getPressure(double &P, double &T);

        startPressure command        

      double sealevel(double P, double A);

        weather data)

        

      double altitude(double P, double P0);

        sea-level, runway, etc.)

        

      char getError(void);

        

  private:

   

      char readInt(char address, int16_t &value);

        

      char readUInt(char address, uint16_t &value);

       

      char readBytes(unsigned char *values, char length);

        

        

      char writeBytes(unsigned char *values, char length);

        subsequent registers)

        

      int16_t AC1,AC2,AC3,VB1,VB2,MB,MC,MD;

      uint16_t AC4,AC5,AC6; 

      double c5,c6,mc,md,x0,x1,x2,y0,y1,y2,p0,p1,p2;

      char _error;

};

#define BMP180_ADDR 0x77 

#define BMP180_REG_CONTROL 0xF4

#define BMP180_REG_RESULT 0xF6

#define BMP180_COMMAND_TEMPERATURE 0x2E

#define BMP180_COMMAND_PRESSURE0 0x34

#define BMP180_COMMAND_PRESSURE1 0x74

#define BMP180_COMMAND_PRESSURE2 0xB4

#define BMP180_COMMAND_PRESSURE3 0xF4


SFE_BMP180.cp

/*

【Arduino】66种传感器模块系列实验(68)

实验六十八:BMP180 新款 BOSCH温度模块气压传感器(代替BMP085)

SFE_BMP180.cp

*/

#include <SFE_BMP180.h>

#include <Wire.h>

#include <stdio.h>

#include <math.h>

SFE_BMP180::SFE_BMP180()

{

}

char SFE_BMP180::begin()

{

    double c3,c4,b1;


    Wire.begin();

    if (readInt(0xAA,AC1) &&

        readInt(0xAC,AC2) &&

        readInt(0xAE,AC3) &&

        readUInt(0xB0,AC4) &&

        readUInt(0xB2,AC5) &&

        readUInt(0xB4,AC6) &&

        readInt(0xB6,VB1) &&

        readInt(0xB8,VB2) &&

        readInt(0xBA,MB) &&

        readInt(0xBC,MC) &&

        readInt(0xBE,MD))

    {

AC6 = 23153;


Calcs.pdf


25671; AC6 = 18974;

        c3 = 160.0 * pow(2,-15) * AC3;

        c4 = pow(10,-3) * pow(2,-15) * AC4;

        b1 = pow(160,2) * pow(2,-30) * VB1;

        c5 = (pow(2,-15) / 160) * AC5;

        c6 = AC6;

        mc = (pow(2,11) / pow(160,2)) * MC;

        md = MD / 160.0;

        x0 = AC1;

        x1 = 160.0 * pow(2,-13) * AC2;

        x2 = pow(160,2) * pow(2,-25) * VB2;

        y0 = c4 * pow(2,15);

        y1 = c4 * c3;

        y2 = c4 * b1;

        p0 = (3791.0 - 8.0) / 1600.0;

        p1 = 1.0 - 7357.0 * pow(2,-20);

        p2 = 3038.0 * 100.0 * pow(2,-36);

        return(1);

    }

    else

    {


        return(0);

    }

}

char SFE_BMP180::readInt(char address, int16_t &value)

{

    unsigned char data[2];

    data[0] = address;

    if (readBytes(data,2))

    {

        value = (int16_t)((data[0]<<8)|data[1]);


negative

        return(1);

    }

    value = 0;

    return(0);

}

char SFE_BMP180::readUInt(char address, uint16_t &value)

{

    unsigned char data[2];

    data[0] = address;

    if (readBytes(data,2))

    {

        value = (((uint16_t)data[0]<<8)|(uint16_t)data[1]);

        return(1);

    }

    value = 0;

    return(0);

}

char SFE_BMP180::readBytes(unsigned char *values, char length)

{

    char x;

    Wire.beginTransmission(BMP180_ADDR);

    Wire.write(values[0]);

    _error = Wire.endTransmission();

    if (_error == 0)

    {

        Wire.requestFrom(BMP180_ADDR,length);

while(Wire.available() != length) ; 

        for(x=0;x<length;x++)

        {

            values[x] = Wire.read();

        }

        return(1);

    }

    return(0);

}

char SFE_BMP180::writeBytes(unsigned char *values, char length)

{

    char x;


    Wire.beginTransmission(BMP180_ADDR);

    Wire.write(values,length);

    _error = Wire.endTransmission();

    if (_error == 0)

        return(1);

    else

        return(0);

}

char SFE_BMP180::startTemperature(void)

{

    unsigned char data[2], result;


    data[0] = BMP180_REG_CONTROL;

    data[1] = BMP180_COMMAND_TEMPERATURE;

    result = writeBytes(data, 2);

if (result) 

return(5); 

    else

return(0); 

}

char SFE_BMP180::getTemperature(double &T)

{

    unsigned char data[2];

    char result;

    double tu, a;


    data[0] = BMP180_REG_RESULT;

    result = readBytes(data, 2);

if (result) 

    {

        tu = (data[0] * 256.0) + data[1];


        a = c5 * (tu - c6);

        T = a + (mc / (a + md));

    }

    return(result);

}

char SFE_BMP180::startPressure(char oversampling)

{

    unsigned char data[2], result, delay;


    data[0] = BMP180_REG_CONTROL;

    switch (oversampling)

    {

        case 0:

            data[1] = BMP180_COMMAND_PRESSURE0;

            delay = 5;

        break;

        case 1:

            data[1] = BMP180_COMMAND_PRESSURE1;

            delay = 8;

        break;

        case 2:

            data[1] = BMP180_COMMAND_PRESSURE2;

            delay = 14;

        break;

        case 3:

            data[1] = BMP180_COMMAND_PRESSURE3;

            delay = 26;

        break;

        default:

            data[1] = BMP180_COMMAND_PRESSURE0;

            delay = 5;

        break;

    }

    result = writeBytes(data, 2);

    if (result)

return(delay); 

    else

return(0); 

}

char SFE_BMP180::getPressure(double &P, double &T)

sealevel().

{

    unsigned char data[3];

    char result;

    double pu,s,x,y,z;


    data[0] = BMP180_REG_RESULT;

    result = readBytes(data, 3);

if (result) 

    {

        pu = (data[0] * 256.0) + data[1] + (data[2]/256.0);


        s = T - 25.0;

        x = (x2 * pow(s,2)) + (x1 * s) + x0;

        y = (y2 * pow(s,2)) + (y1 * s) + y0;

        z = (pu - x) / y;

        P = (p2 * pow(z,2)) + (p1 * z) + p0;

    }

    return(result);

}

double SFE_BMP180::sealevel(double P, double A)

{

    return(P/pow(1-(A/44330.0),5.255));

}

double SFE_BMP180::altitude(double P, double P0)

{

    return(44330.0*(1-pow(P/P0,1/5.255)));

}

char SFE_BMP180::getError(void)


{

    return(_error);

}

模块接线方式

1.先连接芯片与单片机(通过I2C接口),按照如下方式连接

5V—VIN

GND–GND

A5—SCL

A4—SDA

2.然后UNO通过usb与PC电脑连接

3.拷贝后面的代码烧录进Arduino


实验开源代码

/*

【Arduino】66种传感器模块系列实验(68)

实验六十八:BMP180 新款 BOSCH温度模块气压传感器(代替BMP085)

程序之一

*/

#include <SFE_BMP180.h>

SFE_BMP180 AirPresure;

char presureDelayTime;

double presureP, presureT;

void setup() {

  Serial.begin(9600);

  AirPresure.begin();

}

void loop()

{

  presureDelayTime = AirPresure.startPressure(3);

  if (presureDelayTime != 0)

  {

  delay(presureDelayTime);

  presureDelayTime = AirPresure.getPressure(presureP, presureT);

  if (presureDelayTime != 0)

  {

    

    Serial.print("Current Preasure: ");

    Serial.print(presureP);

    Serial.println(" bar");

    Serial.print(presureP);

    Serial.print(" bar is");

    Serial.print(presureP / 1000.0);

    Serial.println(" atm");

  }

  else

  {

    Serial.println("ERROR");

  }

  }

  else

  {

  Serial.println("ERROR");

  }

  delay(1000);

}



/*

【Arduino】66种传感器模块系列实验(68)

实验六十八:BMP180 新款 BOSCH温度模块气压传感器(代替BMP085)

程序之二,气温、气压与海拔值可以调整并校准

*/

#include <Wire.h>

#define BMP180ADD 0x77   

                      

unsigned char OSS;                   

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;        

float temperature;  

double pressure;  

double pressure2;

long b5;       

double altitude;  

void setup()

{

  Serial.begin(9600);

  Wire.begin();

  OSS = 2;  

  BMP180start();

}

void loop()

{

  calculate();

  show();

  delay(1000);

}

void calculate()

{

  temperature = bmp180GetTemperature(bmp180ReadUT());

  temperature = temperature*0.0137;

  pressure = bmp180GetPressure(bmp180ReadUP());

  pressure2 = pressure/115325;

  pressure2 = pow(pressure2,0.29029496);

  altitude = 39*(1+pressure2);                   

}

void show()

{

  Serial.print("气温: ");

  Serial.print(temperature, 1);                   

  Serial.println(" C");

  Serial.print("气压: ");

  Serial.print(pressure, 0);                     

  Serial.println(" Pa");

  Serial.print("海拔:");

  Serial.print(altitude);

  Serial.println("m");

}

void BMP180start()

{              

  ac1 = bmp180ReadDate(0xAA);              

  ac2 = bmp180ReadDate(0xAC);  

  ac3 = bmp180ReadDate(0xAE);  

  ac4 = bmp180ReadDate(0xB0);  

  ac5 = bmp180ReadDate(0xB2);  

  ac6 = bmp180ReadDate(0xB4);  

  b1  = bmp180ReadDate(0xB6);  

  b2  = bmp180ReadDate(0xB8);  

  mb  = bmp180ReadDate(0xBA);  

  mc  = bmp180ReadDate(0xBC);  

  md  = bmp180ReadDate(0xBE);

}

short bmp180GetTemperature(unsigned int ut)

{

  long x1, x2;

  x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;  

  x2 = ((long)mc << 11)/(x1 + md);           

  b5 = x1 + x2;                        

  return ((b5 + 8)>>4);                  

}

long bmp180GetPressure(unsigned long up)

{

  long x1, x2, x3, b3, b6, p;

  unsigned long b4, b7;

  

  b6 = b5 - 4000;

  x1 = (b2 * (b6 * b6)>>12)>>11;

  x2 = (ac2 * b6)>>11;

  x3 = x1 + x2;

  b3 = (((((long)ac1)*4 + x3)<<OSS) + 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>>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;

  

  return p;

}

int bmp180Read(unsigned char address)

{

  unsigned char data;

  

  Wire.beginTransmission(BMP180ADD);

  Wire.write(address);

  Wire.endTransmission();

  

  Wire.requestFrom(BMP180ADD, 1);

  while(!Wire.available());

   

  return Wire.read();

}

int bmp180ReadDate(unsigned char address)

{

  unsigned char msb, lsb;

  Wire.beginTransmission(BMP180ADD);

  Wire.write(address);

  Wire.endTransmission();

  Wire.requestFrom(BMP180ADD, 2);

  while(Wire.available()<2);

  msb = Wire.read();

  lsb = Wire.read();

  return (int) msb<<8 | lsb;

}

unsigned int bmp180ReadUT()

{

  unsigned int ut;

  Wire.beginTransmission(BMP180ADD);

  Wire.write(0xF4);                

  Wire.write(0x2E);                

  Wire.endTransmission();  

  delay(5);                     

  ut = bmp180ReadDate(0xF6);          

  return ut;

}

unsigned long bmp180ReadUP()

{

  unsigned char msb, lsb, xlsb;

  unsigned long up = 0;

  

  Wire.beginTransmission(BMP180ADD);

  Wire.write(0xF4);                

  Wire.write(0x34 + (OSS<<6));         

  Wire.endTransmission(); 

  delay(2 + (3<<OSS));              

  

  Wire.beginTransmission(BMP180ADD);

  Wire.write(0xF6);                

  Wire.endTransmission();

  

  Wire.requestFrom(BMP180ADD, 3); 

  while(Wire.available() < 3);         

  msb = Wire.read();

  lsb = Wire.read();

  xlsb = Wire.read();

  up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);//16 to 19 bit

  return up;

}



/*

【Arduino】168种传感器模块系列实验(67)

实验六十七:BMP180 新款 BOSCH温度模块气压传感器(代替BMP085)

程序之三,温度、实时气压、已知海拔计算的海平面的气压、已知海平面气压计算的高度

只是算法有点烂,做做实验而已

*/

#include <SFE_BMP180.h> 

#include <Wire.h> 

SFE_BMP180 pressure; 

#define ALTITUDE 255.0 

unsigned long gpstimes;

void setup() 

Serial.begin(9600); 

pressure.begin(); 

void loop() 

gpstimes=millis();

char status; 

double T,P,p0,a; 

status = pressure.startTemperature(); 

delay(status); 

status = pressure.getTemperature(T); 

delay(status); 

Serial.print("temperature: "); 

Serial.print(T,2); 

Serial.println(" deg C, "); 

status = pressure.startPressure(3); 

delay(status); 

status = pressure.getPressure(P,T); 

// Print out the measurement: 

Serial.print("absolute pressure A: "); 

Serial.print(P,2); 

Serial.println(" mb, "); 

p0=1013.2;

a = pressure.altitude(P,p0); 

Serial.print("computed altitude A: "); 

Serial.print(a,0); 

Serial.println(" meters, "); 

T=25.00;

status = pressure.getPressure(P,T); 

Serial.print("absolute pressure B: "); 

Serial.print(P,2); 

Serial.println(" mb, "); 

p0=1013.2;

a = pressure.altitude(P,p0); 

Serial.print("computed altitude B: "); 

Serial.print(a,0); 

Serial.println(" meters, "); 

gpstimes=millis()-gpstimes;

Serial.print("gpstimes="); 

Serial.println(gpstimes); 

Serial.println();

delay(2000); 

}


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271