Skip to content

Commit b338e18

Browse files
AsCressbessman
authored andcommitted
fix: fixed BMP180
1 parent 4e53d8f commit b338e18

File tree

2 files changed

+186
-109
lines changed

2 files changed

+186
-109
lines changed

pslab/external/BMP180.py

Lines changed: 0 additions & 109 deletions
This file was deleted.

pslab/external/bmp180.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
"""BMP180 Altimeter."""
2+
3+
import time
4+
import logging
5+
import struct
6+
from pslab.bus import I2CSlave
7+
8+
# BMP180 default address
9+
_ADDRESS = 0x77
10+
11+
# Operating Modes
12+
_ULTRALOWPOWER = 0
13+
_STANDARD = 1
14+
_HIGHRES = 2
15+
_ULTRAHIGHRES = 3
16+
17+
# BMP180 Registers
18+
_CAL_AC1 = 0xAA # R Calibration data (16 bits)
19+
_CAL_AC2 = 0xAC # R Calibration data (16 bits)
20+
_CAL_AC3 = 0xAE # R Calibration data (16 bits)
21+
_CAL_AC4 = 0xB0 # R Calibration data (16 bits)
22+
_CAL_AC5 = 0xB2 # R Calibration data (16 bits)
23+
_CAL_AC6 = 0xB4 # R Calibration data (16 bits)
24+
_CAL_B1 = 0xB6 # R Calibration data (16 bits)
25+
_CAL_B2 = 0xB8 # R Calibration data (16 bits)
26+
_CAL_MB = 0xBA # R Calibration data (16 bits)
27+
_CAL_MC = 0xBC # R Calibration data (16 bits)
28+
_CAL_MD = 0xBE # R Calibration data (16 bits)
29+
_CONTROL = 0xF4
30+
_TEMPDATA = 0xF6
31+
_PRESSUREDATA = 0xF6
32+
33+
# Commands
34+
_READTEMPCMD = 0x2E
35+
_READPRESSURECMD = 0x34
36+
37+
_logger = logging.getLogger(__name__)
38+
39+
40+
class BMP180(I2CSlave):
41+
"""Class to interface with the BMP180 Altimeter.
42+
43+
Parameters
44+
----------
45+
mode : int, optional
46+
The mode of operation for the sensor, determining the oversampling setting.
47+
The default mode is `_HIGHRES`. This parameter affects the precision and speed
48+
of the temperature and pressure measurements.
49+
50+
**kwargs : dict, optional
51+
Additional keyword arguments, such as:
52+
- address (int): The I2C address of the BMP180 sensor. Default is `_ADDRESS`.
53+
54+
Attributes
55+
----------
56+
temperature : float
57+
The measured temperature in degrees Celsius.
58+
59+
pressure : float
60+
The measured pressure in Pa (Pascals).
61+
62+
altitude : float
63+
The calculated altitude in meters based on the current pressure reading
64+
and a reference sea level pressure.
65+
"""
66+
67+
NUMPLOTS = 3
68+
PLOTNAMES = ["Temperature", "Pressure", "Altitude"]
69+
name = "BMP180 Altimeter"
70+
71+
def __init__(self, mode=_HIGHRES, **kwargs):
72+
self._ADDRESS = kwargs.get("address", _ADDRESS)
73+
super().__init__(self._ADDRESS)
74+
self._mode = mode
75+
76+
# Load calibration values
77+
self._ac1 = self._read_int16(_CAL_AC1)
78+
self._ac2 = self._read_int16(_CAL_AC2)
79+
self._ac3 = self._read_int16(_CAL_AC3)
80+
self._ac4 = self._read_uint16(_CAL_AC4)
81+
self._ac5 = self._read_uint16(_CAL_AC5)
82+
self._ac6 = self._read_uint16(_CAL_AC6)
83+
self._b1 = self._read_int16(_CAL_B1)
84+
self._b2 = self._read_int16(_CAL_B2)
85+
self._mb = self._read_int16(_CAL_MB)
86+
self._mc = self._read_int16(_CAL_MC)
87+
self._md = self._read_int16(_CAL_MD)
88+
89+
_logger.debug(f"ac1: {self._ac1}")
90+
_logger.debug(f"ac2: {self._ac2}")
91+
_logger.debug(f"ac3: {self._ac3}")
92+
_logger.debug(f"ac4: {self._ac4}")
93+
_logger.debug(f"ac5: {self._ac5}")
94+
_logger.debug(f"ac6: {self._ac6}")
95+
_logger.debug(f"b1: {self._b1}")
96+
_logger.debug(f"b2: {self._b2}")
97+
_logger.debug(f"mb: {self._mb}")
98+
_logger.debug(f"mc: {self._mc}")
99+
_logger.debug(f"md: {self._md}")
100+
101+
def _read_int16(self, addr):
102+
BE_INT16 = struct.Struct(">h") # signed short, big endian
103+
return BE_INT16.unpack(self.read(2, addr))[0]
104+
105+
def _read_uint16(self, addr):
106+
BE_UINT16 = struct.Struct(">H") # unsigned short, big endian
107+
return BE_UINT16.unpack(self.read(2, addr))[0]
108+
109+
def _read_raw_temperature(self):
110+
"""Read the raw temperature from the sensor."""
111+
self.write([_READTEMPCMD], _CONTROL)
112+
time.sleep(0.005)
113+
raw = self._read_uint16(_TEMPDATA)
114+
return raw
115+
116+
@property
117+
def temperature(self):
118+
"""Get the actual temperature in degrees celsius."""
119+
ut = self._read_raw_temperature()
120+
# Calculations from section 3.5 of the datasheet
121+
x1 = ((ut - self._ac6) * self._ac5) >> 15
122+
x2 = (self._mc << 11) // (x1 + self._md)
123+
b5 = x1 + x2
124+
temp = ((b5 + 8) >> 4) / 10.0
125+
return temp
126+
127+
@property
128+
def oversampling(self):
129+
"""oversampling : int
130+
The oversampling setting used by the sensor. This attribute is settable and
131+
determines the trade-off between measurement accuracy and speed. Possible values
132+
include `_ULTRALOWPOWER`, `_STANDARD`, `_HIGHRES`, and `_ULTRAHIGHRES`.
133+
"""
134+
return self._mode
135+
136+
@oversampling.setter
137+
def oversampling(self, value):
138+
self._mode = value
139+
140+
def _read_raw_pressure(self):
141+
"""Read the raw pressure level from the sensor."""
142+
delays = [0.005, 0.008, 0.014, 0.026]
143+
self.write([_READPRESSURECMD + (self._mode << 6)], _CONTROL)
144+
time.sleep(delays[self._mode])
145+
msb = self.read_byte(_PRESSUREDATA) & 0xFF
146+
lsb = self.read_byte(_PRESSUREDATA + 1) & 0xFF
147+
xlsb = self.read_byte(_PRESSUREDATA + 2) & 0xFF
148+
raw = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - self._mode)
149+
return raw
150+
151+
@property
152+
def pressure(self):
153+
"""Get the actual pressure in Pascals."""
154+
ut = self._read_raw_temperature()
155+
up = self._read_raw_pressure()
156+
# Calculations from section 3.5 of the datasheet
157+
x1 = ((ut - self._ac6) * self._ac5) >> 15
158+
x2 = (self._mc << 11) // (x1 + self._md)
159+
b5 = x1 + x2
160+
# Pressure Calculations
161+
b6 = b5 - 4000
162+
x1 = (self._b2 * (b6 * b6) >> 12) >> 11
163+
x2 = (self._ac2 * b6) >> 11
164+
x3 = x1 + x2
165+
b3 = (((self._ac1 * 4 + x3) << self._mode) + 2) // 4
166+
x1 = (self._ac3 * b6) >> 13
167+
x2 = (self._b1 * ((b6 * b6) >> 12)) >> 16
168+
x3 = ((x1 + x2) + 2) >> 2
169+
b4 = (self._ac4 * (x3 + 32768)) >> 15
170+
b7 = (up - b3) * (50000 >> self._mode)
171+
if b7 < 0x80000000:
172+
p = (b7 * 2) // b4
173+
else:
174+
p = (b7 // b4) * 2
175+
x1 = (p >> 8) * (p >> 8)
176+
x1 = (x1 * 3038) >> 16
177+
x2 = (-7357 * p) >> 16
178+
pres = p + ((x1 + x2 + 3791) >> 4)
179+
return pres
180+
181+
@property
182+
def altitude(self):
183+
# Calculation from section 3.6 of datasheet
184+
pressure = float(self.pressure)
185+
alt = 44330.0 * (1.0 - pow(pressure / 101325.0, (1.0 / 5.255)))
186+
return alt

0 commit comments

Comments
 (0)