大気圧センサー(BMP180)

工具箱をあさったら、I2C接続で使用できる大気圧センサーを見つけたので使用してみようかと思います

 

まずはモノ。単品でも、キットに付属でも入手できそうです



データシートです

これをある程度読み取れれば、使用可能です

https://www.sparkfun.com/datasheets/Components/General/BST-BMP085-DS000-05.pdf

 

サンプルプログラムです。

公式(?)のものも見つかりますが、動かなかったので手を入れています

このセンサーは温度センサーもついており、大気圧の算出に、その温度センサーの値も使用します

1秒ごとにセンサーから読み取り、温度と気圧をprintしてみているだけです

なお、1クラス1ファイルにする慣習があるようですが、このサンプルは2クラスと実行ルーチンを1ファイルにしてしまっています(適宜分けてもOK)

from time import sleep
import smbus

''' i2cクラス '''
class i2c:
    # i2c オブジェクト
    i2c = None
    # i2c アドレス
    ADR = None
    
    ''' コンストラクタ '''
    def __init__(self, adr, bus = 1) -> None:
        self.ADR = adr
        self.i2c = smbus.SMBus(bus)

    ''' 符号あり8ビット読込 '''
    def readS8(self, register):
        result = self.i2c.read_byte_data(self.ADR, register)
        if result > 127:
            # 符号算出
            result -= 256
        return result

    ''' 符号あり16ビット読込(アドレス値は指定8ビット と 指定8ビット + 1) '''
    def readS16(self, register):
        hi = self.readS8(register)
        lo = self.readU8(register+1)
        return (hi << 8) + lo

    ''' 符号なし8ビット読込 '''
    def readU8(self, register):
        result = self.i2c.read_byte_data(self.ADR, register)
        return result

    ''' 符号なし16ビット読込(アドレス値は指定8ビット と 指定8ビット + 1) '''
    def readU16(self, register):
        hi = self.readU8(register)
        lo = self.readU8(register+1)
        return (hi << 8) + lo

    ''' 指定ブロック読込 '''
    def readBlockData(self, register, blocks):
        block = self.i2c.read_i2c_block_data(self.ADR, register, blocks)
        return block

    ''' 8ビット書込 '''
    def write8(self, register, value):
        self.i2c.write_byte_data(self.ADR, register, value)

    ''' 8ビット書込 '''
    def writeByte(self, value):
        self.i2c.write_byte(self.ADR, value)
    
class BMP085:
    BMP085_CAL_AC1           = 0xAA
    BMP085_CAL_AC2           = 0xAC
    BMP085_CAL_AC3           = 0xAE
    BMP085_CAL_AC4           = 0xB0
    BMP085_CAL_AC5           = 0xB2
    BMP085_CAL_AC6           = 0xB4
    BMP085_CAL_B1            = 0xB6
    BMP085_CAL_B2            = 0xB8
    BMP085_CAL_MB            = 0xBA
    BMP085_CAL_MC            = 0xBC
    BMP085_CAL_MD            = 0xBE
    BMP085_CONTROL           = 0xF4
    BMP085_TEMPDATA          = 0xF6
    BMP085_PRESSUREDATA      = 0xF6
    BMP085_READTEMPCMD       = 0x2E
    BMP085_READPRESSURECMD   = 0x34
    MODE                     = 3
    WAIT_TIME                = [0.005, 0.014, 0.008, 0.026]
    I2C_ADR                  = 0x77
    i2c                      = None   

    ''' コンストラクタ '''
    def __init__(self) -> None:
        # i2cオブジェクト
        self.i2c = i2c(self.I2C_ADR)

    ''' キャリブレーション '''
    def calibration(self):
        # キャリブレーションデータ読込
        self.cal_AC1 = self.i2c.readS16(self.BMP085_CAL_AC1)
        self.cal_AC2 = self.i2c.readS16(self.BMP085_CAL_AC2)
        self.cal_AC3 = self.i2c.readS16(self.BMP085_CAL_AC3)
        self.cal_AC4 = self.i2c.readU16(self.BMP085_CAL_AC4)
        self.cal_AC5 = self.i2c.readU16(self.BMP085_CAL_AC5)
        self.cal_AC6 = self.i2c.readU16(self.BMP085_CAL_AC6)
        self.cal_B1 =  self.i2c.readS16(self.BMP085_CAL_B1)
        self.cal_B2 =  self.i2c.readS16(self.BMP085_CAL_B2)
        self.cal_MB =  self.i2c.readS16(self.BMP085_CAL_MB)
        self.cal_MC =  self.i2c.readS16(self.BMP085_CAL_MC)
        self.cal_MD =  self.i2c.readS16(self.BMP085_CAL_MD)

    ''' センサーから温度を取得 '''
    def readUncpmpensatedTemp(self):
        self.i2c.write8(self.BMP085_CONTROL, self.BMP085_READTEMPCMD)
        sleep(0.026)
        raw = self.i2c.readU16(self.BMP085_TEMPDATA)
        return raw

    ''' センサーから気圧を取得 '''
    def readUncpmpensatedPressure(self):
        self.i2c.write8(self.BMP085_CONTROL, self.BMP085_READPRESSURECMD + (self.MODE << 6))
        sleep(self.WAIT_TIME[self.MODE])
        msb = self.i2c.readU8(self.BMP085_PRESSUREDATA)
        lsb = self.i2c.readU8(self.BMP085_PRESSUREDATA+1)
        xlsb = self.i2c.readU8(self.BMP085_PRESSUREDATA+2)
        raw = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - self.MODE)

        return raw

    ''' 温度と気圧を算出 '''
    def calcTemperaturePressure(self):
        UT = self.readUncpmpensatedTemp()
        UP = self.readUncpmpensatedPressure()

        X1 = ((UT - self.cal_AC6) * self.cal_AC5) / 32768
        X2 = (self.cal_MC * 2048) / (X1 + self.cal_MD)
        B5 = X1 + X2
        B6 = B5 - 4000
        X1 = (self.cal_B2 * (B6 * B6) / 4096) / 2048
        X2 = (self.cal_AC2 * B6) / 2048
        X3 = X1 + X2

        # 温度を算出しておく
        temp = (B5 + 8) / 16 / 10

        B3 = (((self.cal_AC1 * 4 + X3) * ( 2 ** self.MODE)) + 2) / 4
        X1 = (self.cal_AC3 * B6) / 8192
        X2 = (self.cal_B1 * ((B6 * B6) / 4096)) / 65536
        X3 = ((X1 + X2) + 2) / 4
        B4 = (self.cal_AC4 * (X3 + 32768)) / 32768
        B7 = (UP - B3) * (50000 >> self.MODE)

        if (B7 < 0x80000000):
            press = int((B7 * 2) / B4)
        else:
            press = int((B7 / B4) * 2)
       
        X1 = (press / 256 ) * (press / 256)
        X1 = (X1 * 3038) / 65536
        X2 = (-7357 * press)  / 65536

        press = press + ((X1 + X2 + 3791) / 16)

        return temp, press

# インスタンス生成
bmp = BMP085()
# 初期化
bmp.calibration()

while True:
    # 気温と気圧を取得
    tempPress = bmp.calcTemperaturePressure()

    # 表示
    print(f'temp: {str(tempPress[0])[:5]} C')
    print(f'prss: {str(tempPress[1] / 100.0 )[:6]} hPa')

    sleep(1)