20
20
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
# THE SOFTWARE.
22
22
"""
23
- `adafruit_bmp280`
24
- ====================================================
23
+ `adafruit_bmp280` - Adafruit BMP280 - Temperature & Barometic Pressure Sensor
24
+ ===============================================================================
25
25
26
26
CircuitPython driver from BMP280 Temperature and Barometic Pressure sensor
27
27
28
28
* Author(s): ladyada
29
29
"""
30
30
import math
31
- import time
31
+ from time import sleep
32
32
try :
33
33
import struct
34
34
except ImportError :
35
35
import ustruct as struct
36
-
37
36
from micropython import const
38
37
39
38
__version__ = "0.0.0-auto.0"
45
44
46
45
_REGISTER_CHIPID = const (0xD0 )
47
46
_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)
59
47
_REGISTER_SOFTRESET = const (0xE0 )
60
48
_REGISTER_STATUS = const (0xF3 )
61
- _REGISTER_CONTROL = const (0xF4 )
49
+ _REGISTER_CTRL_MEAS = const (0xF4 )
62
50
_REGISTER_CONFIG = const (0xF5 )
63
51
_REGISTER_PRESSUREDATA = const (0xF7 )
64
52
_REGISTER_TEMPDATA = const (0xFA )
65
53
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
+
66
102
class Adafruit_BMP280 : # pylint: disable=invalid-name
67
103
"""Base BMP280 object. Use `Adafruit_BMP280_I2C` or `Adafruit_BMP280_SPI` instead of this. This
68
104
checks the BMP280 was found, reads the coefficients and enables the sensor for continuous
@@ -72,56 +108,221 @@ def __init__(self):
72
108
chip_id = self ._read_byte (_REGISTER_CHIPID )
73
109
if _CHIP_ID != chip_id :
74
110
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 ()
75
118
self ._read_coefficients ()
119
+ self ._write_ctrl_meas ()
120
+ self ._write_config ()
76
121
self .sea_level_pressure = 1013.25
77
122
"""Pressure in hectoPascals at sea level. Used to calibrate `altitude`."""
123
+ self ._t_fine = None
78
124
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
89
133
#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)
90
139
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 )
94
141
#print("t_fine: ", self.t_fine)
95
- t_fine = int (var1 + var2 )
96
- temperature = t_fine / 5120.0
97
142
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
115
288
116
289
@property
117
290
def temperature (self ):
118
291
"""The compensated temperature in degrees celsius."""
119
- return self ._read ()[0 ]
292
+ self ._read_temperature ()
293
+ return self ._t_fine / 5120.0
120
294
121
295
@property
122
296
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
125
326
126
327
@property
127
328
def altitude (self ):
0 commit comments