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
- 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℃です。