4. 读取BMP180气压传感器数据
任务说明
本案例使用BMP180数字气压传感器,通过I2C接口读取大气压和温度,并依据气压-高度公式计算当前海拔。BMP180内部集成压力传感器和温度传感器,温度数据用于补偿气压测量,因此两者必须同时读取。最终在终端打印温度、气压和海拔值。
硬件连接
BMP180模块与树莓派的连接方式如下表所示(树莓派I2C引脚为3.3V逻辑,BMP180模块通常已带电平转换,可直接连接):
| BMP180引脚 | 树莓派引脚 | 说明 |
|---|---|---|
| VIN | Pin 1 (3.3V) | 电源正极 |
| GND | Pin 6 (GND) | 电源地 |
| SCL | Pin 5 (GPIO3/SCL) | I2C时钟 |
| SDA | Pin 3 (GPIO2/SDA) | I2C数据 |
代码实现
以下Python代码直接操作BMP180寄存器,不依赖第三方传感器库,仅使用标准I2C接口。代码包含完整的校准系数读取、温度/气压计算和海拔换算逻辑。
#!/usr/bin/env python3
import smbus
import time
import math
# BMP180 I2C地址
BMP180_ADDR = 0x77
# 寄存器地址
REG_AC1_H = 0xAA
REG_CTRL_MEAS = 0xF4
REG_ADC_OUT_MSB = 0xF6
REG_SCO = 0x20 # 温度转换
REG_SCO_P = 0x34 # 气压转换(oss=0)
# 初始化I2C总线(树莓派I2C总线号为1)
bus = smbus.SMBus(1)
# 读取16位有符号校准系数
def read_s16(reg):
val = bus.read_i2c_block_data(BMP180_ADDR, reg, 2)
return (val[0] << 8 | val[1]) - 65536 if (val[0] & 0x80) else (val[0] << 8 | val[1])
# 读取16位无符号校准系数
def read_u16(reg):
val = bus.read_i2c_block_data(BMP180_ADDR, reg, 2)
return (val[0] << 8 | val[1])
# 读取校准数据
AC1 = read_s16(0xAA)
AC2 = read_s16(0xAC)
AC3 = read_s16(0xAE)
AC4 = read_u16(0xB0)
AC5 = read_u16(0xB2)
AC6 = read_u16(0xB4)
B1 = read_s16(0xB6)
B2 = read_s16(0xB8)
MB = read_s16(0xBA)
MC = read_s16(0xBC)
MD = read_s16(0xBE)
def read_temperature():
"""读取原始温度并计算实际温度(摄氏度)"""
bus.write_byte_data(BMP180_ADDR, REG_CTRL_MEAS, REG_SCO)
time.sleep(0.005)
msb = bus.read_byte_data(BMP180_ADDR, 0xF6)
lsb = bus.read_byte_data(BMP180_ADDR, 0xF7)
UT = (msb << 8) | lsb
# 温度补偿计算
X1 = ((UT - AC6) * AC5) >> 15
X2 = (MC << 11) // (X1 + MD)
B5 = X1 + X2
T = (B5 + 8) >> 4
return T / 10.0
def read_pressure():
"""读取原始气压并计算实际气压(Pa)"""
# 先读取温度以获得B5值
bus.write_byte_data(BMP180_ADDR, REG_CTRL_MEAS, REG_SCO)
time.sleep(0.005)
msb = bus.read_byte_data(BMP180_ADDR, 0xF6)
lsb = bus.read_byte_data(BMP180_ADDR, 0xF7)
UT = (msb << 8) | lsb
X1 = ((UT - AC6) * AC5) >> 15
X2 = (MC << 11) // (X1 + MD)
B5 = X1 + X2
# 读取气压原始值(oss=0)
bus.write_byte_data(BMP180_ADDR, REG_CTRL_MEAS, REG_SCO_P)
time.sleep(0.005)
msb = bus.read_byte_data(BMP180_ADDR, 0xF6)
lsb = bus.read_byte_data(BMP180_ADDR, 0xF7)
UP = (msb << 8) | lsb
# 气压补偿计算
B6 = B5 - 4000
X1 = (B2 * (B6 * B6 >> 12)) >> 11
X2 = (AC2 * B6) >> 11
X3 = X1 + X2
B3 = (((AC1 * 4 + X3) << 0) + 2) >> 2
X1 = (AC3 * B6) >> 13
X2 = (B1 * ((B6 * B6) >> 12)) >> 16
X3 = ((X1 + X2) + 2) >> 2
B4 = (AC4 * (X3 + 32768)) >> 15
B7 = (UP - B3) * (50000 >> 0)
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
P = P + ((X1 + X2 + 3791) >> 4)
return P
def calculate_altitude(pressure, sea_level_pressure=101325):
"""根据气压计算海拔(米),sea_level_pressure为海平面标准气压"""
return 44330 * (1 - (pressure / sea_level_pressure) ** (1/5.255))
if __name__ == "__main__":
try:
while True:
temp = read_temperature()
press = read_pressure()
alt = calculate_altitude(press)
print(f"温度: {temp:.1f} °C | 气压: {press:.1f} Pa | 海拔: {alt:.1f} m")
time.sleep(2)
except KeyboardInterrupt:
print("\n程序已停止")
运行与验证
前置条件:树莓派已启用I2C接口(sudo raspi-config → Interface Options → I2C → Enable),并安装smbus库:
sudo apt-get install python3-smbus i2c-tools
验证I2C设备:
i2cdetect -y 1
应看到地址0x77对应的设备编号,确认BMP180已正确连接。
运行程序:
python3 bmp180_read.py
判定标准:
- 程序每2秒输出一组数据,格式为“温度: xx.x °C | 气压: xxxxx.x Pa | 海拔: xx.x m”;
- 温度值应在当前室温合理范围内(如15~35°C);
- 气压值应在正常大气压范围(约95000~105000 Pa);
- 海拔值应与实际地理位置大致相符(误差通常不超过±50米,取决于海平面气压设定)。
若输出数值明显异常(如温度-40°C或气压为0),请检查接线和I2C地址是否正确。