作為最常見的傳感器,本篇(來自于知乎某大神的文章)實現(xiàn)氣壓傳感的交互:
1.先說明BMP180的特點
? 壓力范圍:300~1100hPa(海拔 9000 米~-500 米)
? 電源電壓:1.8V~3.6V(VDDA), 1.62V~3.6V(VDDD)
? 尺寸:3.6mmx3.8x0.93mm
? 低功耗:5μA,在標準模式
? 高精度:低功耗模式下蕉鸳,分辨率為 0.06hPa(0.5 米)
? 高線性模式下蜕煌,分辨率為 0.03hPa(0.25 米)
? 含溫度輸出
? I2C 接口
? 溫度補償
? MSL 1 反應(yīng)時間:7.5ms
? 待機電流:0.1μA
注意了該傳感器是I2C接口的,因此在后續(xù)步驟要稍加注意株扛。
2. 接線
I2C 有兩個總線:SCL 為時鐘信號养距,和 SDA 為雙向數(shù)據(jù)傳輸诉探。 每個 I2C 器件采用獨特的 7 位地址,這意味著你可以有超過 120 個獨特的 I2C 器件共享總線棍厌, 并且可以同時控制這些器件一起工作肾胯。
將 BMP180 的 VCC 引腳用紅色跳線連接樹莓派的 3V3 ( 3.3 伏電源)。將 BMP180 的 SDA 引腳 接入樹莓派的 SDA 引腳并將 BMP180 SCL 引腳接入樹莓派的 SCL 引腳耘纱,該引腳提供一個規(guī)律的 時鐘信號敬肚。SDA 傳遞數(shù)據(jù)信號。BMP180 的 GND 引腳通過黑色跳線連接樹莓派的接地( GND) 引腳束析。 在上電前艳馒,一定多檢查兩次接線的準確性。
3. 環(huán)境和程序部分
配置文件/boot/config.txt:
dtparam=i2c_arm=on
重啟樹莓派,用如下命令查看傳感器是否接上:
i2cdetect -y 1
如果接上了的話會顯示下圖:
編寫 BMP180.py:
#!/usr/bin/env python
import time
import smbus
# BMP085 default address.
BMP180_I2CADDR? ? ? ? ? = 0x77
# Operating Modes
BMP180_ULTRALOWPOWER? ? = 0
BMP180_STANDARD? ? ? ? ? = 1
BMP180_HIGHRES? ? ? ? ? = 2
BMP180_ULTRAHIGHRES? ? ? = 3
# BMP085 Registers
BMP180_CAL_AC1? ? ? ? ? = 0xAA? # R? Calibration data (16 bits)
BMP180_CAL_AC2? ? ? ? ? = 0xAC? # R? Calibration data (16 bits)
BMP180_CAL_AC3? ? ? ? ? = 0xAE? # R? Calibration data (16 bits)
BMP180_CAL_AC4? ? ? ? ? = 0xB0? # R? Calibration data (16 bits)
BMP180_CAL_AC5? ? ? ? ? = 0xB2? # R? Calibration data (16 bits)
BMP180_CAL_AC6? ? ? ? ? = 0xB4? # R? Calibration data (16 bits)
BMP180_CAL_B1? ? ? ? ? ? = 0xB6? # R? Calibration data (16 bits)
BMP180_CAL_B2? ? ? ? ? ? = 0xB8? # R? Calibration data (16 bits)
BMP180_CAL_MB? ? ? ? ? ? = 0xBA? # R? Calibration data (16 bits)
BMP180_CAL_MC? ? ? ? ? ? = 0xBC? # R? Calibration data (16 bits)
BMP180_CAL_MD? ? ? ? ? ? = 0xBE? # R? Calibration data (16 bits)
BMP180_CONTROL? ? ? ? ? = 0xF4
BMP180_TEMPDATA? ? ? ? ? = 0xF6
BMP180_PRESSUREDATA? ? ? = 0xF6
# Commands
BMP180_READTEMPCMD? ? ? = 0x2E
BMP180_READPRESSURECMD? = 0x34
class BMP180(object):
? ? def __init__(self, address=BMP180_I2CADDR, mode=BMP180_STANDARD):
? ? ? ? self._mode = mode
? ? ? ? self._address = address
? ? ? ? self._bus = smbus.SMBus(1)
? ? ? ? # Load calibration values.
? ? ? ? self._load_calibration()
? ? def _read_byte(self,cmd):
? ? ? ? return self._bus.read_byte_data(self._address,cmd)
? ? def _read_u16(self,cmd):
? ? ? ? MSB = self._bus.read_byte_data(self._address,cmd)
? ? ? ? LSB = self._bus.read_byte_data(self._address,cmd+1)
? ? ? ? return (MSB << 8) + LSB
? ? def _read_s16(self,cmd):
? ? ? ? result = self._read_u16(cmd)
? ? ? ? if result > 32767:result -= 65536
? ? ? ? return result
? ? def _write_byte(self,cmd,val):
? ? ? ? self._bus.write_byte_data(self._address,cmd,val)
? ? def _load_calibration(self):
? ? ? ? "load calibration"
? ? ? ? self.cal_AC1 = self._read_s16(BMP180_CAL_AC1)? # INT16
? ? ? ? self.cal_AC2 = self._read_s16(BMP180_CAL_AC2)? # INT16
? ? ? ? self.cal_AC3 = self._read_s16(BMP180_CAL_AC3)? # INT16
? ? ? ? self.cal_AC4 = self._read_u16(BMP180_CAL_AC4)? # UINT16
? ? ? ? self.cal_AC5 = self._read_u16(BMP180_CAL_AC5)? # UINT16
? ? ? ? self.cal_AC6 = self._read_u16(BMP180_CAL_AC6)? # UINT16
? ? ? ? self.cal_B1? = self._read_s16(BMP180_CAL_B1)? ? # INT16
? ? ? ? self.cal_B2? = self._read_s16(BMP180_CAL_B2)? ? # INT16
? ? ? ? self.cal_MB? = self._read_s16(BMP180_CAL_MB)? ? # INT16
? ? ? ? self.cal_MC? = self._read_s16(BMP180_CAL_MC)? ? # INT16
? ? ? ? self.cal_MD? = self._read_s16(BMP180_CAL_MD)? ? # INT16
? ? def read_raw_temp(self):
? ? ? ? """Reads the raw (uncompensated) temperature from the sensor."""
? ? ? ? self._write_byte(BMP180_CONTROL, BMP180_READTEMPCMD)
? ? ? ? time.sleep(0.005)? # Wait 5ms
? ? ? ? MSB = self._read_byte(BMP180_TEMPDATA)
? ? ? ? LSB = self._read_byte(BMP180_TEMPDATA+1)
? ? ? ? raw = (MSB << 8) + LSB
? ? ? ? return raw
? ? def read_raw_pressure(self):
? ? ? ? """Reads the raw (uncompensated) pressure level from the sensor."""
? ? ? ? self._write_byte(BMP180_CONTROL, BMP180_READPRESSURECMD + (self._mode << 6))
? ? ? ? if self._mode == BMP180_ULTRALOWPOWER:
? ? ? ? ? ? time.sleep(0.005)
? ? ? ? elif self._mode == BMP180_HIGHRES:
? ? ? ? ? ? time.sleep(0.014)
? ? ? ? elif self._mode == BMP180_ULTRAHIGHRES:
? ? ? ? ? ? time.sleep(0.026)
? ? ? ? else:
? ? ? ? ? ? time.sleep(0.008)
? ? ? ? MSB = self._read_byte(BMP180_PRESSUREDATA)
? ? ? ? LSB = self._read_byte(BMP180_PRESSUREDATA+1)
? ? ? ? XLSB = self._read_byte(BMP180_PRESSUREDATA+2)
? ? ? ? raw = ((MSB << 16) + (LSB << 8) + XLSB) >> (8 - self._mode)
? ? ? ? return raw
? ? def read_temperature(self):
? ? ? ? """Gets the compensated temperature in degrees celsius."""
? ? ? ? UT = self.read_raw_temp()
? ? ? ? X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
? ? ? ? X2 = (self.cal_MC << 11) / (X1 + self.cal_MD)
? ? ? ? B5 = X1 + X2
? ? ? ? temp = ((B5 + 8) >> 4) / 10.0
? ? ? ? return temp
? ? def read_pressure(self):
? ? ? ? """Gets the compensated pressure in Pascals."""
? ? ? ? UT = self.read_raw_temp()
? ? ? ? UP = self.read_raw_pressure()
? ? ? ? X1 = ((UT - self.cal_AC6) * self.cal_AC5) >> 15
? ? ? ? X2 = (self.cal_MC << 11) / (X1 + self.cal_MD)
? ? ? ? B5 = X1 + X2
? ? ? ? # Pressure Calculations
? ? ? ? B6 = B5 - 4000
? ? ? ? X1 = (self.cal_B2 * (B6 * B6) >> 12) >> 11
? ? ? ? X2 = (self.cal_AC2 * B6) >> 11
? ? ? ? X3 = X1 + X2
? ? ? ? B3 = (((self.cal_AC1 * 4 + X3) << self._mode) + 2) / 4
? ? ? ? X1 = (self.cal_AC3 * B6) >> 13
? ? ? ? X2 = (self.cal_B1 * ((B6 * B6) >> 12)) >> 16
? ? ? ? X3 = ((X1 + X2) + 2) >> 2
? ? ? ? B4 = (self.cal_AC4 * (X3 + 32768)) >> 15
? ? ? ? B7 = (UP - B3) * (50000 >> self._mode)
? ? ? ? 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)
? ? ? ? return p
? ? def read_altitude(self, sealevel_pa=101325.0):
? ? ? ? """Calculates the altitude in meters."""
? ? ? ? # Calculation taken straight from section 3.6 of the datasheet.
? ? ? ? pressure = float(self.read_pressure())
? ? ? ? altitude = 44330.0 * (1.0 - pow(pressure / sealevel_pa, (1.0/5.255)))
? ? ? ? return altitude
? ? def read_sealevel_pressure(self, altitude_m=0.0):
? ? ? ? """Calculates the pressure at sealevel when given a known altitude in
? ? ? ? meters. Returns a value in Pascals."""
? ? ? ? pressure = float(self.read_pressure())
? ? ? ? p0 = pressure / pow(1.0 - altitude_m/44330.0, 5.255)
? ? ? ? return p0
然后編寫調(diào)用函數(shù)bmp180_example.py:
#!/usr/bin/python
import time
from BMP180 import BMP180
# Initialise the BMP085 and use STANDARD mode (default value)
# bmp = BMP085(0x77, debug=True)
bmp = BMP180()
# To specify a different operating mode, uncomment one of the following:
# bmp = BMP085(0x77, 0)? # ULTRALOWPOWER Mode
# bmp = BMP085(0x77, 1)? # STANDARD Mode
# bmp = BMP085(0x77, 2)? # HIRES Mode
# bmp = BMP085(0x77, 3)? # ULTRAHIRES Mode
while True:
? ? temp = bmp.read_temperature()
# Read the current barometric pressure level
? ? pressure = bmp.read_pressure()
# To calculate altitude based on an estimated mean sea level pressure
# (1013.25 hPa) call the function as follows, but this won't be very accurate
? ? altitude = bmp.read_altitude()
# To specify a more accurate altitude, enter the correct mean sea level
# pressure level.? For example, if the current pressure level is 1023.50 hPa
# enter 102350 since we include two decimal places in the integer value
# altitude = bmp.readAltitude(102350)
? ? print "Temperature: %.2f C" % temp
? ? print "Pressure:? ? %.2f hPa" % (pressure / 100.0)
? ? #print "Altitude:? ? %.2f\n" % altitude
? ? time.sleep(1)
執(zhí)行./bmp180_example.py就可以在終端看到實時的溫度/氣壓輸出弄慰。