据StarFive报道,开发者已经在VisionFive 2上成功使用了气压传感器,具体说明如下:
1. 准备工作
- Development board: VisionFive/VisionFive 2
- Air pressure sensor: BMP180
- DuPont Line: Many

2、气压传感器的原理
本演示中使用的具体气压传感器模块如下:

压力传感器型号为BMP180,用于测量周围空气的绝对压力(大气压力)。其测量范围为300hPa-1100hPa,精度低至0.02hPa。它还可以测量温度并通过转换公式获得高度值。

BMP180气压传感器通过I2C接口进行通信,可以轻松连接到VisionFive。本演示中使用的模块可以由 5V 或 3.3V 供电,但不能同时供电。
在实践中,受实际测量环境的影响,BMP180测得的实际压力和温度值相对准确,但由于气流、阳光等因素可能导致大气压力和温度的变化,计算出的高度并不完全准确,因此计算的高度可能会相差0-100米。但在相对稳定的环境中,通过测量高差可以获得可靠的数据。例如,如果在地面上测量一个压力值,将其记录为基本压力值,然后根据该基本值在不同楼层进行测量,则得到的高度值相对准确。对于未来的延误,此方法将用于测试地板的高度。

3、气压传感器的使用
首先,参考下图,将压力传感器模块连接到VisionFive上:

连接:

注意:
电源电压应根据实际使用的传感器确定。本演示中使用的压力传感器模块使用 5V 电源电压。
将 BMP180 传感器模块连接到板卡后,您可以使用is2工具检查连接是否正常。
执行以下作,查看I2C设备的连接状态:
i2cdetect -y -r 0

