5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (20) ディジタル温度センサ5 SPI ADT7310

分解能が0.0078℃と高い温度センサ

 アナログデバイセズのADT7310はSPIインターフェースをもつディジタル出力の温度センサです。同じスペックでI2CインターフェースをもつADT7410があります。

 いずれも、秋月電子通商からブレッドボードで利用できる小型の基板に実装したモジュールが入手できます。SPIのデータ転送速度は数MHzと高速にできますが、配線長は短いほうがよいでしょう。ラズパイの近くの温度を測る用途に向いています。

ADT7310のスペック

  • 電源電圧;2.7~5.5V
  • 消費電流;210uA
  • 温度の確度;±0.4℃(-40~105℃、3.0V時)
  • 測定温度;-55~150℃
  • 温度の分解能;0.0078℃
  • 温度変換時間;240ms
  • SPIデータ転送速度;5MHz

ADT7310モジュールの構成

 モジュールは、設定温度を超えると有効になるCT信号とINT信号は外部に出ていませんが、電源、GND、SPIの信号が端子に出ています。電源とGNDには0.1uFのコンデンサが入っています。温度を測るだけという用途に適しています。

●接続

 温度の表示に使うキャラクタLCDのAQM0802は、I2Cのインターフェースを利用します。6ピンのソケットを、GPIOの1番ピンから11番ピンに挿します。

ADT7310モジュール ラズパイのGPIO
Vdd 3.3V 17番ピン
SCLK(SCL) CLK 23番ピン
Dout(SDO) MISO 21番ピン
Din(SDI) MOSI 19番ピン
/CS CE0 24番ピン
GND GND 25番ピン

連続読み出しのタイミング

 ADT7310には、消費電力を抑えるワンショットと連続変換の二つのモードがあります。ここでは連続変換(コンティニアス・リード)を選びます。連続変換のコマンド・バイトは次のように0x54です。レジスタ・アドレスは0x02です。

0 R/W レジスタ・アドレス コンティニアス・リード 0 0
0 1 0 1 0 1 0 0
                                                   0x54

 A-D変換は240msかかります。したがって、コマンドを送って240ms待ってから温度の入ったレジスタから2バイト読み出します。SPIでは、コマンドを送るときはクロックが出ます。読み出しのときもクロックが必要なので、ダミーの2バイト分のデータを送ります。

プログラム

 2017年9月18日現在のOSのバージョンです。

uname -a
4.9.50
python -V
2.7.13
pip list
spidev(3.0)

 最初に温度データを13ビットで読み出しをします。13ビットは電源が入ったときのデフォルトなので、読み出しだけを行います。

 動作が不安定な時にリセットするには、Dinに32クロック以上の'1'を加えるようにデータシートに書かれています。しかし、そのリセットを行っても最初に4,5回、異常なデータを受け取ります。何回かを読み飛ばすようにしました。このプログラムでは最後のspi.close()は機能していません。

 spi.xfer2([0x00,0x00])の0x00はダミーデータです。

#!/usr/bin/env python
import spidev
import time

spi = spidev.SpiDev()
spi.open(0,0) #port 0,cs 0
spi.max_speed_hz = 1000000

def sign13(x):
return ( -(x & 0b1000000000000) |
(x & 0b0111111111111) )

#main
spi.xfer2([0xff,0xff,0xff,0xff])
time.sleep(0.01)
spi.xfer2([0x54])
time.sleep(0.24)
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])

while 1:
spi.xfer2([0x54])
time.sleep(0.24)
adc = spi.xfer2([0x00,0x00])
data = (((adc[0]) << 8) | adc[1] ) >> 3
# print(str(hex(adc[0]))+" "+str(hex(adc[1]))+" "+str(data))
data_s = sign13(int(hex(data),16))
print (str(data_s*0.065) + "C")
time.sleep(1)
spi.close()

 温度を16ビットで読み出すときは、コンフィギュレーション・レジスタでビット長の変更をしてからデータを読み出します。

 データシートから、コンフィギュレーション・レジスタの書き込むレジスタ・アドレスは0x01です。コマンド・バイトは0x0cです。書き込むデータは最上位ビットが1なので、0x80です。

