RaspberryPi ZeroでI2C。BME280で温度を。

全然BLOGに手をつけてなく電子工作グダグダやってました。
流れ的にI2Cなので定番のBME280での温度・湿度・気圧測定です。

必要なもの一式組み込みます。(Python3ベース)

$ sudo apt-get -y install python3-dev
$ sudo apt-get -y install python3-pip # pip3 入れる
$ sudo apt-get -y install python3-gpiozero # pinout 使えるようにしてみる
$ sudo apt-get -y install i2c-tools # pi OS(lite) には入ってないっぽい

モジュール[smbus2]入れます

$ pip3 install smbus2

BME280はデータシート見ながら&Python勉強。と
ソースぐちゃぐちゃですが貼り付けます。

#--------------------------------------------------------------------------------
#   0x80 ~ 0xA1 R   調整データ              dig.T1 ~ T3,dig.P1 ~ P9,dig_H1	19?
#   0xD0        R   チップID                chip_id     [7-0]
#   0xE0        W   リセット                reset       [7-0]
#   0xE1 ~ 0xF0 R   調整データ              dig.H2 ~ H6
#   0xF2        R/W 制御レジスタ            osrs_h[2-0]
#   0xF3        R   ステータス              measuring,im_up_date
#   0xF4        R/W 制御レジスタ            osrc_t[2-0],osrs_p[2-0],mode[1-0]
#   0xF5        R/W 設定レジスタ            t_sb[2-0],filter[2-0],pi3w_en
#   0xF7        R   圧力測定データ(HIGH)   press.msb   [7-0]
#   0xF8        R   圧力測定データ(LOW)    press.lsb   [7-0]
#   0xF9        R   圧力測定データ(exLOW)  press.xlsb  [7-4]
#   0xFA        R   温度測定データ (HIGH)   temp.msb    [7-0]
#   0xFB        R   温度測定データ (LOW)    temp.lsb    [7-0]
#   0xFC        R   温度測定データ (exLOW)  temp.xlsb   [7-4]
#   0xFD        R   湿度測定データ(HIGH)   press.lsb   [7-0]
#   0xFE        R   湿度測定データ(LOW)    press.lsb   [7-0]
#--------------------------------------------------------------------------------
from smbus2 import SMBus

bus_number  = 1
i2c_address = 0x76

bus = SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0
#--------------------------------------------------------------------------------
#   Register Write
#--------------------------------------------------------------------------------
def writeReg(reg_address, data):
    bus.write_byte_data(i2c_address,reg_address,data)
#--------------------------------------------------------------------------------
#   flg:0 DWORD,1:WORD,2:BYTE
#--------------------------------------------------------------------------------
_DWORD = 0
_WORD  = 1
_BYTE  = 3
def unsigned2long(dt,flg=1):
    cf = 0x80000000
    mk = 0xffffffff
    if flg & 1:
        cf >>= 16
        mk >>= 16
    if flg & 2:
        cf >>= 8
        mk >>= 8
    if dt & cf:    dt = (-dt ^ mk)+1
    return dt;
#--------------------------------------------------------------------------------
#   キャリブレーション
#       0x88 - 0x8D     T1(WORD),T2,T3(short)  6Byte
#       0x8E - 0x9F     P1(WORD),P2-P9(short) 18Byte
#       0xA1            H1(BYTE)
#       0xE1            H1(BYTE)
#--------------------------------------------------------------------------------
def get_calib_param():
    #----------------------------------------------------------------------------
    #   T1 ~ T3
    for i in list(range(0x88,0x8E,2)):
        digT.append(bus.read_word_data(i2c_address,i))
    #----------------------------------------------------------------------------
    #   P1 - P9
    for i in list(range(0x8E,0xA0,2)):
        digP.append(bus.read_word_data(i2c_address,i))
    #----------------------------------------------------------------------------
    #   H1 - H6
    digH.append(bus.read_byte_data(i2c_address,0xA1))       #H1
    digH.append(bus.read_word_data(i2c_address,0xE1))       #H2
    digH.append(bus.read_byte_data(i2c_address,0xE3))       #H3
    t = bus.read_word_data(i2c_address,0xE4)
    digH.append(((t & 0xFF) << 4) | ((t >> 8) & 0x0F))      #H4 0xE4 / 0xE5[3-0] => [11-4]/[3-0]
    t = (t >> 12) & 0x0F
    t = t | (bus.read_byte_data(i2c_address,0xE6) << 4) digH.append(t) #H5 0xE5[7-4] / 0xE6 => [3-0]/[11-4]
    digH.append(bus.read_byte_data(i2c_address,0xE7))       #H6
    #----------------------------------------------------------------------------
    # sign Flip
    # T2,T3     : (short)
    for i in range(1,2):    digT[i] = unsigned2long(digT[i],_WORD)
    # P2 ~ P9   : (short)
    for i in range(1,9):    digP[i] = unsigned2long(digP[i],_WORD)
    # H2,H4,H5  : (short)
    for i in [1,3,4]:       digH[i] = unsigned2long(digH[i],_WORD)
    # H6        : (char)
    digH[5] = unsigned2long(digH[5],_BYTE)
