树莓派系列教程12:I2C总线控制BMP180

通过上一章,相信各位对树莓派I2C编程有一定的了解了,今天我们继续使用I2C来控制BMP180压强传感器。BMP180压强传感器操作原理比较简单,开机先通过I2C读取出AC1,AC2,AC3,AC4,AC5,AC6,B1,B2,MB,MC,MD等寄存器的值,这些寄存器的值作为校准时使用。如何读取温度寄存器,压强寄存器的值,根据下图公式算出测得的当前温度和压强。

本章主要讲解python程序,使大家熟悉python编程。关于bcm2835,wiringpi程序具体可参看Pioneer600示例程序。

驱动文件bmp180.py

001import time
002import smbus
003 
004# BMP085 default address.
005BMP180_I2CADDR           = 0x77
006 
007# Operating Modes
008BMP180_ULTRALOWPOWER     = 0
009BMP180_STANDARD          = 1
010BMP180_HIGHRES           = 2
011BMP180_ULTRAHIGHRES      = 3
012 
013# BMP085 Registers
014BMP180_CAL_AC1           = 0xAA  # R   Calibration data (16 bits)
015BMP180_CAL_AC2           = 0xAC  # R   Calibration data (16 bits)
016BMP180_CAL_AC3           = 0xAE  # R   Calibration data (16 bits)
017BMP180_CAL_AC4           = 0xB0  # R   Calibration data (16 bits)
018BMP180_CAL_AC5           = 0xB2  # R   Calibration data (16 bits)
019BMP180_CAL_AC6           = 0xB4  # R   Calibration data (16 bits)
020BMP180_CAL_B1            = 0xB6  # R   Calibration data (16 bits)
021BMP180_CAL_B2            = 0xB8  # R   Calibration data (16 bits)
022BMP180_CAL_MB            = 0xBA  # R   Calibration data (16 bits)
023BMP180_CAL_MC            = 0xBC  # R   Calibration data (16 bits)
024BMP180_CAL_MD            = 0xBE  # R   Calibration data (16 bits)
025BMP180_CONTROL           = 0xF4
026BMP180_TEMPDATA          = 0xF6
027BMP180_PRESSUREDATA      = 0xF6
028 
029# Commands
030BMP180_READTEMPCMD       = 0x2E
031BMP180_READPRESSURECMD   = 0x34
032 
033 
034class BMP180(object):
035    def __init__(self, address=BMP180_I2CADDR, mode=BMP180_STANDARD):
036        self._mode = mode
037        self._address = address
038        self._bus = smbus.SMBus(1)
039        # Load calibration values.
040        self._load_calibration()
041    def _read_byte(self,cmd):
042        return self._bus.read_byte_data(self._address,cmd)
043 
044    def _read_u16(self,cmd):
045        MSB = self._bus.read_byte_data(self._address,cmd)
046        LSB = self._bus.read_byte_data(self._address,cmd+1)
047        return (MSB << 8) + LSB
048 
049    def _read_s16(self,cmd):
050        result = self._read_u16(cmd)
051        if result > 32767:result -= 65536
052        return result
053 
054    def _write_byte(self,cmd,val):
055        self._bus.write_byte_data(self._address,cmd,val)
056 
057    def _load_calibration(self):
058        "load calibration"
059        self.cal_AC1 = self._read_s16(BMP180_CAL_AC1)   # INT16
060        self.cal_AC2 = self._read_s16(BMP180_CAL_AC2)   # INT16
061        self.cal_AC3 = self._read_s16(BMP180_CAL_AC3)   # INT16
062        self.cal_AC4 = self._read_u16(BMP180_CAL_AC4)   # UINT16
063        self.cal_AC5 = self._read_u16(BMP180_CAL_AC5)   # UINT16
064        self.cal_AC6 = self._read_u16(BMP180_CAL_AC6)   # UINT16
065        self.cal_B1  = self._read_s16(BMP180_CAL_B1)     # INT16
066        self.cal_B2  = self._read_s16(BMP180_CAL_B2)     # INT16
067        self.cal_MB  = self._read_s16(BMP180_CAL_MB)     # INT16
068        self.cal_MC  = self._read_s16(BMP180_CAL_MC)     # INT16
069        self.cal_MD  = self._read_s16(BMP180_CAL_MD)     # INT16
070 
071    def read_raw_temp(self):
072        """Reads the raw (uncompensated) temperature from the sensor."""
073        self._write_byte(BMP180_CONTROL, BMP180_READTEMPCMD)
074        time.sleep(0.005)  # Wait 5ms
075        MSB = self._read_byte(BMP180_TEMPDATA)
076        LSB = self._read_byte(BMP180_TEMPDATA+1)
077        raw = (MSB << 8) + LSB
078        return raw
079 
080    def read_raw_pressure(self):
081        """Reads the raw (uncompensated) pressure level from the sensor."""
082        self._write_byte(BMP180_CONTROL, BMP180_READPRESSURECMD + (self._mode << 6))
083        if self._mode == BMP180_ULTRALOWPOWER:
084            time.sleep(0.005)
085        elif self._mode == BMP180_HIGHRES:
086            time.sleep(0.014)
087        elif self._mode == BMP180_ULTRAHIGHRES:
088            time.sleep(0.026)
089        else:
090            time.sleep(0.008)
091        MSB = self._read_byte(BMP180_PRESSUREDATA)
092        LSB = self._read_byte(BMP180_PRESSUREDATA+1)
093        XLSB = self._read_byte(BMP180_PRESSUREDATA+2)
094        raw = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - self._mode)
095        return raw
096 
097    def read_temperature(self):
098        """Gets the compensated temperature in degrees celsius."""
099        UT = self.read_raw_temp()
100 
101        X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
102        X2 = (self.cal_MC << 11) / (X1 + self.cal_MD)
103        B5 = X1 + X2
104        temp = ((B5 + 8) >> 4) / 10.0
105        return temp
106 
107    def read_pressure(self):
108        """Gets the compensated pressure in Pascals."""
109        UT = self.read_raw_temp()
110        UP = self.read_raw_pressure()
111 
112 
113        X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
114        X2 = (self.cal_MC << 11) / (X1 + self.cal_MD)
115        B5 = X1 + X2
116 
117        # Pressure Calculations
118        B6 = B5 - 4000
119        X1 = (self.cal_B2 * (B6 * B6) >> 12) >> 11
120        X2 = (self.cal_AC2 * B6) >> 11
121        X3 = X1 + X2
122        B3 = (((self.cal_AC1 * 4 + X3) << self._mode) + 2) / 4
123 
124        X1 = (self.cal_AC3 * B6) >> 13
125        X2 = (self.cal_B1 * ((B6 * B6) >> 12)) >> 16
126        X3 = ((X1 + X2) + 2) >> 2
127        B4 = (self.cal_AC4 * (X3 + 32768)) >> 15
128        B7 = (UP - B3) * (50000 >> self._mode)
129 
130        if B7 < 0x80000000:
131            p = (B7 * 2) / B4
132        else:
133            p = (B7 / B4) * 2
134        X1 = (p >> 8) * (p >> 8)
135        X1 = (X1 * 3038) >> 16
136        X2 = (-7357 * p) >> 16
137 
138        p = p + ((X1 + X2 + 3791) >> 4)
139        return p
140 
141    def read_altitude(self, sealevel_pa=101325.0):
142        """Calculates the altitude in meters."""
143        # Calculation taken straight from section 3.6 of the datasheet.
144        pressure = float(self.read_pressure())
145        altitude = 44330.0 * (1.0 - pow(pressure / sealevel_pa, (1.0/5.255)))
146        return altitude
147 
148    def read_sealevel_pressure(self, altitude_m=0.0):
149        """Calculates the pressure at sealevel when given a known altitude in
150        meters. Returns a value in Pascals."""
151        pressure = float(self.read_pressure())
152        p0 = pressure / pow(1.0 - altitude_m/44330.0, 5.255)
153        return p0

