According to StarFive, developers have successfully used Air Pressure Sensor on VisionFive 2, and the specific instructions are as follows:
- Development board: VisionFive/VisionFive 2
- Air pressure sensor: BMP180
- DuPont Line: Many
2. Principle of air pressure sensor
The specific air pressure sensor modules used in this demo are as follows:
The pressure sensor model is BMP180, which is used to measure the absolute pressure of the surrounding air (atmospheric pressure). Its measurement range is from 300hPa - 1100hPa with an accuracy as low as 0.02hPa. It can also measure temperature and obtain height values through conversion formulas.
The BMP180 air pressure sensor communicates through the I2C interface and can be easily connected to VisionFive. The modules used in this demo can be powered by 5V or 3.3V, but cannot be powered simultaneously.
In practical, influenced by the actual measurement environment, the actual pressure and temperature values measured by BMP180 are relatively accurate, but the calculated altitude is not entirely accurate because air flow, sunlight, and other factors may cause changes in atmospheric pressure and temperature, so the calculated altitude may differ by 0-100 meters. But in a relatively stable environment, reliable data can be obtained by measuring the height difference. For example, if a pressure value is measured on the ground, which is recorded as the basic pressure value, and then measure on different floors based on this basic value, the height value obtained is relatively accurate. For future delays, this method will be used to test the height of the floors.
3. The use of air pressure sensor
Firstly, refer to the following figure and connect the pressure sensor module to the VisionFive:
The power supply voltage should be determined based on the actual sensor used. The pressure sensor module used in this demo uses a 5V power supply voltage.
After connecting the BMP180 sensor module to the board, you can use the is2tools to check whether the connection is normal.
Execute following to view the connection status of I2C devices:
i2cdetect -y -r 0
From the above figure, it can be seen that the BMP180 sensor module has been successfully connected, and its IIC communication address is 0x77.
To obtain information about BMP180, the board needs to use the IIC interface for communication, which can be assisted by a third-party module bmp180.
git clone https://github.com/m-rtijn/bmp180.git pip install smbus
After downloading the third-party library bmp180, some modifications need to be made to the
bmp180.py file in order to be used on the board, as follows:
""" This program handles the communication over I2C between a Raspberry Pi and a BMP180 Temperature/Pressure sensor. Made by: MrTijn/Tijndagamer Copyright 2015-2017 Released under the MIT license. """ import smbus import math from time import sleep class 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 altitude if __name__ == "__main__": bmp = bmp180(0x77) print(bmp.get_temp()) print(bmp.get_pressure()) print(bmp.get_altitude())
Then, refer to the example and write the following program to read the required data:
# -*- coding: utf-8 -*- # file: ~/projects/pressure/bmp180/read_data_from_bm180.py from bmp180 import bmp180 import time bmp = 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 can output the actual measured data.
The actual results are as follows:
In actual use, it is necessary to use
bmp.get_altitude() to measure the reference value, and then use
bmp.get_altitude(baseline value) to measure the Elevation value based on this reference value.
In actual measurements, due to environmental influences, the result values may drift to a certain extent. It is possible to consider continuously reading multiple pieces of data and then using certain algorithms to obtain the final reasonable test results.
In this demo, we learned the basic use of air pressure sensors.
In fact, pressure sensors are widely used in indoor and outdoor navigation, weather forecasting, indoor environment monitoring, fan power control and many other occasions.