5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (42) ディジタル温度センサ7 I2C MLX90614ESF-BAA
■離れたところからピンポイントで温度を測る
MelexisのMLX90614は、遠距離になるとレンズが必要ですが、素子のままで、5cm程度の距離の温度が非接触で測れます。Digi-keyで購入したのは環境温度と赤外線の温度計が一つずつのモデルです。モデルによっては、赤外線の温度測定部が二組入っていますが、同時に読み出せるのは、二つの素子のデータです。
●MLX90614ESF-BAAのスペック
- 電源電圧 2.6~3.6V(5Vのモデルもある)
- 測定温度範囲 -40~85℃
- インターフェース I2C、PWM
- デフォルトのスレーブ・アドレス(0x5a)。レジスタを書き換えて変更可
- 分解能 0.02℃
- 確度 ±0.5℃
●接続
このデバイスは、一般的なI2Cと2本だけで接続するPWM方式があります。ここでは、電源を含めた4本で接続するI2C方法を利用します。
●レジスタ
EEPROMとRAMがあり、計測データが入っているRAMは読み出しだけができます。EEPROMには設定値を変更して書き込めます。
◆EEPROM
- PWMCTRL(0x22)詳細はデータシートを参照
- Config Register1(0x25)詳細はデータシートを参照
- SMBBus address(0x2e)下位4ビットのみ変更可
◆RAM
いずれのセンサも0.02℃の分解能で、絶対温度で読み出せます。下位バイト、上位バイトの順で入っています。摂氏℃に直すには、0.02を掛けて273.15を引きます。
- 周辺温度Ta (0x06)
- 赤外線センサTobj1 (0x07)
- 赤外線センサTobj2 (0x08)
●PEC(チェック・バイト)
読み書き時に、PECという1バイトのデータがあります。CRC8 ATMというフォーマットです。読み出しのときは無視できますが、書き込み時には必須です。読み書きしている値が通信途中でノイズなどで化けていないかをチェックできます。ここでは、Pythonで16進で3桁もしくは4桁で動作が検証できた関数crc8atm()を使っています。筆算による方法をそのまま実装したので、文字列処理がトリッキです。
●プログラム
#!/usr/bin/env python
import smbus
import time
i2c = smbus.SMBus(1)
addr=0x5a
def crc8atm(data) : #data=0x654321
data =data <<8
length = len(bin(data)[2:])
for i in range(length):
if int(bin(data)[2:3],2) == 1 : #MSB =1
nokori = bin(data)[11:]
sentou = (int(bin(data)[2:11],2)) ^ (int('100000111',2))
data = int((str(bin(sentou)[2:11])+str(nokori)),2)
data=int(bin(data),2)
if len(str(bin(data)[2:]))<9:
return(hex(data))
#main
#i2c.write_i2c_block_data(addr,0x25,[0xb4,0x9f,0x8c]) #default
#i2c.write_i2c_block_data(addr,0x25,[0xb4,0xcf,0x3b]) #gain=25
print bin(i2c.read_word_data(addr,0x22)) ,"PWMCTRL"
print bin(i2c.read_word_data(addr,0x25)) ,"Config Register1"
print hex(i2c.read_byte_data(addr,0x2e)) ,"slave address"
time.sleep(0.5)
while 1:
Atemp = i2c.read_i2c_block_data(addr,0x6,3)
Otemp1 = i2c.read_i2c_block_data(addr,0x7,3)
# Otemp2 = i2c.read_i2c_block_data(addr,0x8,3)
AmbientTemp = ((Atemp[1]*256 + Atemp[0]) *0.02 -273.15)
ObjectTemp1 = ((Otemp1[1]*256 + Otemp1[0]) *0.02 -273.15)
# ObjectTemp2 = ((Otemp2[1]*256 + Otemp2[0]) *0.02 -273.15)
print round(AmbientTemp,2),round(ObjectTemp1,2)
print "TempHEXAdata",hex(Atemp[0]),hex(Atemp[1]),"readedCRC",hex(Atemp[2]),
data = int((hex(int("b406b5"+str(hex(Atemp[0])[2:])+str(hex(Atemp[1])[2:]),16)) )[:-1],16)
print crc8atm(data),"<-calculated"
time.sleep(1)
●パラメータの変更にはPEC(CRC)が必要
チェック用CRC8はマキシムの1-wireデバイスやA-D変換ICなどでも採用されているようです。同じ8ビットでも計算方法は異なります。設定を変更するには、EEPROMのレジスタに変更内容を書き込みます。矛盾したデータはエラーになります。PECの値が正しくないときにもエラーになります。EEPROMではPWMCTRL(0x22)、Config Registor1(0x25)とSlave Address(0x2e)が変更できます。
書き込みのとき、CRCはデータだけでなく、
スレーブ・アドレス、レジスタ、データ下位、データ上位 |
の四つから求めます。読み出しのときは、スレーブ・アドレスはR/Wビットを含むので値が異なり、
0xb4(ライト)、 アドレス、 0xb5(リード)、 データ下位、データ上位 |
と五つのデータから計算します。
プログラムでは、読み出したデータのPECと計算したPECを表示していいます。この値が異なると、そのデータは捨てなければなりません。
実行結果です。
※執筆時点;2017-11-29版をダウンロードし、sudo apt-get update と sudo apt-get upgrade -y および sudo rpi-update で更新し、カーネルはuname -a で確認。4.9.70でした。
※プログラムを仮にmlx90614.pyという名前で/home/piに保存すると、sudo chmod 755 mlx90614.py で実行権を付け、ターミナルから、python mlx90614.pyで実行します。I2CやSPIのグループにpiユーザが属しているので、sudoは不要です。
プログラム・リストは、表示の関係でTabキーが無視されるので、スペースに代えてあります。また、リスト中を2回クリックすると全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。ラズパイに持っていくと、スペースやリターン・コードなどが化けていることがあるので、一度消して、ラズパイのテキスト・エディタで修正してください。
※I2Cの有効化は、こちらの説明を参照ください。SPIなどにもEnableにチェックを入れています。