树莓派系列教程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)