Raspberry Pi 4 + Python3入門 <STEP1> (5) 7セグメントLED 74HC595 その5 BME280をネイティブにアクセス②

 前回、センサBME280の温度だけ取得しました。湿度と気圧のデータも読み出します。

補償データを全部読み出し気圧を求める

 気圧の補償値は温度と同じく9個のレジスタを読み出すだけです。また、変換スタートも温度と同じレジスタCtrl_registerの操作でできます。
 温度の読み出しの途中で変数t_fineが求まります。この変数の値は、気圧や湿度でも計算に利用するので、global変数にしています。

 補正で得られたデータはPaなので、100で割って単位をhPaにします。

# Copyright (c) 2014 Adafruit Industries、 Author: Tony DiCola
# https://github.com/adafruit/Adafruit_Python_BME280/blob/master/Adafruit_BME280.py  , https://github.com/adafruit/Adafruit_Python_GPIO/blob/master/Adafruit_GPIO/I2C.py

import smbus, time
import LED7seg_595 as LED7

BME280_address = 0x76
ID_register = 0xd0
Ctrl_hum = 0xf2
Ctrl_register = 0xf4
Config_reg = 0xf5
Temp_register = 0xfa
Press_register = 0xf7
Hum_register = 0xfd

osrs_t = 0b00100000 # Temp oversampling x 1
osrs_p = 0b00000100 # Press oversampling x 1
osrs_h = 0b00000001 # Humidity oversampling x 1
mode_normal = 0b00000011
t_sb = 0b10100000 # Tstandby 1000ms
filter = 0 # Filter off
t_fine = 0.0

i2c = smbus.SMBus(1)

def readU8(dig_registor):
temp = i2c.read_byte_data(BME280_address, dig_registor)
return temp & 0xff

def readS8(dig_registor):
result = readU8(dig_registor)
if result > 127:
result -= 256
return result

def readU16(dig_registor):
temp = i2c.read_word_data(BME280_address, dig_registor)
return temp & 0xffff

def readS16(dig_registor):
result = readU16(dig_registor)
if result > 32767:
result -= 65536
return result

def read_temp():
global t_fine
temp = i2c.read_i2c_block_data(BME280_address, Temp_register, 3)
temperature = float((temp[0] << 16 | temp[1] << 8 | temp[2] ) >> 4)
var1 = (temperature / 16384.0 - float(dig_T1) / 1024.0) * float(dig_T2)
var2 = ((temperature / 131072.0 - float(dig_T1) / 8192.0) * (temperature / 131072.0 - float(dig_T1) / 8192.0)) * float(dig_T3)
t_fine = int(var1 + var2)
T = (var1 + var2) / 5120.0
return T

def read_press():
global t_fine
temp = i2c.read_i2c_block_data(BME280_address, Press_register, 3)
press = float((temp[0] << 16 | temp[1] << 8 | temp[2] ) >> 4)
var1 = float(t_fine) / 2.0 - 64000.0
var2 = var1 * var1 * float(dig_P6) / 32768.0
var2 = var2 + var1 * float(dig_P5) * 2.0
var2 = var2 / 4.0 + float(dig_P4) * 65536.0
var1 = (float(dig_P3) * var1 * var1 / 524288.0 + float(dig_P2) * var1) / 524288.0
var1 = (1.0 + var1 / 32768.0) * float(dig_P1)
if var1 == 0:
return 0
p = 1048576.0 - press
p = ((p - var2 / 4096.0) * 6250.0) / var1
var1 = float(dig_P9) * p * p / 2147483648.0
var2 = p * float(dig_P8) / 32768.0
p = p + (var1 + var2 + float(dig_P7)) / 16.0
return p

i2c.write_i2c_block_data(BME280_address, Ctrl_hum, [osrs_h])
i2c.write_i2c_block_data(BME280_address, Ctrl_register, [osrs_t | osrs_p | mode_normal])
i2c.write_i2c_block_data(BME280_address, Config_reg, [t_sb | filter])

dig_T1 = readU16(0x88)
dig_T2 = readS16(0x8A)
dig_T3 = readS16(0x8C)

dig_P1 = readU16(0x8E)
dig_P2 = readS16(0x90)
dig_P3 = readS16(0x92)
dig_P4 = readS16(0x94)
dig_P5 = readS16(0x96)
dig_P6 = readS16(0x98)
dig_P7 = readS16(0x9A)
dig_P8 = readS16(0x9C)
dig_P9 = readS16(0x9E)

dig_H1 = readU8(0xA1)
dig_H2 = readS16(0xE1) # readS16LE
dig_H3 = readU8(0xE3)
dig_H6 = readS8(0xE7)

h4 = readS8(0xE4)
h4 = (h4 << 4)
dig_H4 = h4 | (readU8(0xE5) & 0x0F)

h5 = readS8(0xE6)
h5 = (h5 << 4)
dig_H5 = h5 | (readU8(0xE5) >> 4 & 0x0F)

print('temperature ',round(read_temp(),2))
LED7.disp7seg(round(read_temp(),1))

print('press ',round((read_press()/100.0),2))

time.sleep(3.14)

 実行例です。


湿度

 湿度の補償値は、レジスタから読み出すだけでは得られません。106~115行のように、一部計算をします。湿度のデータは2バイトです。