#!/usr/bin/env python
import spidev
import time

spi = spidev.SpiDev()
spi.open(0,0) #port 0,cs 0
spi.max_speed_hz = 1000000

def sign16(x):
return ( -(x & 0b1000000000000000) |
(x & 0b0111111111111111) )

#main
spi.xfer2([0xff,0xff,0xff,0xff])
time.sleep(0.01)
spi.xfer2([0x0c,0x80]) #ConfigR 0x01, b7=1 <16bit
time.sleep(0.24)
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])

while 1:
spi.xfer2([0x54])
time.sleep(0.24)
adc = spi.xfer2([0x00,0x00])
data = ((adc[0]) << 8) | adc[1]
# print(str(hex(adc[0]))+" "+str(hex(adc[1]))+" "+str(data))
data_s = sign16(int(hex(data),16))
print (str(data_s*0.0078125) + "C")
time.sleep(1)
spi.close()

 読み出した温度をLCD AQM0802に表示します。

 LCDcommand()とwriteLCD()はLCD用の関数です。LCDcommand()は、LCDへ直接命令を送信します。writeLCD()は、引数に入っている文字列を表示します。initLCD()はLCDの初期化コードを送信します。

 プログラム・リストは、表示の関係でTabキーが無視されます。スペース8個に代えてあります。また、リスト中を2回クリックすると、全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。ラズパイに持っていくと、リターン・コードなどが化けていることがあるので、一度消して、ラズパイのテキスト・エディタで改行してください。

 プログラムを仮にadt7310.pyとすると、sudo chmod 755 adt7310.py で実行権を付け、ターミナルから、python adt7310.pyで実行します。i2cやSPIのグループにpiユーザが属しているので、sudoは不要です。

#!/usr/bin/env python
import spidev
import smbus
import time

i2c = smbus.SMBus(1)
addr02=0x3e #lcd
spi = spidev.SpiDev()
spi.open(0,0) #port 0,cs 0
spi.max_speed_hz = 1000000

_command=0x00;_data=0x40;_clear=0x01;_home=0x02;display_On=0x0f;LCD_2ndline=0x40+0x80

def sign16(x):
return ( -(x & 0b1000000000000000) |
(x & 0b0111111111111111) )

#LCD AQM0802
def LCDcommand( code ):
i2c.write_byte_data(addr02, _command, code)
time.sleep(0.2)

def writeLCD( message ):
mojilist=[]
for moji in message:
mojilist.append(ord(moji))
i2c.write_i2c_block_data(addr02, _data, mojilist)
time.sleep(0.2)

def initLCD():
LCDcommand(0x38);LCDcommand(0x39);LCDcommand(0x14);LCDcommand(0x73);LCDcommand(0x56);LCDcommand(0x6c);LCDcommand(0x38);LCDcommand(_clear);LCDcommand(display_On)
 
#main
initLCD()
writeLCD("Start")
spi.xfer2([0xff,0xff,0xff,0xff])
time.sleep(1)

spi.xfer2([0x0c,0x80]) #ConfigR 0x01, b7=1 <-16bit

spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])
spi.xfer2([0x00,0x00])

while 1:
spi.xfer2([0x54])
time.sleep(0.24)
adc = spi.xfer2([0x00,0x00])
data = ((adc[0]) << 8) | adc[1]
# print(str(hex(adc[0]))+" "+str(hex(adc[1]))+" "+str(data))
data_s = sign16(int(hex(data),16))
temp = data_s*0.0078125
print (str(temp) + "C")
LCDcommand(_clear)
writeLCD("T" + str(temp) )
time.sleep(1)
spi.close()

 実行中の様子です。読み出したデータをそのまま表示していますが、温度の確度は±0.4℃です。