自由に工作中

マイコンについて学習しています

気温センサーBMP180のI2C読み取り

Rasberry Pi Picoを用いたI2Cの読み取りについての備忘録です。

 

プログラミング初心者なので、センサーのデータを読むことが出来ただけで

大分進歩した感じで、非常に嬉しいものです。

 

気温/気圧/高度センサーのBMP180を用いました。

今回は、気温のみの読み取りになりますが、気圧/高度にも挑戦したいと思っています。

 

ちなみに、I2C読み取りの学習のために、BMP180用にクラスを作成していない

初心者が書きそうなプログラムコードになっているので、ご注意ください。

 

f:id:goma483549:20210917213401j:plain

 

接続

 Picoの3.3V --- センサーのVCC

 PicoのGND --- センサーのGND

 PicoのGPIO0 --- SDA

 PicoのGPIO1 --- SCL

 

コード

from machine import Pin, I2C
import time
import ustruct

# I2Cに使うピンの設定
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=100000)

# デバイスのアドレススキャン
address = i2c.scan()[0]
print("address is:" + hex(address))
     
#I2Cアドレス119のデバイスレジスタ0xAA~0xBFまで2Byteごと読み取り
#BMP180のセンサー補正値読み取り
AC1 = i2c.readfrom_mem(address,0xAA,2)
AC2 = i2c.readfrom_mem(address,0xAC,2)
AC3 = i2c.readfrom_mem(address,0xAE,2)
AC4 = i2c.readfrom_mem(address,0xB0,2)
AC5 = i2c.readfrom_mem(address,0xB2,2)
AC6 = i2c.readfrom_mem(address,0xB4,2)
B1 = i2c.readfrom_mem(address,0xB6,2)
B2 = i2c.readfrom_mem(address,0xB8,2)
MB = i2c.readfrom_mem(address,0xBA,2)
MC = i2c.readfrom_mem(address,0xBC,2)
MD = i2c.readfrom_mem(address,0xBE,2)

 

#補正値ビット列を10進数へ変換
#unpackするとタプルで返すため、[0]で先頭データを読み取る
fmt = '>h' #short big-endian
fmt2 = '>H' #unsigned short big-endian
AC1_x = ustruct.unpack(fmt, AC1)[0]
AC2_x = ustruct.unpack(fmt, AC2)[0]
AC3_x = ustruct.unpack(fmt, AC3)[0]
AC4_x = ustruct.unpack(fmt2, AC4)[0]
AC5_x = ustruct.unpack(fmt2, AC5)[0]
AC6_x = ustruct.unpack(fmt2, AC6)[0]
B1_x = ustruct.unpack(fmt, B1)[0]
B2_x = ustruct.unpack(fmt, B2)[0]
MB_x = ustruct.unpack(fmt, MB)[0]
MC_x = ustruct.unpack(fmt, MC)[0]
MD_x = ustruct.unpack(fmt, MD)[0]

 

#0xF4に0x2Eを書くと気温測定を開始

i2c.writeto_mem(address,0xF4, bytearray([0x2E]))
time.sleep(0.005)

 

#補正前の気温データの読み取り

UT = i2c.readfrom_mem(address,0xF6,2)
UT_raw = ustruct.unpack(fmt2, UT)[0]

 

#気温の計算
X1 = (UT_raw - AC6_x)*AC5_x/2**15
X2 = MC_x*2**11/(X1 + MD_x)
B5 = X1 + X2
Temp = (B5 + 8)/2**4/10

print("Temperature:",'{:.2f}'.format(Temp),"C")

 

するとこんな感じで出力されます。

address is:0x77
AC1: 8233
AC2: -1091
AC3: -14152
AC4: 33442
AC5: 25693
AC6: 16550
B1: 6515
B2: 39
MB: -32768
MC: -11786
MD: 2398

Temperature: 24.36 C

 

つまづきやすいのは、タプルの扱いでしょうか。

address = i2c.scan() でもアドレスは取得できるのですが、複数データの入ったタプルというものになっており、

address = i2c.scan()[0] という風に最初のデータを参照しないとエラーになってしまいました。

 

ustruct.unpack の部分も同じく、アンパックするとタプルになるようで、タプルの最初のデータをセンサーの補正値として取り出しています。

ここでのアンパックはレジスタの0,1のデータを10進数に戻す作業です。

 

fmt = '>h' #short big-endian 

に関しては、センサーのメモリから取り出したビットデータをどの順に並べて、

どの型(short、int、longなど)に変換しますかという部分です。

 

上のコードは基本的には以下を参考にしています。

micropython-bmp180/bmp180.py at master · micropython-IMU/micropython-bmp180 · GitHub

こちらでは、読み取りからunpackを1行で書いています。手慣れたものですね(^^ ;

self._AC1 = unp('>h', self._bmp_i2c.readfrom_mem(_bmp_addr, 0xAA, 2))[0]

 

structに関しては以下も参考になります

docs.python.org

 

なかなか経験がないと、I2Cの読み取りも大変ですね。

少しづつ経験値を増やしていきたいです。