从上图可以看出,BMP180传感器模块已经连接成功,其IIC通信地址0x77。
要获取有关BMP180的信息,该板需要使用IIC接口进行通信,该接口可以由第三方模块bmp180辅助。
git clone https://github.com/m-rtijn/bmp180.gitpip install smbus下载第三方库 bmp180 后,需要对bmp180.py文件,以便在板上使用,如下所示:
"""This program handles the communication over I2C between a Raspberry Pi and aBMP180 Temperature/Pressure sensor.Made by: MrTijn/TijndagamerCopyright 2015-2017Released under the MIT license."""import smbusimport mathfrom time import sleepclass bmp180: # Global variables address = None bus = smbus.SMBus(0) # 星光派开发板40Pin上的I2C使用i2c-0 mode = 1 # TODO: Add a way to change the mode # BMP180 registers CONTROL_REG = 0xF4 DATA_REG = 0xF6 # Calibration data registers CAL_AC1_REG = 0xAA CAL_AC2_REG = 0xAC CAL_AC3_REG = 0xAE CAL_AC4_REG = 0xB0 CAL_AC5_REG = 0xB2 CAL_AC6_REG = 0xB4 CAL_B1_REG = 0xB6 CAL_B2_REG = 0xB8 CAL_MB_REG = 0xBA CAL_MC_REG = 0xBC CAL_MD_REG = 0xBE # Calibration data variables calAC1 = 0 calAC2 = 0 calAC3 = 0 calAC4 = 0 calAC5 = 0 calAC6 = 0 calB1 = 0 calB2 = 0 calMB = 0 calMC = 0 calMD = 0 def __init__(self, address): self.address = address # Get the calibration data from the BMP180 self.read_calibration_data() # I2C methods def read_signed_16_bit(self, register): """Reads a signed 16-bit value. register -- the register to read from. Returns the read value. """ msb = self.bus.read_byte_data(self.address, register) lsb = self.bus.read_byte_data(self.address, register + 1) if msb > 127: msb -= 256 return (msb << 8) + lsb def read_unsigned_16_bit(self, register): """Reads an unsigned 16-bit value. Reads the given register and the following, and combines them as an unsigned 16-bit value. register -- the register to read from. Returns the read value. """ msb = self.bus.read_byte_data(self.address, register) lsb = self.bus.read_byte_data(self.address, register + 1) return (msb << 8) + lsb # BMP180 interaction methods def read_calibration_data(self): """Reads and stores the raw calibration data.""" self.calAC1 = self.read_signed_16_bit(self.CAL_AC1_REG) self.calAC2 = self.read_signed_16_bit(self.CAL_AC2_REG) self.calAC3 = self.read_signed_16_bit(self.CAL_AC3_REG) self.calAC4 = self.read_unsigned_16_bit(self.CAL_AC4_REG) self.calAC5 = self.read_unsigned_16_bit(self.CAL_AC5_REG) self.calAC6 = self.read_unsigned_16_bit(self.CAL_AC6_REG) self.calB1 = self.read_signed_16_bit(self.CAL_B1_REG) self.calB2 = self.read_signed_16_bit(self.CAL_B2_REG) self.calMB = self.read_signed_16_bit(self.CAL_MB_REG) self.calMC = self.read_signed_16_bit(self.CAL_MC_REG) self.calMD = self.read_signed_16_bit(self.CAL_MD_REG) def get_raw_temp(self): """Reads and returns the raw temperature data.""" # Write 0x2E to CONTROL_REG to start the measurement self.bus.write_byte_data(self.address, self.CONTROL_REG, 0x2E) # Wait 4,5 ms sleep(0.0045) # Read the raw data from the DATA_REG, 0xF6 raw_data = self.read_unsigned_16_bit(self.DATA_REG) # Return the raw data return raw_data def get_raw_pressure(self): """Reads and returns the raw pressure data.""" # Write appropriate data to sensor to start the measurement self.bus.write_byte_data(self.address, self.CONTROL_REG, 0x34 + (self.mode << 6)) # Sleep for 8 ms. # TODO: Way to use the correct wait time for the current mode sleep(0.008) MSB = self.bus.read_byte_data(self.address, self.DATA_REG) LSB = self.bus.read_byte_data(self.address, self.DATA_REG + 1) XLSB = self.bus.read_byte_data(self.address, self.DATA_REG + 2) raw_data = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - self.mode) return raw_data def get_temp(self): """Reads the raw temperature and calculates the actual temperature. The calculations used to get the actual temperature are from the BMP-180 datasheet. Returns the actual temperature in degrees Celcius. """ UT = self.get_raw_temp() X1 = 0 X2 = 0 B5 = 0 actual_temp = 0.0 X1 = ((UT - self.calAC6) * self.calAC5) / math.pow(2, 15) X2 = (self.calMC * math.pow(2, 11)) / (X1 + self.calMD) B5 = X1 + X2 actual_temp = ((B5 + 8) / math.pow(2, 4)) / 10 return actual_temp def get_pressure(self): """Reads and calculates the actual pressure. Returns the actual pressure in Pascal. """ UP = self.get_raw_pressure() UT = self.get_raw_temp() B3 = 0 B4 = 0 B5 = 0 B6 = 0 B7 = 0 X1 = 0 X2 = 0 X3 = 0 pressure = 0 # These calculations are from the BMP180 datasheet, page 15 # Not sure if these calculations should be here, maybe they could be # removed? X1 = ((UT - self.calAC6) * self.calAC5) / math.pow(2, 15) X2 = (self.calMC * math.pow(2, 11)) / (X1 + self.calMD) B5 = X1 + X2 # Todo: change math.pow cals to constants B6 = B5 - 4000 X1 = (self.calB2 * (B6 * B6 / math.pow(2, 12))) / math.pow(2, 11) X2 = self.calAC2 * B6 / math.pow(2, 11) X3 = X1 + X2 B3 = (((self.calAC1 * 4 + int(X3)) << self.mode) + 2) / 4 X1 = self.calAC3 * B6 / math.pow(2, 13) X2 = (self.calB1 * (B6 * B6 / math.pow(2, 12))) / math.pow(2, 16) X3 = ((X1 + X2) + 2) / math.pow(2, 2) B4 = self.calAC4 * (X3 + 32768) / math.pow(2,15) B7 = (UP - B3) * (50000 >> self.mode) if B7 < 0x80000000: pressure = (B7 * 2) / B4 else: pressure = (B7 / B4) * 2 X1 = (pressure / math.pow(2, 8)) * (pressure / math.pow(2, 8)) X1 = (X1 * 3038) / math.pow(2, 16) X2 = (-7357 * pressure) / math.pow(2, 16) pressure = pressure + (X1 + X2 + 3791) / math.pow(2, 4) return pressure def get_altitude(self, sea_level_pressure = 101325): """Calulates the altitude. This method calculates the altitude using the pressure. This method is not reliable when the sensor is inside. sea_level_pressure -- the pressure at the sea level closest to you in Pascal. Returns the altitude in meters. !!! This method probably does not work correctly. I've tried to test it but at the moment I have no way of verifying the data. !!! """ altitude = 0.0 pressure = float(self.get_pressure()) # altitude = 44330.0 * (1.0 - math.pow(pressure / sea_level_pressure, 0.00019029495)) altitude = 44330.0 * (1.0 - pow(pressure / sea_level_pressure, (1.0/5.255))) # 矫正计算结果 altitude = round(altitude, 2) return altitudeif __name__ == "__main__": bmp = bmp180(0x77) print(bmp.get_temp()) print(bmp.get_pressure()) print(bmp.get_altitude())然后,参考示例并编写以下程序来读取所需的数据:
# -*- coding: utf-8 -*-# file: ~/projects/pressure/bmp180/read_data_from_bm180.pyfrom bmp180 import bmp180import timebmp = bmp180(0x77)while True: temp = bmp.get_temp() pressure = bmp.get_pressure() / 1000 # altitude = bmp.get_altitude() # 当参数为空时,用于测量基准值 altitude = bmp.get_altitude(102225.9) # 以基准值为基础,测量高度值 print("当前温度: %0.1f ℃" % temp) print("当前气压: %0.4f kPa" % pressure) print("可能高度: %0.2f 米n" % altitude) time.sleep(2)然后运行read_data_from_bm180.py可以输出实际测量数据。
pyhon3 read_data_from_bm180.py实际结果如下:

在实际使用中,有必要使用bmp.get_altitude()测量参考值,然后使用bmp.get_altitude(基线值)以根据此参考值测量高程值。
在实际测量中,由于环境影响,结果值可能会有一定程度的漂移。可以考虑连续读取多条数据,然后使用一定的算法来获得最终合理的测试结果。
4. 总结
在这个演示中,我们学习了气压传感器的基本用法。
事实上,压力传感器广泛应用于室内外导航、天气预报、室内环境监测、风扇功率控制等诸多场合。
|