CircuitPython 10行プログラミング (4) I2C

 Tinket M0マイコン・ボードとCircuitPythonを使って、I2Cバスにつながるセンサを利用します。

 マイコンの周辺モジュールを使うI2Cがライブラリbusio、そうでないときはライブラリbitbangioを使うとされています。
 busioには次の関数があります。

  • I2C - 2線式シリアル
  • OneWire - マキシム1-Wireシリアル
  • SPI - 3〜4線式シリアル
  • UART - 双方向シリアル

 bitbangioには次の関数があります。

  • I2C
  • OneWire
  • SPI

 Tinket M0マイコン・ボードで使われているSAMD21のUARTのピン接続は固定されていません。使えるピンの組み合わせは、こちらのページに掲載されています。

 Pythonではpyserialが使われますが、CircuitPythonではbusioのUARTを使うようです。

I2Cをつなぐ

 I2CデバイスのSi7021(アマゾンで購入した温湿度センサ)を接続します。センサ・モジュールのVin端子にはレギュレータが入っているので、Vbusの5Vへつないでいます。SDA/SCLの信号は3.3Vです。
 次の図の白地の文字は、基板裏に書かれたシルク印刷をTop Viewで見ています。

 接続です。

Tinket M0
裏面シルク
Si7021のシルク
SDA SDA
SCL SCL
USB Vin
GND GND

 bitbangioはエラーが出て使えませんでした。ライブラリbusioを使ったI2Cscanのプログラムは、こちらのページを参照しました。64を探してきました。

 print(type(i2c.scan()))で調べると、list形式のデータです。16進表示に直します。

print(hex(i2c.scan().pop()))

 0x40でした。Si7021のデータシートによると、0x40で固定で、外部の端子で変更はできないようです。
 I2Cバスを使うとき、バスをロックしないとエラーが出ます。ロックをするのは、ほかのマスタ?が同じデバイスをアクセスしないように排他的に使うためのようです。

書き込み i2c.writeto(スレーブ・アドレス, 読み出すポインタ・アドレス, stop=False)
読み出し i2c.readfrom_into(スレーブ・アドレス, バッファ)

 

 読み出した値はバッファに1バイトずつlistで入っています。最初のバイトがデータシートでは上位バイト、2バイト目が下位バイトなので、

  Temp0 = result[0] << 8 | result[1]

 

で16ビット・データに変換します。データシートの温度の変換式で摂氏を得ます。

  Temp = -46.85 + 175.72 * Temp0 * 0.00001525878

 途中のprint文を整理しました。

from board import *
from busio import I2C

i2c = I2C(SCL, SDA)

while not i2c.try_lock():
pass
i2c.writeto(0x40, bytes([0xe3]), stop=False)
result = bytearray(2)
i2c.readfrom_into(0x40, result)
Temp0 = result[0] << 8 | result[1]
Temp = -46.85 + 175.72 * Temp0 * 0.00001525878
print(round(Temp,1), "C")

 温度のポインタを書き込んだタイミングです。

 読み出しを要求したタイミングです。

 2バイトが読み出されました。

 湿度も読み出します。10行をはるかに超えてしまいました。連続して温度を読み出すポインタのアドレスは0xe3、同じく湿度は0xe5です。

from board import *
from busio import I2C
from time import sleep

i2c = I2C(SCL, SDA)

while not i2c.try_lock():
pass
while 1:
i2c.writeto(0x40, bytes([0xe3]), stop=False)
result = bytearray(2)
i2c.readfrom_into(0x40, result)
Temp0 = result[0] << 8 | result[1]
Temp = -46.85 + 175.72 * Temp0 * 0.00001525878
print(round(Temp,1), "C")

i2c.writeto(0x40, bytes([0xe5]), stop=False)
i2c.readfrom_into(0x40, result)
Hum0 = result[0] << 8 | result[1]
Hum = -6 + 125.0 * Hum0 * 0.00001525878
print(round(Hum,0), "%")
sleep(3.14)

Adafruitのライブラリを利用

 最新版のライブラリをダウンロードします。adafruit-circuitpython-bundle-3.x-mpy-20190202.zipを解凍して、adafruit_si7021.mpyとadafruit_bus_deviceフォルダを、CIRCUIYPYドライブの中にlibの名前のフォルダを作って入れます。
 今度は約10行で収まりました。

import time
import board
import busio
import adafruit_si7021

i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_si7021.SI7021(i2c)

while True:
print("\nTemperature: %0.1f C" % sensor.temperature)
print("Humidity: %0.1f %%" % sensor.relative_humidity)
time.sleep(2)

 実行中の様子です。