5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (18) ディジタル温度センサ3 I2C MCP9808

確度±0.25℃が得られるI2C温度センサ

 MCP9808は、データは最小0.0625℃単位で読み出せ、確度は ±0.25℃と細かな温度変化をとらえるのに便利な温度センサです。インターフェースはI2Cです。測定した温度は同じくI2CインターフェースのLCD AQM0802に表示します。

 Adafruitのブレークアウト・ボードをスイッチサイエンスで入手しました。

MC9808の主なスペック

  • 電源電圧; 2.7~5.5 V
  • 消費電流;200 μA
  • インターフェース;I2C(データ転送速度0~400kHz)
  • 測定温度範囲;-40~125℃(確度±0.25°C(typ))、-20~100℃(確度±0.5°C(max))

●MCP9808ボードのピン配置

 SDAとSCLのプルアップ抵抗は、ラズパイ本体についているので取り去ります。ラズパイとの接続は下記の4本です。


ピン名称 備考
Vdd +3.3Vへ
Gnd グラウンド
SCL I2C。10kΩでプルアップ済み
SDA I2C。10kΩでプルアップ済み
Alert 温度の読み出しでは使わない
アドレス A0 下記のアドレス選択を参照
アドレス A1 下記のアドレス選択を参照
アドレス A2 下記のアドレス選択を参照

スレーブのアドレス

  A2、A1、A0端子に何もつながないとスレーブ・アドレスは0x18です。変更したいときは、Vddにつなぎます。

アドレス
A6 0 固定
A5 0 固定
A4 1 固定
A3 1 固定
A2  外部ピンで設定。解放で0
A1  外部ピンで設定。解放で0
A0  外部ピンで設定。解放で0

 変更例です。ここではデフォルトで使いました。

ピン名              
A2 Vdd Vdd Vdd - - - Vdd
A1 - Vdd Vdd Vdd Vdd - -
A0 - - Vdd - Vdd Vdd Vdd
アドレス 0x1c 0x1e 0x1f 0x1a 0x1b 0x19 0x1d

温度読み出しレジスタは0x05

 最上位にある符号signは、負のとき1、0℃以上では0です。2の補数形式の13ビット(分解能+0.0625°C)でデータが格納されています。13、14、15のビットはアラート情報なので、温度を読み出すときはマスクします。

接続

 AQM0802のソケットのピン配置がI2C バス1の信号位置に合わせています。しかし、GPIOに挿すと、MCP9808が接続できません。回路図ではAQM0802をGPIOに挿すように書きましたが、実際は、ラズパイのGPIOにあるI2C信号の3番ピンSDA5番ピンSCL、1番ピンの3.3V、6番ピンのGNDをブレッドボードに持ってきて配線しました。

 配線が終わってから、ラズパイの電源を入れます。

(※)I2Cの有効化は、1-Wireの説明を参照ください。1-Wireと同じく、I2CもEnableにチェックを入れています。

  ターミナルから、i2cdetect -y 1 で配線が正しいかを確認します。LCDの3eとMCP9808の18が見えているはずです。

プログラム

 MCP9808とI2C接続のキャラクタLCD表示器はsmbusライブラリを利用します。変換待ちをするsleep()用にtimeライブラリを使います。

 最初に、MCP9808からデータを読み出すところまでのプログラムを作ります。

 sign16()関数は2の補数のデータから、符号のついた数字に変換します。

#!/usr/bin/env python
import smbus
i2c = smbus.SMBus(1)
addr=0x18 #MCP9808

def sign16(x):
return ( -(x & 0b1000000000000000) |
(x & 0b0111111111111111) )
#main
data = i2c.read_i2c_block_data(addr, 0x05)
raw = ((data[0] & 0x1f) << 8) | (data[1])
#print (hex(data[0]));print(hex(data[1]));print(hex(raw))
raw_s = sign16(int(hex(raw),16))
temp = raw_s * 0.0625
print (str(temp) +"C")

 実行結果です。

 LCDに表示する部分を追加します。

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

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

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

#!/usr/bin/env python
import smbus
import time
i2c = smbus.SMBus(1)
addr=0x18 #MCP9808
addr02=0x3e #lcd
_command=0x00;_data=0x40;_clear=0x01;_home=0x02;display_On=0x0f;LCD_2ndline=0x40+0x80

#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)

def sign16(x):
return ( -(x & 0b1000000000000000) |
(x & 0b0111111111111111) )
#main
initLCD()
while 1:
data = i2c.read_i2c_block_data(addr, 0x05)
raw = ((data[0] & 0x1f) << 8) | (data[1])
# print (hex(data[0]));print(hex(data[1]));print(hex(raw))
raw_s = sign16(int(hex(raw),16))
temp = raw_s * 0.0625
print (str(temp) +"C")
LCDcommand(_clear)
writeLCD("T=" + str(temp) )
time.sleep(1)

 実行結果です。最上位ビットを1にしたテスト・データを表示しています。