自由に工作中

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

気温センサー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の読み取りも大変ですね。

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

 

 

 

Micro Python の書き方(I2Cスキャン)

Raspberry Pi Pico用です。

 

接続したセンサーやLCDディスプレイのI2Cアドレスのスキャン方法になります。

GPIO0とGPIO1にI2Cを接続して、以下のコードを走らせます。

 

from machine import Pin, I2C

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

# デバイスのアドレススキャン
address = i2c.scan()[0]
print("address is :" + hex(address))

 

すると、接続したデバイスのI2Cアドレスが16進数で返ってきます。

address is :0x77

 

追加で以下を書くと、接続したデバイスのメモリのレジスタ0xAA番地から始まる

2バイト分のデータを読みます。

AA1 = i2c.readfrom_mem(address,0xAA,2)

 

まだ、Micro Python初心者なので間違え等ありましたら、ご指摘ください。

Micro Python の書き方(ADC アナログ/デジタル変換)

忘れてしまうのでメモ。Rasberry Pi Pico用。

 

from machine import ADC, Pin

 

# ADC0を使う設定

PIN_ADC = 0

 

# ADC0~ADC2のあるGPIO26~28を使う記述でもOK

PIN_ADC = 26

 

# ADCの電圧は3.3V

VREF =3.3

 

# ADC オブジェクトを作成

adc = machine.ADC( PIN_ADC ) 

 

# ADCの値を読み取り

value = adc.read_u16()       

 

# デジタル値を電圧に変換

volt = value /65535 * VREF

 

# 電圧を表示する

print("電圧は:",volt ,"V" )

 

Micro Python の書き方(PWM)

忘れてしまうのでメモ。Rasberry Pi Pico用。

 

from machine import PWM

 

# LEDを接続したGPIOの番号

LED_PIN = 18

 

# PWMの周波数

FREQ = 100

 

# duty比を0~100で設定

DUTY = 25

 

# 指定したピンをPWM出力するようにする

led = PWM( PIN (LED_PIN) )

 

# PWMの周波数を設定する

led.freq( FREQ )

 

# デューティー比を0~65535の範囲で設定する

pwm_out = int( DUTY / 100 * 65535 )

 

# PWM出力する

led.duty_u16( pwm_out )

Micro Python の書き方 (PIN)

忘れてしまうのでメモ。Rasberry Pi Pico用。

 

from machine import Pin

 

# GPIO23番を出力モードにして、出力High(3.3V)にする

LED_PIN = 23

led = Pin(LED_PIN, Pin.OUT)

led.value(1)

 

# GPIO18番を入力モードにする

LED_PIN = 18

led = Pin(LED_PIN, Pin.IN)

 

# プルアップ抵抗を有効にする

LED_PIN = 18

led = Pin(LED_PIN, Pin.IN, Pin.PULL_DOWN)

 

# Pin.PULL_DOWN:プルダウンを有効

# Pin.PULL_UP:プルアップを有効

# Pin.NONE :無効化

 

# ピンの値を読み込んで表示
print(led.value())

Raspberry Pi Pico でCircuit Pythonを使う準備

Raspberry Pi Pico でCircuit Pythonを使ってみたので、準備方法を備忘録として残しています。

Picoのプログラミング言語C/C++、MicroPythonですが

Adafruit Industriesが開発を支援するCircuitPythonによる記述も可能です。

 

PicoがUSBメモリとして認識され、パソコンのエディッタでPico内のコードを

編集することができるので、特別な開発環境が要らないメリットがあるようです。

 

1. 以下のサイトからPico用のCircuitPythonのUF2ファイルをダウンロードします。

 2021/9/11現在は、CircuitPython 6.3.0が安定している最新版のようです。

 Pico Download (circuitpython.org)

 

2. Pico本体のBOOTSELボタンを押しながら、PCに接続します。

 

3. RPI-RP2ドライブが見えるので、先ほどダウンロードしたUF2ファイルを

 ドラッグ&ドロップして、RPI-RP2ドライブへコピーします。

 すると、Picoが自動で再起動されます。

f:id:goma483549:20210911094423j:plain

 

4. 自動起動したあと、Pico内にCIRCUITPYドライブが見えるので、

 その直下にある code.pyにプログラムを記述します。

 またはcode.pyを消してmain.pyでも動作しました。

 追加でimportするLibraryなどは、CIRCUITPYドライブ直下にあるlibフォルダ内

 に置きます。


f:id:goma483549:20210911095522j:plain