气压传感器BMP180的简单应用
BMP180是一款高精度、小体积、超低能耗的压力传感器,可以应用在移动设备中。它的性能卓越,绝对精度最低可以达到0.03hPa,并且耗电极低,只有3μA。BMP180采用强大的8-pin陶瓷无引线芯片承载(LCC)超薄封装,可以通过I2C总线直接与各种微处理器相连。今天主要讲了气压传感器BMP180的简单应用。
文章目录
一、BMP180
1.介绍
BMP180是一款高精度、小体积、超低能耗的压力传感器,可以应用在移动设备中。它的性能卓越,绝对精度最低可以达到0.03hPa,并且耗电极低,只有3μA。BMP180采用强大的8-pin陶瓷无引线芯片承载(LCC)超薄封装,可以通过I2C总线直接与各种微处理器相连。
2.主要特点:
- 压力范围:300-1100hPa(海拔9000米~-500米)
- 电源电压:1.8V-3.6V(VDDA),1.62V~3.6V(VDDD)
- LCC8封装:无铅陶瓷载体封装(LCC)
- 尺寸:3.6mmx3.8x0.93mm
- 低功耗:5μA,在标准模式
- 高精度:低功耗模式下,分辨率为0.06hPa(0.5米)
- 高线性模式下,分辨率为0.03hPa(0.25米)
- 含温度输出
- I2C接口
- 温度补偿
- 无铅,符合RoHS规范
- MSL 1反应时间:7.5ms
- 待机电流:0.1μA
- 无需外部时钟电路
3. 典型应用:
- GPS精确导航(航位推算,上下桥检测等)
- 室内室外导航
- 休闲、体育和医疗健康等监测
- 天气预报
- 垂直速度指示(上升/下沉速度)
- 风扇功率控制
4. 原理图
从原理图可以看出,SCL和SDA是I2C总线的通信引脚,VDD和GND用来接电源的正负极,接3.3V即可。
5. 典型应用电路
BMP180的压力和温度数据,必须通过传感器的校准数据进行补偿计算,校准数据可以通过读取其内部的EEPROM存储器来获取。
BMP180由一个压阻传感器、一个模数转换器和一个控制单元组成与E2PROM和串行I2C接口。如下图所示:
6. 测量流程
7. 工作模式
它有4钟工作模式,由过采样率(OSRS)表示,其实就是最大转换时间的不同,如
- 超低功耗(ultra low power)= 0,最大转换时间为4.5ms;
- 标准(standard) = 1,最大转换时间为7.5ms;
- 高精度(high)= 2,最大转换时间为13.5ms;
- 超高精度(ultra high resolution))= 3,最大转换时间为25.5ms。
二、软件
以下代码来自野火–F407_霸天虎开发板。
1.初始化
BMP180的从机地址为0x77
示例代码如下:
#define BMP180_I2C_ADDR 0x77
#define BMP180_PROM_START__ADDR 0xaa
#define BMP180_PROM_DATA__LEN 22
/**
* @brief 初始化,获取校准参数
* @note 在第一次转换前要先调用这个函数,然后用于真实值计算
*/
static void bmp180Init(void)
{
uint8_t data[22];
/* 从器件中读取22个校准数据 */
i2cRead(BMP180_I2C_ADDR, BMP180_PROM_START__ADDR, BMP180_PROM_DATA__LEN, data);
/*parameters AC1-AC6*/
calParam.ac1 = (data[0] << 8) | data[1];
calParam.ac2 = (data[2] << 8) | data[3];
calParam.ac3 = (data[4] << 8) | data[5];
calParam.ac4 = (data[6] << 8) | data[7];
calParam.ac5 = (data[8] << 8) | data[9];
calParam.ac6 = (data[10] << 8) | data[11];
/*parameters B1,B2*/
calParam.b1 = (data[12] << 8) | data[13];
calParam.b2 = (data[14] << 8) | data[15];
/*parameters MB,MC,MD*/
calParam.mb = (data[16] << 8) | data[17];
calParam.mc = (data[18] << 8) | data[19];
calParam.md = (data[20] << 8) | data[21];
}
2.获取原始温度
要获得温度数据,必须先向控制寄存器(地址0xF4)写0x2E,然后等待至少4.5ms,才可以从地址0xF6和0xF7读取十六位的温度数据。
#define BMP180_I2C_ADDR 0x77
#define BMP180_T_MEASURE 0x2E // temperature measurent
#define BMP180_CTRL_MEAS_REG 0xF4
#define BMP180_ADC_OUT_MSB_REG 0xF6
/**
* @brief 获取未偏移的原始温度数据,需要等待4.5ms才转换完成
* @note 本函数要被循环调用
* 用到了systick的millis函数获取时间。
* @retval convDone: ture:转换完成 _FAIL:转换未完成
*/
static uint8_t bmp180GetUT(void)
{
uint8_t data[2];
static uint8_t convDone = _FAIL; //静态变量,用于标志是否转换完成
static uint32_t convTime=0; //静态变量,用于记录开始转换用了多长时间
if(convTime==0) //第一次调用本函数
{
convDone = _FAIL; //重置标志位
i2cWrite(BMP180_I2C_ADDR, BMP180_CTRL_MEAS_REG, BMP180_T_MEASURE); //控制开始转换温度
convTime= millis(); //记录开始转换时刻
}
if((millis()-convTime) > 5) //温度转换需要4.5ms
{
i2cRead(BMP180_I2C_ADDR, BMP180_ADC_OUT_MSB_REG, 2, data); //读取温度转换的数据
bmp180Val.ut = (data[0] << 8) | data[1]; //温度数据格式
convDone = _SUCCESS; //转换完成标志
convTime = 0; //重置转换时间
}
return convDone;
}
3.获取真实温度
/**
* @brief 计算真实温度值
* @note datasheet有公式
* @param ut:未偏移的原始温度数据,由bmp180_get_ut 函数得到
* @retval temperature:真实的温度值,单位:0.1摄氏度
*/
static void bmp180CalTemperature(void)
{
int16_t temperature;
int32_t x1, x2;
/* 根据转换公式计算参数 */
x1 = (((int32_t) bmp180Val.ut - (int32_t) calParam.ac6) * (int32_t) calParam.ac5) >> 15;
x2 = ((int32_t) calParam.mc << 11) / (x1 + calParam.md);
bmp180Val.paramB5 = x1 + x2;
/* 计算真实温度值 */
temperature = (( bmp180Val.paramB5 + 8) >> 4); // 温度值单位: 0.1 C
bmp180Val.temperature = temperature; //计算完才赋值,减少上层函数调用get时,交给上层中间数据的概率
}
4.获取原始气压
要获得气压数据,必须先向控制寄存器(地址0xF4)写0x34(0x74、0xB4、0xF4),然后等待至少4.5ms,才可以从地址0xF6和0xF6读取16位的气压数据。
#define BMP180_I2C_ADDR 0x77
#define BMP180_P_MEASURE 0x34 // pressure measurement
#define BMP180_CTRL_MEAS_REG 0xF4
#define BMP180_ADC_OUT_MSB_REG 0xF6
/**
* @brief 获取未偏移的原始压力数据
* @note 获取压力前调用,等待时间:
* 模式0,4.5ms 模式1,7.5ms 模式2,13.5ms 模式3,25.5ms
* 用到了systick的millis函数获取时间。
* 本函数要被循环调用
* @retval convDone: ture:转换完成 _FAIL:转换未完成
*/
static uint8_t bmp180GetUP(void)
{
uint8_t data[3];
//uint8_t ctrl=0x0f;
static uint8_t convDone = _FAIL; //静态变量,用于标志是否转换完成
static uint32_t convTime = 0; //静态变量,用于记录开始转换用了多长时间
if(convTime == 0) //第一次调用本函数
{
convDone = _FAIL; //重置标志位 BMP180_CTRL_MEAS_REG
i2cWrite(BMP180_I2C_ADDR,BMP180_CTRL_MEAS_REG ,(BMP180_P_MEASURE + (OSS<< 6))); //开始压力转换
convTime = millis(); //记录开始转换时刻
}
if((millis()-convTime) > OSS_TIME) //判断是否转换完成
{
i2cRead(BMP180_I2C_ADDR, BMP180_ADC_OUT_MSB_REG, 3, data);
bmp180Val.up = (((uint32_t) data[0] << 16) | ((uint32_t) data[1] << 8) | (uint32_t) data[2]) >> (8 - OSS);
convDone = _SUCCESS; //转换完成标志
convTime = 0; //重置转换时间
}
return convDone;
}
5.获取真实气压
/**
* @brief 计算真实压力数据
* @note datasheet有公式
* @param up:未偏移的原始压力数据,由bmp180GetUp函数得到
* @retval pressure:真实的压力值,单位:Pa
*/
static void bmp180CalPressure(void)
{
int32_t pressure,x1, x2, x3, b3, b6;
uint32_t b4, b7;
/* 根据公式计算参数 */
b6 = bmp180Val.paramB5 - 4000;
// *****calculate B3************
x1 = (b6 * b6) >> 12;
x1 *= calParam.b2;
x1 >>= 11;
x2 = (calParam.ac2 * b6);
x2 >>= 11;
x3 = x1 + x2;
b3 = (((((int32_t)calParam.ac1) * 4 + x3) << OSS) + 2) >> 2;
// *****calculate B4************
x1 = (calParam.ac3 * b6) >> 13;
x2 = (calParam.b1 * ((b6 * b6) >> 12) ) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (calParam.ac4 * (uint32_t) (x3 + 32768)) >> 15;
b7 = ((uint32_t)(bmp180Val.up - b3) * (50000 >> OSS));
if (b7 < 0x80000000)
{
pressure = (b7 << 1) / b4;
}
else
{
pressure = (b7 / b4) << 1;
}
x1 = pressure >> 8;
x1 *= x1;
x1 = (x1 * SMD500_PARAM_MG) >> 16;
x2 = (pressure * SMD500_PARAM_MH) >> 16;
/* 计算真实压力值 */
pressure += (x1 + x2 + SMD500_PARAM_MI) >> 4; // 压力值单位: Pa
bmp180Val.pressure = pressure; //计算完才赋值,减少错误地把中间数据交给上层的概率 (上层使用get函数获取数据)
}
6.海拔高度的换算
BMP180传感器提供温度和压力的绝对测量值,但不提供海拔高度的直接输出。
由于大气压力随高度升高而降低。
由上图我们可知,气压与海平面的高度具有近似线性的反比,因此如果我们测量了某地的气压,我们可以使用简单的数学运算从海平面计算海拔高度。
/**
* @brief 更新气压、温度计数据
* @note 本函数要被循环调用,整个转换时间30ms
* @param tempData,温度数据指针,若数据更新了,本函数会把tempData的isNew标志置1
* @retval
*/
static void bmp180TempUpdate(SENSOR_DATA_T *tempData)
{
static uint8_t state = 0;
isNew = tempData ->isNew; //isNew静态变量用来同步tempData的isNew变量
//isNew静态变量同步得的信息在后面会在presUpdate和altiUpdate函数使用
switch(state)
{
case 0:
if(bmp180GetUT() == _SUCCESS) //温度转换
state++; //温度转换完成,进入压力转换状态
break;
case 1:
if(bmp180GetUP() == _SUCCESS) //压力转换
state++; //压力转换完成,开始真实值计算
break;
case 2:
bmp180CalTemperature(); //真实值计算
bmp180CalPressure();
bmp180Val.altitude = (1.0f - pow(bmp180Val.pressure / 101325.0f, 0.190295f)) * 44330.0f;
//根据压力值计算海拔高度公式由datasheet而来, 单位为:米 //公式中的1hPa=0.01Pa,由传感器算出的压力值单位为Pa,代码这里在使用datasheet的公式时化了单位
tempData->isNew = isNew = _SUCCESS ; //更新数据状态
state = 0;
break;
}
}
通过当地的气象服务中可以得到海平面压力P0,利用传感器读取的压力P和该海平面压力P0的值,通过上面的公式可以计算传感器所在位置的高度。
注意:海平面压力P0的值不是固定的,跟所属区域及环境温度和天气情况的变化而变化。
三、总结
今天主要讲了气压传感器BMP180的简单应用。
感谢你的观看!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)