Raspberry Pi(Linux、Python)で温度測定(1) MCP9808

Adaflut MCP9808(購入はスイッチサイエンス)

 MCP9808はマイクロチップの温度センサです。I2Cインターフェースでデータを読み取ります。
 電源電圧は2.7~5.5Vなので、ラズパイにそのままつなげられます。測定温度範囲は-20~100℃です。データは最小0.0625℃で読み出せますが、確度は ±0.25℃です。

MCP9808ボードのピン配置

 ラズパイとの接続は下記の4本です。


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

スレーブのアドレス

 アドレスを変更するために、A2、A1、A0の3ピンがボード上にあります。

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

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

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

温度レジスタは0x05

 最上位にある符号は、負のとき1、0℃以上では0です。0、1、13、14、15のビットは読み出すと0です。

(※)最小の1と0ビットにはデータが入っていますが利用していません。

ラズパイとの接続

  MCP9808とLCDモジュールAQM1602AをI2Cバスにつなぎます。AQM1602Aこの記事のように、そのままつないでは認識されないので、バス・リピータPCA9515ADを挟みます。



プログラミング

 i2cdetectで接続を確認します。0x18にいます。


(1) 温度レジスタをワード(16ビット)単位で読み出すと、2バイトが逆転しているので、入れ替える

t=i2c.read_word_data(addr03,0x05) #temp reg
tswap= swap16(int(hex(t),16))

<バイト・スワップ>

def swap16(x):
        return (((x << 8) & 0xFF00) |
                ((x >> 8) & 0x00FF))

(2) 正の温度であれば、符号は0なのでそのまま扱えばよいが、ビット12が’1’つまり10進で4096以上ならば、0x0fffでマスクをして符号を取り去ってから換算。下2桁にデータがないので2ビット右シフトをするために16で割る

temp = (int(hex(tswap),16) & 0x0fff) / 16.0

(3) 四捨五入する

temp = round(temp,1)

(4) 文字列tempをLCDに表示する

mojilist=[]
for moji in str(temp):
        mojilist.append(ord(moji))

i2c.write_i2c_block_data(addr02, _data, mojilist)
time.sleep(0.2)

(5) 温度に続けて℃を表示

i2c.write_byte_data(addr02, _data, 0xdf)
time.sleep(0.2)
i2c.write_byte_data(addr02, _data, 0x43)

プログラム全体です。

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

i2c = smbus.SMBus(1) # 1 is bus number
addr02=0x3e #lcd
addr03=0x18 #MCP9808
_command=0x00
_data=0x40
_clear=0x01
_home=0x02
display_On=0x0f
LCD_2ndline=0x40+0x80

# LCD AQM1602
i2c.write_byte_data(addr02, _command, 0x38)
time.sleep(0.2)
i2c.write_byte_data(addr02, _command, 0x39)
time.sleep(0.1)
i2c.write_byte_data(addr02, _command, 0x14)
time.sleep(0.1)
i2c.write_byte_data(addr02, _command, 0x73)
time.sleep(0.1)
i2c.write_byte_data(addr02, _command, 0x56)
time.sleep(0.2)
i2c.write_byte_data(addr02, _command, 0x6c)
time.sleep(0.2)
i2c.write_byte_data(addr02, _command, _home) # 0x38
time.sleep(0.1)
i2c.write_byte_data(addr02, _command, _clear)
time.sleep(0.1)
i2c.write_byte_data(addr02, _command, display_On)
time.sleep(0.1)

def swap16(x):
        return (((x << 8) & 0xFF00) |
                ((x >> 8) & 0x00FF))

#main
print "start"

t=i2c.read_word_data(addr03,0x05) #temp reg
tswap= swap16(int(hex(t),16))
temp = (int(hex(tswap),16) & 0x0fff) / 16.0
temp = round(temp,1)
print t,hex(t),hex(tswap),temp

mojilist=[]
        for moji in str(temp):
        mojilist.append(ord(moji))
# print moji,hex(ord(moji)),mojilist
i2c.write_i2c_block_data(addr02, _data, mojilist)
time.sleep(0.2)
i2c.write_byte_data(addr02, _data, 0xdf)
time.sleep(0.2)
i2c.write_byte_data(addr02, _data, 0x43)
print "end"

 実行したようすです。