BMP280 高精度大気圧センサーで測定

BMP280 で大気圧を測定します。
BMP280
配線図
Raspberry Pi Pico Pin BMP280 Pin
Pin 36(3V3OUT) VCC
Pin 1(GP0) SDA
Pin 2(GP1) SCL
Pin 3(GND) GND
Pin 36(3V3OUT) VCC
Pin 1(GP0) SDA
Pin 2(GP1) SCL
Pin 3(GND) GND
実際の配線
MicroPythonプログラム
事前準備
ライブラリープログラム bmp280.py
from micropython import const from ustruct import unpack as unp # Author David Stenwall (david at stenwall.io) # Power Modes BMP280_POWER_SLEEP = const(0) BMP280_POWER_FORCED = const(1) BMP280_POWER_NORMAL = const(3) BMP280_SPI3W_ON = const(1) BMP280_SPI3W_OFF = const(0) BMP280_TEMP_OS_SKIP = const(0) BMP280_TEMP_OS_1 = const(1) BMP280_TEMP_OS_2 = const(2) BMP280_TEMP_OS_4 = const(3) BMP280_TEMP_OS_8 = const(4) BMP280_TEMP_OS_16 = const(5) BMP280_PRES_OS_SKIP = const(0) BMP280_PRES_OS_1 = const(1) BMP280_PRES_OS_2 = const(2) BMP280_PRES_OS_4 = const(3) BMP280_PRES_OS_8 = const(4) BMP280_PRES_OS_16 = const(5) # Standby settings in ms BMP280_STANDBY_0_5 = const(0) BMP280_STANDBY_62_5 = const(1) BMP280_STANDBY_125 = const(2) BMP280_STANDBY_250 = const(3) BMP280_STANDBY_500 = const(4) BMP280_STANDBY_1000 = const(5) BMP280_STANDBY_2000 = const(6) BMP280_STANDBY_4000 = const(7) # IIR Filter setting BMP280_IIR_FILTER_OFF = const(0) BMP280_IIR_FILTER_2 = const(1) BMP280_IIR_FILTER_4 = const(2) BMP280_IIR_FILTER_8 = const(3) BMP280_IIR_FILTER_16 = const(4) # Oversampling setting BMP280_OS_ULTRALOW = const(0) BMP280_OS_LOW = const(1) BMP280_OS_STANDARD = const(2) BMP280_OS_HIGH = const(3) BMP280_OS_ULTRAHIGH = const(4) # Oversampling matrix # (PRESS_OS, TEMP_OS, sample time in ms) _BMP280_OS_MATRIX = [ [BMP280_PRES_OS_1, BMP280_TEMP_OS_1, 7], [BMP280_PRES_OS_2, BMP280_TEMP_OS_1, 9], [BMP280_PRES_OS_4, BMP280_TEMP_OS_1, 14], [BMP280_PRES_OS_8, BMP280_TEMP_OS_1, 23], [BMP280_PRES_OS_16, BMP280_TEMP_OS_2, 44] ] # Use cases BMP280_CASE_HANDHELD_LOW = const(0) BMP280_CASE_HANDHELD_DYN = const(1) BMP280_CASE_WEATHER = const(2) BMP280_CASE_FLOOR = const(3) BMP280_CASE_DROP = const(4) BMP280_CASE_INDOOR = const(5) _BMP280_CASE_MATRIX = [ [BMP280_POWER_NORMAL, BMP280_OS_ULTRAHIGH, BMP280_IIR_FILTER_4, BMP280_STANDBY_62_5], [BMP280_POWER_NORMAL, BMP280_OS_STANDARD, BMP280_IIR_FILTER_16, BMP280_STANDBY_0_5], [BMP280_POWER_FORCED, BMP280_OS_ULTRALOW, BMP280_IIR_FILTER_OFF, BMP280_STANDBY_0_5], [BMP280_POWER_NORMAL, BMP280_OS_STANDARD, BMP280_IIR_FILTER_4, BMP280_STANDBY_125], [BMP280_POWER_NORMAL, BMP280_OS_LOW, BMP280_IIR_FILTER_OFF, BMP280_STANDBY_0_5], [BMP280_POWER_NORMAL, BMP280_OS_ULTRAHIGH, BMP280_IIR_FILTER_16, BMP280_STANDBY_0_5] ] _BMP280_REGISTER_ID = const(0xD0) _BMP280_REGISTER_RESET = const(0xE0) _BMP280_REGISTER_STATUS = const(0xF3) _BMP280_REGISTER_CONTROL = const(0xF4) _BMP280_REGISTER_CONFIG = const(0xF5) # IIR filter config _BMP280_REGISTER_DATA = const(0xF7) class BMP280: def __init__(self, i2c_bus, addr=0x76, use_case=BMP280_CASE_HANDHELD_DYN): self._bmp_i2c = i2c_bus self._i2c_addr = addr # read calibration data # < little-endian # H unsigned short # h signed short self._T1 = unp('<H', self._read(0x88, 2))[0] self._T2 = unp('<h', self._read(0x8A, 2))[0] self._T3 = unp('<h', self._read(0x8C, 2))[0] self._P1 = unp('<H', self._read(0x8E, 2))[0] self._P2 = unp('<h', self._read(0x90, 2))[0] self._P3 = unp('<h', self._read(0x92, 2))[0] self._P4 = unp('<h', self._read(0x94, 2))[0] self._P5 = unp('<h', self._read(0x96, 2))[0] self._P6 = unp('<h', self._read(0x98, 2))[0] self._P7 = unp('<h', self._read(0x9A, 2))[0] self._P8 = unp('<h', self._read(0x9C, 2))[0] self._P9 = unp('<h', self._read(0x9E, 2))[0] # output raw self._t_raw = 0 self._t_fine = 0 self._t = 0 self._p_raw = 0 self._p = 0 self.read_wait_ms = 0 # interval between forced measure and readout self._new_read_ms = 200 # interval between self._last_read_ts = 0 if use_case is not None: self.use_case(use_case) def _read(self, addr, size=1): return self._bmp_i2c.readfrom_mem(self._i2c_addr, addr, size) def _write(self, addr, b_arr): if not type(b_arr) is bytearray: b_arr = bytearray([b_arr]) return self._bmp_i2c.writeto_mem(self._i2c_addr, addr, b_arr) def _gauge(self): # TODO limit new reads # read all data at once (as by spec) d = self._read(_BMP280_REGISTER_DATA, 6) self._p_raw = (d[0] << 12) + (d[1] << 4) + (d[2] >> 4) self._t_raw = (d[3] << 12) + (d[4] << 4) + (d[5] >> 4) self._t_fine = 0 self._t = 0 self._p = 0 def reset(self): self._write(_BMP280_REGISTER_RESET, 0xB6) def load_test_calibration(self): self._T1 = 27504 self._T2 = 26435 self._T3 = -1000 self._P1 = 36477 self._P2 = -10685 self._P3 = 3024 self._P4 = 2855 self._P5 = 140 self._P6 = -7 self._P7 = 15500 self._P8 = -14600 self._P9 = 6000 def load_test_data(self): self._t_raw = 519888 self._p_raw = 415148 def print_calibration(self): print("T1: {} {}".format(self._T1, type(self._T1))) print("T2: {} {}".format(self._T2, type(self._T2))) print("T3: {} {}".format(self._T3, type(self._T3))) print("P1: {} {}".format(self._P1, type(self._P1))) print("P2: {} {}".format(self._P2, type(self._P2))) print("P3: {} {}".format(self._P3, type(self._P3))) print("P4: {} {}".format(self._P4, type(self._P4))) print("P5: {} {}".format(self._P5, type(self._P5))) print("P6: {} {}".format(self._P6, type(self._P6))) print("P7: {} {}".format(self._P7, type(self._P7))) print("P8: {} {}".format(self._P8, type(self._P8))) print("P9: {} {}".format(self._P9, type(self._P9))) def _calc_t_fine(self): # From datasheet page 22 self._gauge() if self._t_fine == 0: var1 = (((self._t_raw >> 3) - (self._T1 << 1)) * self._T2) >> 11 var2 = (((((self._t_raw >> 4) - self._T1) * ((self._t_raw >> 4) - self._T1)) >> 12) * self._T3) >> 14 self._t_fine = var1 + var2 @property def temperature(self): self._calc_t_fine() if self._t == 0: self._t = ((self._t_fine * 5 + 128) >> 8) / 100. return self._t @property def pressure(self): # From datasheet page 22 self._calc_t_fine() if self._p == 0: var1 = self._t_fine - 128000 var2 = var1 * var1 * self._P6 var2 = var2 + ((var1 * self._P5) << 17) var2 = var2 + (self._P4 << 35) var1 = ((var1 * var1 * self._P3) >> 8) + ((var1 * self._P2) << 12) var1 = (((1 << 47) + var1) * self._P1) >> 33 if var1 == 0: return 0 p = 1048576 - self._p_raw p = int((((p << 31) - var2) * 3125) / var1) var1 = (self._P9 * (p >> 13) * (p >> 13)) >> 25 var2 = (self._P8 * p) >> 19 p = ((p + var1 + var2) >> 8) + (self._P7 << 4) self._p = p / 256.0 return self._p def _write_bits(self, address, value, length, shift=0): d = self._read(address)[0] m = int('1' * length, 2) << shift d &= ~m d |= m & value << shift self._write(address, d) def _read_bits(self, address, length, shift=0): d = self._read(address)[0] return d >> shift & int('1' * length, 2) @property def standby(self): return self._read_bits(_BMP280_REGISTER_CONFIG, 3, 5) @standby.setter def standby(self, v): assert 0 <= v <= 7 self._write_bits(_BMP280_REGISTER_CONFIG, v, 3, 5) @property def iir(self): return self._read_bits(_BMP280_REGISTER_CONFIG, 3, 2) @iir.setter def iir(self, v): assert 0 <= v <= 4 self._write_bits(_BMP280_REGISTER_CONFIG, v, 3, 2) @property def spi3w(self): return self._read_bits(_BMP280_REGISTER_CONFIG, 1) @spi3w.setter def spi3w(self, v): assert v in (0, 1) self._write_bits(_BMP280_REGISTER_CONFIG, v, 1) @property def temp_os(self): return self._read_bits(_BMP280_REGISTER_CONTROL, 3, 5) @temp_os.setter def temp_os(self, v): assert 0 <= v <= 5 self._write_bits(_BMP280_REGISTER_CONTROL, v, 3, 5) @property def press_os(self): return self._read_bits(_BMP280_REGISTER_CONTROL, 3, 2) @press_os.setter def press_os(self, v): assert 0 <= v <= 5 self._write_bits(_BMP280_REGISTER_CONTROL, v, 3, 2) @property def power_mode(self): return self._read_bits(_BMP280_REGISTER_CONTROL, 2) @power_mode.setter def power_mode(self, v): assert 0 <= v <= 3 self._write_bits(_BMP280_REGISTER_CONTROL, v, 2) @property def is_measuring(self): return bool(self._read_bits(_BMP280_REGISTER_STATUS, 1, 3)) @property def is_updating(self): return bool(self._read_bits(_BMP280_REGISTER_STATUS, 1)) @property def chip_id(self): return self._read(_BMP280_REGISTER_ID, 1) @property def in_normal_mode(self): return self.power_mode == BMP280_POWER_NORMAL def force_measure(self): self.power_mode = BMP280_POWER_FORCED def normal_measure(self): self.power_mode = BMP280_POWER_NORMAL def sleep(self): self.power_mode = BMP280_POWER_SLEEP def use_case(self, uc): assert 0 <= uc <= 5 pm, oss, iir, sb = _BMP280_CASE_MATRIX[uc] p_os, t_os, self.read_wait_ms = _BMP280_OS_MATRIX[oss] self._write(_BMP280_REGISTER_CONFIG, (iir << 2) + (sb << 5)) self._write(_BMP280_REGISTER_CONTROL, pm + (p_os << 2) + (t_os << 5)) def oversample(self, oss): assert 0 <= oss <= 4 p_os, t_os, self.read_wait_ms = _BMP280_OS_MATRIX[oss] self._write_bits(_BMP280_REGISTER_CONTROL, p_os + (t_os << 3), 2)
実行プログラム
from machine import Pin,I2C from bmp280 import * import time bus = I2C(0,scl=Pin(1),sda=Pin(0),freq=200000) bmp = BMP280(bus) bmp.use_case(BMP280_CASE_INDOOR) while True: pressure=bmp.pressure p_bar=pressure/100000 p_mmHg=pressure/133.3224 temperature=bmp.temperature print("Temperature: {} C".format(temperature)) print("Pressure: {} Pa, {} bar, {} mmHg".format(pressure,p_bar,p_mmHg)) time.sleep(1)
実行
自由研究

テンテン
OLED ディスプレイに BMP280 データを表示してみましょう。
詳しくはWEBで見てやってみよう。