# Copyright (c) 2014 Adafruit Industries、 Author: Tony DiCola
# https://github.com/adafruit/Adafruit_Python_BME280/blob/master/Adafruit_BME280.py  , https://github.com/adafruit/Adafruit_Python_GPIO/blob/master/Adafruit_GPIO/I2C.py

import smbus, time
import LED7seg_595 as LED7

BME280_address = 0x76
ID_register = 0xd0
Ctrl_hum = 0xf2
Ctrl_register = 0xf4
Config_reg = 0xf5
Temp_register = 0xfa
Press_register = 0xf7
Hum_register = 0xfd

osrs_t = 0b00100000 # Temp oversampling x 1
osrs_p = 0b00000100 # Press oversampling x 1
osrs_h = 0b00000001 # Humidity oversampling x 1
mode_normal = 0b00000011
t_sb = 0b10100000 # Tstandby 1000ms
filter = 0 # Filter off
t_fine = 0.0

i2c = smbus.SMBus(1)

def readU8(dig_registor):
temp = i2c.read_byte_data(BME280_address, dig_registor)
return temp & 0xff

def readS8(dig_registor):
result = readU8(dig_registor)
if result > 127:
result -= 256
return result

def readU16(dig_registor):
temp = i2c.read_word_data(BME280_address, dig_registor)
return temp & 0xffff

def readS16(dig_registor):
result = readU16(dig_registor)
if result > 32767:
result -= 65536
return result

def read_temp():
global t_fine
temp = i2c.read_i2c_block_data(BME280_address, Temp_register, 3)
temperature = float((temp[0] << 16 | temp[1] << 8 | temp[2] ) >> 4)
var1 = (temperature / 16384.0 - float(dig_T1) / 1024.0) * float(dig_T2)
var2 = ((temperature / 131072.0 - float(dig_T1) / 8192.0) * (temperature / 131072.0 - float(dig_T1) / 8192.0)) * float(dig_T3)
t_fine = int(var1 + var2)
T = (var1 + var2) / 5120.0
return T

def read_press():
global t_fine
temp = i2c.read_i2c_block_data(BME280_address, Press_register, 3)
press = float((temp[0] << 16 | temp[1] << 8 | temp[2] ) >> 4)
var1 = float(t_fine) / 2.0 - 64000.0
var2 = var1 * var1 * float(dig_P6) / 32768.0
var2 = var2 + var1 * float(dig_P5) * 2.0
var2 = var2 / 4.0 + float(dig_P4) * 65536.0
var1 = (float(dig_P3) * var1 * var1 / 524288.0 + float(dig_P2) * var1) / 524288.0
var1 = (1.0 + var1 / 32768.0) * float(dig_P1)
if var1 == 0:
return 0
P = 1048576.0 - press
P = ((P - var2 / 4096.0) * 6250.0) / var1
var1 = float(dig_P9) * P * P / 2147483648.0
var2 = P * float(dig_P8) / 32768.0
P = P + (var1 + var2 + float(dig_P7)) / 16.0
return P

def read_humidity():
global t_fine
temp = i2c.read_i2c_block_data(BME280_address, Hum_register, 2)
hum = float(temp[0] << 8 | temp[1])
H = float(t_fine) - 76800.0
H = (hum - (float(dig_H4) * 64.0 + float(dig_H5) / 16384.0 * H)) * (float(dig_H2) / 65536.0 * (1.0 + float(dig_H6) / 67108864.0 * H * (1.0 + float(dig_H3) / 67108864.0 * H)))
H = H * (1.0 - float(dig_H1) * H / 524288.0)
if H > 100:
H = 100
elif H < 0:
H = 0
return H

i2c.write_i2c_block_data(BME280_address, Ctrl_hum, [osrs_h])
i2c.write_i2c_block_data(BME280_address, Ctrl_register, [osrs_t | osrs_p | mode_normal])
i2c.write_i2c_block_data(BME280_address, Config_reg, [t_sb | filter])

dig_T1 = readU16(0x88)
dig_T2 = readS16(0x8A)
dig_T3 = readS16(0x8C)

dig_P1 = readU16(0x8E)
dig_P2 = readS16(0x90)
dig_P3 = readS16(0x92)
dig_P4 = readS16(0x94)
dig_P5 = readS16(0x96)
dig_P6 = readS16(0x98)
dig_P7 = readS16(0x9A)
dig_P8 = readS16(0x9C)
dig_P9 = readS16(0x9E)

dig_H1 = readU8(0xA1)
dig_H2 = readS16(0xE1) # readS16LE
dig_H3 = readU8(0xE3)
dig_H6 = readS8(0xE7)
h4 = readS8(0xE4)
h4 = (h4 << 4)
dig_H4 = h4 | (readU8(0xE5) & 0x0F)
h5 = readS8(0xE6)
h5 = (h5 << 4)
dig_H5 = h5 | (readU8(0xE5) >> 4 & 0x0F)

print('temperature ',round(read_temp(),2))
LED7.disp7seg(round(read_temp(),1))

print('press ',round((read_press()/100.0),2))

print('humidity ',round(read_humidity(),2))

time.sleep(3.14)

 実行例です。それぞれの測定値の小数点は、デバイスのもつ確度を考慮したものではありません。動作確認をするために小数点第2位まで表示しています。

(※) 本Webのプログラム中、インデントなどのスペースもしくは改行は、通常のプログラム内ではごみ文字になるので、コピペした後、エディタでスペース文字などを入れなおしてください。