4. 读取BMP180气压传感器数据

任务说明

本案例使用BMP180数字气压传感器,通过I2C接口读取大气压和温度,并依据气压-高度公式计算当前海拔。BMP180内部集成压力传感器和温度传感器,温度数据用于补偿气压测量,因此两者必须同时读取。最终在终端打印温度、气压和海拔值。

硬件连接

BMP180模块与树莓派的连接方式如下表所示(树莓派I2C引脚为3.3V逻辑,BMP180模块通常已带电平转换,可直接连接):

BMP180引脚树莓派引脚说明
VINPin 1 (3.3V)电源正极
GNDPin 6 (GND)电源地
SCLPin 5 (GPIO3/SCL)I2C时钟
SDAPin 3 (GPIO2/SDA)I2C数据
树莓派 I2C Master Pin1 3.3V Pin6 GND Pin5 SCL Pin3 SDA BMP180 I2C Slave (0x77) VIN GND SCL SDA 3.3V GND SCL (GPIO3) SDA (GPIO2) I2C 设备地址: 0x77

代码实现

以下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

判定标准:

  1. 程序每2秒输出一组数据,格式为“温度: xx.x °C | 气压: xxxxx.x Pa | 海拔: xx.x m”;
  2. 温度值应在当前室温合理范围内(如15~35°C);
  3. 气压值应在正常大气压范围(约95000~105000 Pa);
  4. 海拔值应与实际地理位置大致相符(误差通常不超过±50米,取决于海平面气压设定)。

若输出数值明显异常(如温度-40°C或气压为0),请检查接线和I2C地址是否正确。