#--------------------------------------------------------------------------------
#   データ読み込み
#       0xF7 ~ 0xFE
#--------------------------------------------------------------------------------
def readData():
    data = []
    for i in range (0xF7, 0xF7+8):
        data.append(bus.read_byte_data(i2c_address,i))
    p_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
    t_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
    h_raw = (data[6] <<  8) |  data[7]

    t = compensate_T(t_raw)
    p = compensate_P(p_raw)
    h = compensate_H(h_raw)
    d = 0.81 * t + 0.01 * h * (0.99 * t - 14.3) + 46.3
    return [t,p,h,d]
#--------------------------------------------------------------------------------
#   圧力
#--------------------------------------------------------------------------------
def compensate_P(adc_P):
    global  t_fine
    pressure = 0.0

    v1 = (t_fine / 2.0) - 64000.0
    v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
    v2 = v2 + ((v1 * digP[4]) * 2.0)
    v2 = (v2 / 4.0) + (digP[3] * 65536.0)
    v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
    v1 = ((32768 + v1) * digP[0]) / 32768

    if v1 == 0:
        return 0
    pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
    if pressure < 0x80000000: pressure = (pressure * 2.0) / v1 else: pressure = (pressure / v1) * 2 v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096 v2 = ((pressure / 4.0) * digP[7]) / 8192.0 pressure = pressure + ((v1 + v2 + digP[6]) / 16.0) # print ("pressure:%7.2f hPa" % (pressure/100)) return pressure/100 #-------------------------------------------------------------------------------- # 温度 #-------------------------------------------------------------------------------- def compensate_T(adc_T): global t_fine v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1] v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2] t_fine = v1 + v2 return t_fine / 5120.0 #-------------------------------------------------------------------------------- # 湿度 #-------------------------------------------------------------------------------- def compensate_H(adc_H): global t_fine var_h = t_fine - 76800.0 if var_h != 0: var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) var_h *= (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h))) else: return 0 var_h = var_h * (1.0 - digH[0] * var_h / 524288.0) if var_h > 100.0:   var_h = 100.0
    elif var_h <   0.0:   var_h =   0.0
    return var_h
#--------------------------------------------------------------------------------
#   Setup
#       0xF2    [00000hhh]  osrs_h  湿度 over sampling 0:skip 1:x1 2:x2 3:x4 4:x8 5~:x16
#       0xF4    [tttpppmm]  osrs_t  温度 over sampling 0:skip 1:x1 2:x2 3:x4 4:x8 5~:x16
#                           osrs_p  圧力 over sampling 0:skip 1:x1 2:x2 3:x4 4:x8 5~:x16
#                           mode    デバイスのセンサーモード
#                                       0  : スリープ
#                                       1-2: 強制
#                                       3  : 通常
#       0xF5    [tttfff0i]  t_sb    通常モードでの休止状態の継続時間
#                                       0:   0.5ms
#                                       1:  62.5ms
#                                       2: 125.0ms
#                                       3: 250.0ms
#                                       4: 500.0ms
#                                       5:1000.0ms
#                                       6:  10.0ms
#                                       7:  20.0ms
#                           filter  0:OFF 1:2 2:4 3:8 5~:16
#                           spi3w   0:4WireSPI 1:3WireSPI
#--------------------------------------------------------------------------------
def setup():
    osrs_h  = (1     )      # 湿度 oversampling x 1
    osrs_t  = (1 << 5)      # 温度 oversampling x 1
    osrs_p  = (1 << 2)      # 圧力 oversampling x 1
    mode    = (3     )      # Normal mode
    t_sb    = (5 << 5)      # Tstandby 1000ms
    filter  = (0 << 2)      # Filter off
    spi3w   = (0     )      # 3-wire SPI Disable

    writeReg(0xF2,osrs_h                 )   # 制御レジスター osrs_h[2-0]
    writeReg(0xF4,osrs_t | osrs_p | mode )   # 制御レジスター osrs_t[2-0] osrs_p[2-0] mode[1-0]
    writeReg(0xF5,t_sb   | filter | spi3w)   # 設定レジスター t_sb [2-0] , filter [2-0] , pi3w_en
#--------------------------------------------------------------------------------
#   Start!
#       Addr:0xD0 chip_id [0x56,0x57,0x58:BMP280] / [0x60:BME280]
#--------------------------------------------------------------------------------
setup()             # 初期化
get_calib_param()   # チップ固有の個体差パラメータ読込

if __name__ == '__main__':
    chip_id = bus.read_byte_data(i2c_address,0xD0);
    if chip_id == 0x60:     print("BME280")
    else:                   print("BMP280")

    try:
        dat = readData()
        print("温度:%-3.2f℃" % dat[0])
        print("気圧:%7.2fhPa" % dat[1])
        print("湿度:%6.2f%"  % dat[2])
        print("不快指数:%3.2f"% dat[3])
    except KeyboardInterrupt:
        pass
#--------------------------------------------------------------------------------
#EOF

チップの型番チェックとモジュールとして呼び出しができるように設定しています。
不快指数も計算してみました。

>>> %Run bme280.py
BME280
温度:27.78℃
気圧:1007.67hPa
湿度: 35.88%
不快指数:73.53

コメント

タイトルとURLをコピーしました