zl程序教程

您现在的位置是:首页 >  APP

当前栏目

一起玩转树莓派(17)——BMP180数字压力传感器应用

2023-02-26 10:19:11 时间

一起玩转树莓派(17)——BMP180数字压力传感器应用

一.BMP180使用说明

BMP180是一款高级的温度气压传感器,通过测量的气压值也可以计算出当前海拔高度。其压力测量范围为300-1100hPa,对应的海拔高度为正9000m-负500m。工作电压在1.8V到3.6V之间。体积小,精度高,采用I2C接口,使用非常方便。BMP180传感器在GPS导航,天气检测,海拔测量和垂直方向速度检测等方面有广泛的应用。本实验,我们尝试使用树莓派的I2C接口来读取BMP180的温度和气压值,并进行海拔高度的计算。

相对于本系列博客前面传感器实验案例,BMP180的使用略微复杂。在编写一款传感器的驱动代码之前,首先需要阅读对应的芯片手册。BMP180数据手册可以在如下地址找到,此手册有详细的BMP180的使用方法及温度气压数值的计算公式。

(福利推荐:阿里云、腾讯云、华为云服务器最新限时优惠活动,云服务器1核2G仅88元/年、2核4G仅698元/3年,点击这里立即抢购>>>

https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/RaspberryPi_I2C/files/BST-BMP180-DS000-09.pdf

本次实验使用的BMP180传感器元件如下图所示:

一起玩转树莓派(17)——BMP180数字压力传感器应用

可以看到此元件有5个引脚,其中VCC引脚可以不做使用,SCL和SDA引脚是I2C总线通信引脚,3.3和GND用来接电源正负极。

1.1 使用校准数据对温度和气压进行补偿校准

BMP180的压力和温度数据,必须通过传感器的校准数据进行补偿计算,校准数据可以通过读取其内部EEPROM存储器来获取,EEPROM (Electrically Erasable Programmable read only memory)又称为E2PROM,即带电可擦可编程只读存储器,等下我们会介绍校准数据的读取方法。

BMP180除了拥有压力温度物理传感器外,还包含E2PROM存储模块,ADC模数转换模块和控制单元等,核心电路图如下:

一起玩转树莓派(17)——BMP180数字压力传感器应用

E2PROM存储器中共存储176位数据,这176位数据被分为11个字,即11个校准系数,每个校准系数为2个字节16位数据。在计算温度和气压之前,需要先将这11个校准系数获取到,下图列出了使用I2C访问的寄存器地址:

一起玩转树莓派(17)——BMP180数字压力传感器应用

需要注意,在这11个校准系数中,AC4,AC5和AC6这3个是无符号整数,其他的都是有符号的整数,对于有符号的整数,寄存器中本身存储的是补码,我们需要将其转换成原码数据。示例代码如下:

#coding:utf-8 import smbus  # 定义BMP180设备地址 deviceAddress = 0x77  # 有符号数的补码转换 def getInt(data):     r = data     # 第1位为1表示是负数      # 对负数的补码再取补码即可得到源码     if (data & 0x8000) != 0:         d = data ^ 0xffff         d = d + 1         r = -d     return r  # 封装的获取E2PROM存储器中数据的方法 # sign参数表示是否是有符号数 def readCalibrate(adrList, index, sign):     value = (adrList[index] << 8) + adrList[index + 1]     if sign:         return getInt(value)          else:         return value  # 获取E2PROM存储其的数据 # read_i2c_block_data为i2C读取一块数据的方法,第2个参数为寄存器地址,第3个参数为读取的字节数 calibrationList = bus.read_i2c_block_data(deviceAddress, 0xAA, 22)  # 获取需要的校准系数 AC1 = readCalibrate(calibrationList, 0, True) AC2 = readCalibrate(calibrationList, 2, True) AC3 = readCalibrate(calibrationList, 4, True) AC4 = readCalibrate(calibrationList, 6, False) AC5 = readCalibrate(calibrationList, 8, False) AC6 = readCalibrate(calibrationList, 10, False) B1 = readCalibrate(calibrationList, 12, True)     B2 = readCalibrate(calibrationList, 14, True) MB = readCalibrate(calibrationList, 16, True) MC = readCalibrate(calibrationList, 18, True) MD = readCalibrate(calibrationList, 20, True)

上面代码中deviceAddress为BMP180连接上I2C总线后的设备地址,后面在连线时,我们再介绍如何得到。read_i2c_block_data函数用来读取一块数据,从芯片手册可知,E2PROM存储器数据地址的起始是0xAA,且是连续的,我们直接将22个字节全部读出即可。

1.2 测量温度与压力数值

BMP180对温度和压力的测量逻辑非常简单,先发出测量指令,之后等待一定的数据转换时间,之后即可直接通过I2C总线来读取测量数据。测量流程如下:

一起玩转树莓派(17)——BMP180数字压力传感器应用

在上面的流程图中可以看到,发送测量温度指令后,等待4.5ms后即可读取温度数据,之后发送测量压力指令,等待一段时间后,即可获取压力数据,拿到原始的数据后通过一定的计算方式,即可算出最终的物理量。需要注意,测量压力所需要等待的转换时间与采样精度有关。

通过选择不同的采样精度,我们可以让BMP180工作在最适合的场景中,即实现功耗,性能和测量速度的按需调整。采样精度模式可选的有如下几种:

一起玩转树莓派(17)——BMP180数字压力传感器应用

可以看到,功耗越低的模式(Mode),采样数越少(Internal number of samples),转换速度越快(Conversion time),噪声越大(RMS noise),精度越差。功耗的配置参数由oversampling_setting决定,后面我们会用到它。

1.3 计算温度和压力数据的全过程

现在,我们已经了解了BMP180的一些使用细节,只需要按照芯片手册的步骤来测量和计算即可得到物理数据。完整的过程下图所示:

一起玩转树莓派(17)——BMP180数字压力传感器应用

可以看到,上面流程图从Start开始后,一共有6个需要做的步骤,其中最后一步是展示数据,我们可以省略掉,还剩下5个核心步骤。

第一步:读取校准系数数据

这一步前面我们已经完成。

第二步:读取尚未进行补偿运算的温度数值

首先通过I2C总线向地位为0xF4的寄存器写入0x2E的指令数据,等待4.5ms后,0xF6(MSB)和0xF7(LSB)寄存器的值,最终计算出未补偿的温度数值为:

UT = MSB << 8 + LSB

示例代码如下:

#coding:utf-8 import smbus import time  # 定义BMP180设备地址 deviceAddress = 0x77  # 通过I2C读取设备某个寄存器的数据 # regAdr 寄存器地址 def readByte(device, regAdr):     return bus.read_byte_data(device, regAdr)  # 读取一个字的数据 def readWord(device, regAdr):     high = bus.read_byte_data(device, regAdr)     low = bus.read_byte_data(device, regAdr + 1)     res = (high << 8) + low     return res  # 写入一个字节的数据 def writeByte(device, regAdr, data):     bus.write_byte_data(device, regAdr, data)  # 有符号数的补码转换 def getInt(data):     r = data     # 第1位为1表示是负数      # 对负数的补码再取补码即可得到源码     if (data & 0x8000) != 0:         d = data ^ 0xffff         d = d + 1         r = -d     return r  # 获取原始的温度数据(未补偿) def getTemperature():     # 写入指令     writeByte(deviceAddress, 0xF4, 0x2E)     # 等待温度数据转换     time.sleep(0.005)      # 读取的数据为有符号数     value = readWord(deviceAddress, 0xF6)     # 符号处理     return getInt(value)

第三步:获取未补偿的压力数据

与获取温度的原始数据类似,首先向0xF4寄存器写入数据0x34+(oss<<6),其中参数oss即为software_oversampling_setting,即我们前面提到的采样精度参数,根据需要选择即可。之后等待一定的转换时间,此时间与oss参数的选择有关,上面表中已经列出。再读取0xF6(MSB),0xF7(LSB)和0xF8(XLSB)的数据,最后使用如下计算方式得到原始压力数据:

UP =  (MSB<<16 + LSB<<8 + XLSB) >> (8 – oss)

示例代码如下:

# 定义采样精度,这里取超高分辨率 OSS = 3  # 获取原始的压力数据 (未补偿) def getPressure():     # 写入指令     writeByte(deviceAddress, 0xF4, 0x34 + (OSS << 6))     time.sleep(0.026)     MSB = readByte(deviceAddress, 0xF6)     LSB = readByte(deviceAddress, 0xF7)     XLSB = readByte(deviceAddress, 0xF8)     value = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - OSS)     return value 

第四步:计算真实的物理温度值

使用如下公式计算真正的物理温度值:

X1 = (UT – AC6) * AC5 / (2^15)

X2 = MC * (2^11) / (X1 + MD)

B5 = X1 + X2

T = (B5 + 8) / (2^4)

示例代码如下:

import math # 计算真实的温度 def calculateTemperature(data):     X1 = ((data - AC6) * AC5) / math.pow(2, 15)     X2 = (MC * math.pow(2, 11)) / (X1 + MD)     B5 = X1 + X2      T = (B5 + 8) / math.pow(2, 4)     return T / 10.0

需要注意,最终计算的到的温度数值为0.1摄氏度单位,转换成摄氏度直接除以10即可。

第5步:计算真实的物理气压值

其他数据的计算相对复杂,公式如下:

B6 = B5 – 4000

X1 = (B2 (B6 B6 / 2^12)) / 2^11

X2 = AC2 * B6 / 2^11

X3 = X1 + X2

B3 = (((AC1 * 4 + X3) << OSS) + 2) / 4

X1 = AC3 * B6 / 2^13

X2 = (B1 (B6 B6 / 2^12)) / 2^16

X3 = ((X1 + X2) + 2) /2 ^2

B4 = AC4 *(UNSIGNED LONG)(X3 + 32768) / 2^15

B7 = ((UNSIGNED LONG)UP – B3) * (50000 >> OSS)

如果B7小于0x80000000,则 P = (B7 2) / B4 否则 P = (B7 / B4) 2

X1 = (P / 2^8) * (P / 2^8)

X2 = (-7357 * P) / 2^16

P = P + (X1 + X2 + 3791) / 2^4

示例代码如下:

# 计算真实的气压 def calculatePressure(temp, data):     X1 = ((temp - AC6) * AC5) / math.pow(2, 15)     X2 = (MC * math.pow(2, 11)) / (X1 + MD)     B5 = X1 + X2      B6 = B5 - 4000     X1 = (B2 * (B6 * B6 >> 12)) >> 11     X2 = AC2 * B6 >> 11     X3 = X1 + X2      B3 = (((AC1 * 4 + X3) << OSS) + 2) >> 2     X1 = (AC3 * B6) >> 13     X2 = (B1 * (B6 * B6 >> 12)) >> 16     X3 = ((X1 + X2) + 2) >> 2     B4 = AC4 * (X3 + 32768) >> 15     B7 = (data - 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     P = P + ((X1 + X2 + 3791) >> 4)     # 单位为Pa 转换为hPa除以100即可     return P /100.0

二. 实验-使用BMP180测量温度、气压和海拔高度

通过前面的介绍,一些核心的功能代码我们其实都已经实现,首先先将BMP180与树莓派相连:

BMP180 树莓派
3.3 3.3V
GND GND
SCL SCL
SDA SDA

要计算海拔高度,可以使用如下公式:

一起玩转树莓派(17)——BMP180数字压力传感器应用

其中p0可以取海平面的标准大气压1013.25hPa。

连好线后,首先确认树莓派开启了I2C总线,如下:

一起玩转树莓派(17)——BMP180数字压力传感器应用

在树莓派的终端使用如下指令可以查看外接的元件地址:

sudo i2cdetect -y 1

可以看到如下图所示的输出:

一起玩转树莓派(17)——BMP180数字压力传感器应用

其中0x77即为BMP180设备地址。

下面给出完整的实验代码:

#coding:utf-8 import smbus import time import math  # 初始化 bus = smbus.SMBus(1) # 定义BMP180设备地址 deviceAddress = 0x77  # 通过I2C读取设备某个寄存器的数据 # regAdr 寄存器地址 def readByte(device, regAdr):     return bus.read_byte_data(device, regAdr)  # 读取一个字的数据 def readWord(device, regAdr):     high = bus.read_byte_data(device, regAdr)     low = bus.read_byte_data(device, regAdr + 1)     res = (high << 8) + low     return res  # 写入一个字节的数据 def writeByte(device, regAdr, data):     bus.write_byte_data(device, regAdr, data)  # 有符号数的补码转换 def getInt(data):     r = data     # 第1位为1表示是负数      # 对负数的补码再取补码即可得到源码     if (data & 0x8000) != 0:         d = data ^ 0xffff         d = d + 1         r = -d     return r  # 封装的获取E2PROM存储器中数据的方法 # sign参数表示是否是有符号数 def readCalibrate(adrList, index, sign):     value = (adrList[index] << 8) + adrList[index + 1]     if sign:         return getInt(value)          else:         return value  # 获取E2PROM存储其的数据 # read_i2c_block_data为i2C读取一块数据的方法,第2个参数为寄存器地址,第3个参数为读取的字节数 calibrationList = bus.read_i2c_block_data(deviceAddress, 0xAA, 22)  # 获取需要的校准系数 AC1 = readCalibrate(calibrationList, 0, True) AC2 = readCalibrate(calibrationList, 2, True) AC3 = readCalibrate(calibrationList, 4, True) AC4 = readCalibrate(calibrationList, 6, False) AC5 = readCalibrate(calibrationList, 8, False) AC6 = readCalibrate(calibrationList, 10, False) B1 = readCalibrate(calibrationList, 12, True)     B2 = readCalibrate(calibrationList, 14, True) MB = readCalibrate(calibrationList, 16, True) MC = readCalibrate(calibrationList, 18, True) MD = readCalibrate(calibrationList, 20, True)  # 获取原始的温度数据(未补偿) def getTemperature():     # 写入指令     writeByte(deviceAddress, 0xF4, 0x2E)     # 等待温度数据转换     time.sleep(0.005)      # 读取的数据为有符号数     value = readWord(deviceAddress, 0xF6)     # 符号处理     return getInt(value)  # 定义采样精度,这里取超高分辨率 OSS = 3  # 获取原始的压力数据 (未补偿) def getPressure():     # 写入指令     writeByte(deviceAddress, 0xF4, 0x34 + (OSS << 6))     time.sleep(0.026)     MSB = readByte(deviceAddress, 0xF6)     LSB = readByte(deviceAddress, 0xF7)     XLSB = readByte(deviceAddress, 0xF8)     value = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - OSS)     return value  # 计算真实的温度 def calculateTemperature(data):     X1 = ((data - AC6) * AC5) / math.pow(2, 15)     X2 = (MC * math.pow(2, 11)) / (X1 + MD)     B5 = X1 + X2      T = (B5 + 8) / math.pow(2, 4)     return T / 10.0  # 计算真实的气压 def calculatePressure(temp, data):     X1 = ((temp - AC6) * AC5) / math.pow(2, 15)     X2 = (MC * math.pow(2, 11)) / (X1 + MD)     B5 = int(X1 + X2)      B6 = B5 - 4000     X1 = (B2 * (B6 * B6 >> 12)) >> 11     X2 = AC2 * B6 >> 11     X3 = X1 + X2      B3 = (((AC1 * 4 + X3) << OSS) + 2) >> 2     X1 = (AC3 * B6) >> 13     X2 = (B1 * (B6 * B6 >> 12)) >> 16     X3 = ((X1 + X2) + 2) >> 2     B4 = AC4 * (X3 + 32768) >> 15     B7 = (data - B3) * (50000 >> OSS)     if (B7 < 0x80000000):         P = int((B7 * 2) / B4)      else:         P = int((B7 / B4) * 2)     X1 = (P >> 8) * (P >> 8)     X1 = (X1 * 3038) >> 16     X2 = (-7357 * P) >> 16     P = P + ((X1 + X2 + 3791) >> 4)     # 单位为Pa 转换为hPa 除以100即可     return P / 100.0  while True:     t = getTemperature()     temp = calculateTemperature(t)     press = calculatePressure(t, getPressure())     high = 44330 * (1 - math.pow((press / 1013.25), 1.0) / 5.255)     print('温度:%f, 气压:%f, 海拔:%f'%(temp, press, high))     time.sleep(1) 

运行上面代码,测量结果如下图所示:

一起玩转树莓派(17)——BMP180数字压力传感器应用

专注技术,懂的热爱,愿意分享,做个朋友

一起玩转树莓派(17)——BMP180数字压力传感器应用


本站部分内容转载自网络,版权属于原作者所有,如有异议请联系QQ153890879修改或删除,谢谢!
转载请注明原文链接:一起玩转树莓派(17)——BMP180数字压力传感器应用

你还在原价购买阿里云、腾讯云、华为云、天翼云产品?那就亏大啦!现在申请成为四大品牌云厂商VIP用户,可以3折优惠价购买云服务器等云产品,并且可享四大云服务商产品终身VIP优惠价,还等什么?赶紧点击下面对应链接免费申请VIP客户吧:

1、点击这里立即申请成为腾讯云VIP客户

2、点击这里立即注册成为天翼云VIP客户

3、点击这里立即申请成为华为云VIP客户

4、点击这里立享阿里云产品终身VIP优惠价

喜欢 (0)
[[email protected]]
分享 (0)