主文件bmp180_example.py

01#!/usr/bin/python
02 
03import time
04from BMP180 import BMP180
05 
06# Initialise the BMP085 and use STANDARD mode (default value)
07# bmp = BMP085(0x77, debug=True)
08bmp = BMP180()
09 
10# To specify a different operating mode, uncomment one of the following:
11# bmp = BMP085(0x77, 0)  # ULTRALOWPOWER Mode
12# bmp = BMP085(0x77, 1)  # STANDARD Mode
13# bmp = BMP085(0x77, 2)  # HIRES Mode
14# bmp = BMP085(0x77, 3)  # ULTRAHIRES Mode
15while True:
16    temp = bmp.read_temperature()
17 
18# Read the current barometric pressure level
19    pressure = bmp.read_pressure()
20 
21# To calculate altitude based on an estimated mean sea level pressure
22# (1013.25 hPa) call the function as follows, but this won't be very accurate
23    altitude = bmp.read_altitude()
24 
25# To specify a more accurate altitude, enter the correct mean sea level
26# pressure level.  For example, if the current pressure level is 1023.50 hPa
27# enter 102350 since we include two decimal places in the integer value
28# altitude = bmp.readAltitude(102350)
29 
30    print "Temperature: %.2f C" % temp
31    print "Pressure:    %.2f hPa" % (pressure / 100.0)
32    print "Altitude:     %.2f\n" % altitude
33time.sleep(1)
TAG: 树莓派Pico 2 RP2350-Tiny/Tiny-Kit 迷你开发板 RP2350A RP2040开发板 树莓派7寸QLED量子点电容触摸显示屏1024x600 PC电脑游戏副屏 PDF手册 Luckfox Pico Max教程 树莓派2.8寸DPI电容触摸显示屏 LCD模块 480×640像素 树莓派红外摄像头 Luckfox Pico Pro教程 树莓派1.5寸OLED 树莓派5迷你PoE HAT (G)以太网RJ45供电扩展板5V 5A Arducam摄像头 串口液晶屏 X1202 树莓派5 UPS电源管理扩展板18650不间断供电模块 树莓派PICO 11.9寸电脑副屏 MP2.5G树莓派5 PCIE转 2.5G以太网扩展板 Pi5 RTL8125 RDK X3 MD Carrier Board 地平线官方原版RDK X3 Module专用核心板底板 扩展板 适用于RDK X3 MD所有版本 树莓派0.85寸LCD X1002树莓派5专用PCIE转M.2 NVME SSD固态硬盘扩展板Pi5 2280 USB转串口