1、在测量海拔高度时,传统的做法是通过测量某一高度的大气压力,再经过换算才能得到高度数据。为了测量大气压力,就得用上气压传感器。BMP180不仅可以实时的测量大气压力,还能测量实时温度。同时它还具有IIC总线的接口,便于单片机进行访问。另外它的使用也很方便,不需要太多的操作就可读取到气压及测量数据。
2、BMP180的工作电压为1.8v~3.6v,典型工作电压为2.5v,其与单片机相连的典型电路如下图所示:
3、 从上图可看出,BMP180内包含有电阻式压力传感器、AD转换器和控制单元,其中控制单元包括了EEPROM和IIC接口。读取BMP180时会直接传送没有经过补偿的温度值和压力值。而在EEPROM中则储存了176位单独的校准数据,这些数据将对读取的温度压力值进行补偿。176位的EEPROM被划分为11个字,每个字16位,这样就包含有11个校准系数。每个器件模块都有自己单独的校准系数,在每一次计算温度压力数据之前,单片机就应该先读出EEPROM中这些校准数据,然后再开始采集数据温度和压力数据。和所有的IIC总线器件一样,BMP180也有一个器件的固定地址,根据其数据手册,出厂时默认BMP180的从机地址为0xEE(写入方向),或0xEF(读出方向)。温度数据UT和压力数据UP都存储在寄存器的第0到15位之中,压力数据UP的精度还可扩展至16~19位。
下面是11个校准参数及地址:
读取温度和气压的寄存器地址及等待时间(osrs:采样分辨率):
从图中可以看出,要获得温度数据,必须先向控制寄存器(地址0xF4)写0x2E,然后等待至少4.5ms,才可以从地址0xF6和0xF7读取十六位的温度数据。同样,要获得气压数据,必须先向控制寄存器(地址0xF4)写0x34(0x74、0xB4、0xF4),然后等待至少4.5ms,才可以从地址0xF6和0xF7读取16位的气压数据。
4、读取气压大致流程为:开始 →读取EEPROM校准值 → 读取温度值 → 读取气压值 → 校准
查看传感器手册可知,流程如下:
海拔计算方法:
P:大气压强 P0:水平面参考压强(例:1013.25hPa)
5、 Sensor_Pressure.c
#include "sensor_pressure.h"
// 定义存取EEPROM校准值的变量
static short ac1;
static short ac2;
static short ac3;
static unsigned short ac4;
static unsigned short ac5;
static unsigned short ac6;
static short b1;
static short b2;
static short mb;
static short mc;
static short md;
// 从气压传感器读取值
bool BMP180_Multiple_Read(uint16_t REG_Address, uint16_t *ReadData)
{
uint8_t REG_Data[2];
uint8_t status;
status = I2C2_Read_NByte(BMP180_SlaveAddress, REG_Address, REG_Data, 2);
*ReadData = (uint16_t)REG_Data[0]<<8 | (uint16_t)REG_Data[1];
return status ;
}
// 读取温度值
bool BMP180_ReadTemp(uint16_t * temp)
{
uint8_t value = BMP_COVERT_TEMP;
I2C2_Write_NByte(BMP180_SlaveAddress, CONTROL_REG_ADDR, &value, 1);
SYSTICK_DelayMs(5);
return BMP180_Multiple_Read(BMP_OUT_MSB, temp);
}
// 读取气压值
bool BMP180_ReadPressure(uint32_t * pressure)
{
uint8_t status;
uint8_t REG_Data[3];
uint8_t value = BMP_COVERT_PRES;
I2C2_Write_NByte(BMP180_SlaveAddress, CONTROL_REG_ADDR, &value, 1);
SYSTICK_DelayMs(OSS_TIME_MS);
// 测量完成 读取传感器测出的值
status = I2C2_Read_NByte(BMP180_SlaveAddress, BMP_OUT_MSB, REG_Data, 3);
*pressure = ((uint32_t)REG_Data[0] << 16 | (uint32_t)REG_Data[1] <<8 | (uint32_t)REG_Data[2]) >> (8 - OSS);
return status;
}
// 传感器初始化并读取EEPROM值
void BMP180_Init(void)
{
I2C2_Hard_Init();
BMP180_Multiple_Read( BMP_AC1_ADDR, (uint16_t *)&ac1 );
BMP180_Multiple_Read( BMP_AC2_ADDR, (uint16_t *)&ac2 );
BMP180_Multiple_Read( BMP_AC3_ADDR, (uint16_t *)&ac3 );
BMP180_Multiple_Read( BMP_AC4_ADDR, (uint16_t *)&ac4 );
BMP180_Multiple_Read( BMP_AC5_ADDR, (uint16_t *)&ac5 );
BMP180_Multiple_Read( BMP_AC6_ADDR, (uint16_t *)&ac6 );
BMP180_Multiple_Read( BMP_B1_ADDR, (uint16_t *)&b1 );
BMP180_Multiple_Read( BMP_B2_ADDR, (uint16_t *)&b2 );
BMP180_Multiple_Read( BMP_MB_ADDR, (uint16_t *)&mb );
BMP180_Multiple_Read( BMP_MC_ADDR, (uint16_t *)&mc );
BMP180_Multiple_Read( BMP_MD_ADDR, (uint16_t *)&md );
}
// 校准温度和气压
void BMP180Convert(float *temperature, long *pressure)
{
uint16_t ut;
uint32_t up;
bool temp_state , pressure_state;
long x1, x2, b5, b6, x3, b3, p;
unsigned long b4, b7;
temp_state = BMP180_ReadTemp(&ut);
pressure_state = BMP180_ReadPressure(&up);
if(temp_state == 0 && pressure_state == 0)
{
// 计算温度
x1 = ((long)ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
*temperature = ((b5 + 8) >> 4) * 0.1f;
// 计算气压
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 * 2) / b4 ;
else
p = (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
* pressure = p + ((x1 + x2 + 3791) >> 4);
}
}
// 计算海拔
void BMP180_Altitude(float *temperature, long *pressure, float *altitide)
{
BMP180Convert(temperature, pressure); // 计算出压强
*altitide = 44330*(1 - pow((*pressure)/ PRESSURE_OF_SEA, 1.0f / 5.255f));
}
6、Sensor_Pressure.h
#ifndef _SENSOR_PRESSURE_H_
#define _SENSOR_PRESSURE_H_
#include "stm32f0xx.h"
#include <stdbool.h>
#include <math.h>
#include "bsp_systick.h"
#include "bsp_hard_i2c.h"
#define BMP180_SlaveAddress 0xEE // 定义器件在IIC总线中的从地址
#define BMP_AC1_ADDR 0xAA // 定义校准寄存器的地址
#define BMP_AC2_ADDR 0xAC
#define BMP_AC3_ADDR 0xAE
#define BMP_AC4_ADDR 0xB0
#define BMP_AC5_ADDR 0xB2
#define BMP_AC6_ADDR 0xB4
#define BMP_B1_ADDR 0xB6
#define BMP_B2_ADDR 0xB8
#define BMP_MB_ADDR 0xBA
#define BMP_MC_ADDR 0xBC
#define BMP_MD_ADDR 0xBE
#define CONTROL_REG_ADDR 0xF4 // 控制寄存器,在这个寄存器中设置不同的值可以设置不同转换时间,同时不同的值可以确认转换大气压或者温度
#define BMP_COVERT_TEMP 0x2E // 转换温度 4.5MS
#define BMP_COVERT_PRES_0 0x34 // 转换大气压 4.5ms
#define BMP_COVERT_PRES_1 0x74 // 转换大气压 7.5ms
#define BMP_COVERT_PRES_2 0xB4 // 转换大气压 13.5ms
#define BMP_COVERT_PRES_3 0xF4 // 转换大气压 25.5ms
#define BMP_OUT_MSB 0xF6 // ADC输出高8位
#define BMP_OUT_LSB 0xF7 // ADC输出低8位
#define BMP_OUT_XLSB 0xF8 // 19位测量时,ADC输出最低3位
#define OSS_TIME_MS 26 // 时间间隔
#define BMP_COVERT_PRES BMP_COVERT_PRES_3 // 大气压转换用时
#define OSS 3 // 大气压转换时间
#define PRESSURE_OF_SEA 101325.0f // 参考海平面压强
bool BMP180_Multiple_Read(uint16_t REG_Address , uint16_t *ReadData);
bool BMP180_ReadTemp(uint16_t * temp);
bool BMP180_ReadPressure(uint32_t * pressure);
void BMP180_Init(void);
void BMP180Convert(float *temperature, long *pressure);
void BMP180_Altitude(float *temperature, long *pressure, float *altitide);
#endif
7、main.c
float temp;
long pressure;
float altitude;
int main()
{
SYSTICK_Init(1); // 滴答定时器初始化
BMP180_Init(); // BMP180传感器初始化
USART1_Init(); // 串口初始化
while(1)
{
BMP180Convert(&temp,&pressure); // 测量温度和大气压
BMP180_Altitude(&temp, &pressure, &altitude); // 计算海拔
printf("Temperature is: %.1f Pressure is: %ld Altitude is:%f\r\n", temp, pressure, altitude);
SYSTICK_DelayMs(50);
}
}
I2C通讯请参考:https://blog.csdn.net/qq_41422043/article/details/99688484
参考资料:https://wenku.baidu.com/view/82a146072f60ddccdb38a011.html