2020# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121# THE SOFTWARE.
2222"""
23- `adafruit_bmp280`
24- ====================================================
23+ `adafruit_bmp280` - Adafruit BMP280 - Temperature & Barometic Pressure Sensor
24+ ===============================================================================
2525
2626CircuitPython driver from BMP280 Temperature and Barometic Pressure sensor
2727
2828* Author(s): ladyada
2929"""
3030import math
31- import time
31+ from time import sleep
3232try :
3333 import struct
3434except ImportError :
3535 import ustruct as struct
36-
3736from micropython import const
3837
3938__version__ = "0.0.0-auto.0"
4544
4645_REGISTER_CHIPID = const (0xD0 )
4746_REGISTER_DIG_T1 = const (0x88 )
48- # _REGISTER_DIG_T2 = const(0x8A)
49- # _REGISTER_DIG_T3 = const(0x8C)
50- # _REGISTER_DIG_P1 = const(0x8E)
51- # _REGISTER_DIG_P2 = const(0x90)
52- # _REGISTER_DIG_P3 = const(0x92)
53- # _REGISTER_DIG_P4 = const(0x94)
54- # _REGISTER_DIG_P5 = const(0x96)
55- # _REGISTER_DIG_P6 = const(0x98)
56- # _REGISTER_DIG_P7 = const(0x9A)
57- # _REGISTER_DIG_P8 = const(0x9C)
58- # _REGISTER_DIG_P9 = const(0x9E)
5947_REGISTER_SOFTRESET = const (0xE0 )
6048_REGISTER_STATUS = const (0xF3 )
61- _REGISTER_CONTROL = const (0xF4 )
49+ _REGISTER_CTRL_MEAS = const (0xF4 )
6250_REGISTER_CONFIG = const (0xF5 )
6351_REGISTER_PRESSUREDATA = const (0xF7 )
6452_REGISTER_TEMPDATA = const (0xFA )
6553
54+ _BMP280_PRESSURE_MIN_HPA = const (300 )
55+ _BMP280_PRESSURE_MAX_HPA = const (1100 )
56+
57+
58+ """iir_filter values"""
59+ IIR_FILTER_DISABLE = const (0 )
60+ IIR_FILTER_X2 = const (0x01 )
61+ IIR_FILTER_X4 = const (0x02 )
62+ IIR_FILTER_X8 = const (0x03 )
63+ IIR_FILTER_X16 = const (0x04 )
64+
65+ _BMP280_IIR_FILTERS = frozenset ((IIR_FILTER_DISABLE , IIR_FILTER_X2 ,
66+ IIR_FILTER_X4 , IIR_FILTER_X8 , IIR_FILTER_X16 ))
67+
68+ """overscan values for temperature, pressure, and humidity"""
69+ OVERSCAN_DISABLE = const (0x00 )
70+ OVERSCAN_X1 = const (0x01 )
71+ OVERSCAN_X2 = const (0x02 )
72+ OVERSCAN_X4 = const (0x03 )
73+ OVERSCAN_X8 = const (0x04 )
74+ OVERSCAN_X16 = const (0x05 )
75+
76+ _BMP280_OVERSCANS = {OVERSCAN_DISABLE :0 , OVERSCAN_X1 :1 , OVERSCAN_X2 :2 ,
77+ OVERSCAN_X4 :4 , OVERSCAN_X8 :8 , OVERSCAN_X16 :16 }
78+
79+ """mode values"""
80+ MODE_SLEEP = const (0x00 )
81+ MODE_FORCE = const (0x01 )
82+ MODE_NORMAL = const (0x03 )
83+
84+ _BMP280_MODES = frozenset ((MODE_SLEEP , MODE_FORCE , MODE_NORMAL ))
85+ """
86+ standby timeconstant values
87+ TC_X[_Y] where X=milliseconds and Y=tenths of a millisecond
88+ """
89+ STANDBY_TC_0_5 = const (0x00 ) #0.5ms
90+ STANDBY_TC_10 = const (0x06 ) #10ms
91+ STANDBY_TC_20 = const (0x07 ) #20ms
92+ STANDBY_TC_62_5 = const (0x01 ) #62.5ms
93+ STANDBY_TC_125 = const (0x02 ) #125ms
94+ STANDBY_TC_250 = const (0x03 ) #250ms
95+ STANDBY_TC_500 = const (0x04 ) #500ms
96+ STANDBY_TC_1000 = const (0x05 ) #1000ms
97+
98+ _BMP280_STANDBY_TCS = frozenset ((STANDBY_TC_0_5 , STANDBY_TC_10 , STANDBY_TC_20 ,
99+ STANDBY_TC_62_5 , STANDBY_TC_125 , STANDBY_TC_250 ,
100+ STANDBY_TC_500 , STANDBY_TC_1000 ))
101+
66102class Adafruit_BMP280 : # pylint: disable=invalid-name
67103 """Base BMP280 object. Use `Adafruit_BMP280_I2C` or `Adafruit_BMP280_SPI` instead of this. This
68104 checks the BMP280 was found, reads the coefficients and enables the sensor for continuous
@@ -72,56 +108,221 @@ def __init__(self):
72108 chip_id = self ._read_byte (_REGISTER_CHIPID )
73109 if _CHIP_ID != chip_id :
74110 raise RuntimeError ('Failed to find BMP280! Chip ID 0x%x' % chip_id )
111+ #Set some reasonable defaults.
112+ self ._iir_filter = IIR_FILTER_DISABLE
113+ self ._overscan_temperature = OVERSCAN_X2
114+ self ._overscan_pressure = OVERSCAN_X16
115+ self ._t_standby = STANDBY_TC_0_5
116+ self ._mode = MODE_SLEEP
117+ self ._reset ()
75118 self ._read_coefficients ()
119+ self ._write_ctrl_meas ()
120+ self ._write_config ()
76121 self .sea_level_pressure = 1013.25
77122 """Pressure in hectoPascals at sea level. Used to calibrate `altitude`."""
123+ self ._t_fine = None
78124
79- def _read (self ):
80- """Returns a tuple for temperature and pressure."""
81- # perform one measurement in high res, forced mode
82- self ._write_register_byte (_REGISTER_CONTROL , 0xFE )
83-
84- # Wait for conversion to complete
85- while self ._read_byte (_REGISTER_STATUS ) & 0x08 :
86- time .sleep (0.002 )
87- # lowest 4 bits get dropped
88- UT = self ._read24 (_REGISTER_TEMPDATA ) / 16
125+ def _read_temperature (self ):
126+ # perform one measurement
127+ if self .mode != MODE_NORMAL :
128+ self .mode = MODE_FORCE
129+ # Wait for conversion to complete
130+ while self ._get_status () & 0x08 :
131+ sleep (0.002 )
132+ raw_temperature = self ._read24 (_REGISTER_TEMPDATA ) / 16 # lowest 4 bits get dropped
89133 #print("raw temp: ", UT)
134+ var1 = (raw_temperature / 16384.0 - self ._temp_calib [0 ] / 1024.0 ) * self ._temp_calib [1 ]
135+ #print(var1)
136+ var2 = ((raw_temperature / 131072.0 - self ._temp_calib [0 ] / 8192.0 ) * (
137+ raw_temperature / 131072.0 - self ._temp_calib [0 ] / 8192.0 )) * self ._temp_calib [2 ]
138+ #print(var2)
90139
91- var1 = (UT / 16384.0 - self ._temp_calib [0 ] / 1024.0 ) * self ._temp_calib [1 ]
92- var2 = ((UT / 131072.0 - self ._temp_calib [0 ] / 8192.0 ) * (
93- UT / 131072.0 - self ._temp_calib [0 ] / 8192.0 )) * self ._temp_calib [2 ]
140+ self ._t_fine = int (var1 + var2 )
94141 #print("t_fine: ", self.t_fine)
95- t_fine = int (var1 + var2 )
96- temperature = t_fine / 5120.0
97142
98- adc = self ._read24 (_REGISTER_PRESSUREDATA ) / 16
99- var1 = float (t_fine ) / 2.0 - 64000.0
100- var2 = var1 * var1 * self ._pressure_calib [5 ] / 32768.0
101- var2 = var2 + var1 * self ._pressure_calib [4 ] * 2.0
102- var2 = var2 / 4.0 + self ._pressure_calib [3 ] * 65536.0
103- var1 = (self ._pressure_calib [2 ] * var1 * var1 / 524288.0 +
104- self ._pressure_calib [1 ] * var1 ) / 524288.0
105- var1 = (1.0 + var1 / 32768.0 ) * self ._pressure_calib [0 ]
106- if var1 == 0 :
107- return 0
108- p = 1048576.0 - adc
109- p = ((p - var2 / 4096.0 ) * 6250.0 ) / var1
110- var1 = self ._pressure_calib [8 ] * p * p / 2147483648.0
111- var2 = p * self ._pressure_calib [7 ] / 32768.0
112- p = p + (var1 + var2 + self ._pressure_calib [6 ]) / 16.0
113- pressure = p / 100
114- return (temperature , pressure )
143+ def _reset (self ):
144+ """Soft reset the sensor"""
145+ self ._write_register_byte (_REGISTER_SOFTRESET , 0xB6 )
146+ sleep (0.004 ) #Datasheet says 2ms. Using 4ms just to be safe
147+
148+ def _write_ctrl_meas (self ):
149+ """
150+ Write the values to the ctrl_meas register in the device
151+ ctrl_meas sets the pressure and temperature data acquistion options
152+ """
153+ self ._write_register_byte (_REGISTER_CTRL_MEAS , self ._ctrl_meas )
154+
155+ def _get_status (self ):
156+ """Get the value from the status register in the device """
157+ return self ._read_byte (_REGISTER_STATUS )
158+
159+ def _read_config (self ):
160+ """Read the value from the config register in the device """
161+ return self ._read_byte (_REGISTER_CONFIG )
162+
163+ def _write_config (self ):
164+ """Write the value to the config register in the device """
165+ normal_flag = False
166+ if self ._mode == MODE_NORMAL :
167+ #Writes to the config register may be ignored while in Normal mode
168+ normal_flag = True
169+ self .mode = MODE_SLEEP #So we switch to Sleep mode first
170+ self ._write_register_byte (_REGISTER_CONFIG , self ._config )
171+ if normal_flag :
172+ self .mode = MODE_NORMAL
173+
174+ @property
175+ def mode (self ):
176+ """
177+ Operation mode
178+ Allowed values are set in the MODE enum class
179+ """
180+ return self ._mode
181+
182+ @mode .setter
183+ def mode (self , value ):
184+ if not value in _BMP280_MODES :
185+ raise ValueError ('Mode \' %s\' not supported' % (value ))
186+ self ._mode = value
187+ self ._write_ctrl_meas ()
188+
189+ @property
190+ def standby_period (self ):
191+ """
192+ Control the inactive period when in Normal mode
193+ Allowed standby periods are set the STANDBY enum class
194+ """
195+ return self ._t_standby
196+
197+ @standby_period .setter
198+ def standby_period (self , value ):
199+ if not value in _BMP280_STANDBY_TCS :
200+ raise ValueError ('Standby Period \' %s\' not supported' % (value ))
201+ if self ._t_standby == value :
202+ return
203+ self ._t_standby = value
204+ self ._write_config ()
205+
206+ @property
207+ def overscan_temperature (self ):
208+ """
209+ Temperature Oversampling
210+ Allowed values are set in the OVERSCAN enum class
211+ """
212+ return self ._overscan_temperature
213+
214+ @overscan_temperature .setter
215+ def overscan_temperature (self , value ):
216+ if not value in _BMP280_OVERSCANS :
217+ raise ValueError ('Overscan value \' %s\' not supported' % (value ))
218+ self ._overscan_temperature = value
219+ self ._write_ctrl_meas ()
220+
221+ @property
222+ def overscan_pressure (self ):
223+ """
224+ Pressure Oversampling
225+ Allowed values are set in the OVERSCAN enum class
226+ """
227+ return self ._overscan_pressure
228+
229+ @overscan_pressure .setter
230+ def overscan_pressure (self , value ):
231+ if not value in _BMP280_OVERSCANS :
232+ raise ValueError ('Overscan value \' %s\' not supported' % (value ))
233+ self ._overscan_pressure = value
234+ self ._write_ctrl_meas ()
235+
236+ @property
237+ def iir_filter (self ):
238+ """
239+ Controls the time constant of the IIR filter
240+ Allowed values are set in the IIR_FILTER enum class
241+ """
242+ return self ._iir_filter
243+
244+ @iir_filter .setter
245+ def iir_filter (self , value ):
246+ if not value in _BMP280_IIR_FILTERS :
247+ raise ValueError ('IIR Filter \' %s\' not supported' % (value ))
248+ self ._iir_filter = value
249+ self ._write_config ()
250+
251+ @property
252+ def _config (self ):
253+ """Value to be written to the device's config register """
254+ config = 0
255+ if self .mode == MODE_NORMAL :
256+ config += (self ._t_standby << 5 )
257+ if self ._iir_filter :
258+ config += (self ._iir_filter << 2 )
259+ return config
260+
261+ @property
262+ def _ctrl_meas (self ):
263+ """Value to be written to the device's ctrl_meas register """
264+ ctrl_meas = (self .overscan_temperature << 5 )
265+ ctrl_meas += (self .overscan_pressure << 2 )
266+ ctrl_meas += self .mode
267+ return ctrl_meas
268+
269+ @property
270+ def measurement_time_typical (self ):
271+ """Typical time in milliseconds required to complete a measurement in normal mode"""
272+ meas_time_ms = 1
273+ if self .overscan_temperature != OVERSCAN_DISABLE :
274+ meas_time_ms += (2 * _BMP280_OVERSCANS .get (self .overscan_temperature ))
275+ if self .overscan_pressure != OVERSCAN_DISABLE :
276+ meas_time_ms += (2 * _BMP280_OVERSCANS .get (self .overscan_pressure ) + 0.5 )
277+ return meas_time_ms
278+
279+ @property
280+ def measurement_time_max (self ):
281+ """Maximum time in milliseconds required to complete a measurement in normal mode"""
282+ meas_time_ms = 1.25
283+ if self .overscan_temperature != OVERSCAN_DISABLE :
284+ meas_time_ms += (2.3 * _BMP280_OVERSCANS .get (self .overscan_temperature ))
285+ if self .overscan_pressure != OVERSCAN_DISABLE :
286+ meas_time_ms += (2.3 * _BMP280_OVERSCANS .get (self .overscan_pressure ) + 0.575 )
287+ return meas_time_ms
115288
116289 @property
117290 def temperature (self ):
118291 """The compensated temperature in degrees celsius."""
119- return self ._read ()[0 ]
292+ self ._read_temperature ()
293+ return self ._t_fine / 5120.0
120294
121295 @property
122296 def pressure (self ):
123- """The compensated pressure in hectoPascals."""
124- return self ._read ()[1 ]
297+ """
298+ The compensated pressure in hectoPascals.
299+ returns None if pressure measurement is disabled
300+ """
301+ self ._read_temperature ()
302+
303+ # Algorithm from the BMP280 driver
304+ # https://github.com/BoschSensortec/BMP280_driver/blob/master/bmp280.c
305+ adc = self ._read24 (_REGISTER_PRESSUREDATA ) / 16 # lowest 4 bits get dropped
306+ var1 = float (self ._t_fine ) / 2.0 - 64000.0
307+ var2 = var1 * var1 * self ._pressure_calib [5 ] / 32768.0
308+ var2 = var2 + var1 * self ._pressure_calib [4 ] * 2.0
309+ var2 = var2 / 4.0 + self ._pressure_calib [3 ] * 65536.0
310+ var3 = self ._pressure_calib [2 ] * var1 * var1 / 524288.0
311+ var1 = (var3 + self ._pressure_calib [1 ] * var1 ) / 524288.0
312+ var1 = (1.0 + var1 / 32768.0 ) * self ._pressure_calib [0 ]
313+ if not var1 :
314+ return _BMP280_PRESSURE_MIN_HPA
315+ pressure = 1048576.0 - adc
316+ pressure = ((pressure - var2 / 4096.0 ) * 6250.0 ) / var1
317+ var1 = self ._pressure_calib [8 ] * pressure * pressure / 2147483648.0
318+ var2 = pressure * self ._pressure_calib [7 ] / 32768.0
319+ pressure = pressure + (var1 + var2 + self ._pressure_calib [6 ]) / 16.0
320+ pressure /= 100
321+ if pressure < _BMP280_PRESSURE_MIN_HPA :
322+ return _BMP280_PRESSURE_MIN_HPA
323+ if pressure > _BMP280_PRESSURE_MAX_HPA :
324+ return _BMP280_PRESSURE_MAX_HPA
325+ return pressure
125326
126327 @property
127328 def altitude (self ):
0 commit comments