概要
ラズパイでI2Cセンサモジュールとの通信をPythonでプログラミングする際に使うライブラリ2種類と,ハマってわかった注意点をログしておきます
環境
- Raspberry Pi 3B
- OS: Raspbian (Jessie)
- Python: 2.7.9
使ったI2Cモジュールは以下の通り
- ADT7410 (Analog Devices) 温度センサ
- AM2322 (Aosong) 温湿度センサ
ライブラリ比較
SMBus
webで調べるとこのライブラリを使っている例が多いですね.SMBusはSystem Management Busで,I2Cの一種とのことです.
関数の参考サイト: Using the I2C Interface – Raspberry Pi Projects
さらに関数詳細: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/i2c/smbus-protocol
インストール
sudo apt install python-smbus
使い方
ADT7410を例に温度を読み取ってみます1
# ADT7410の温度読み取り
import smbus
i2c = smbus.SMBus(1) # 注:ラズパイのI2Cポート
address = 0x48
block = i2c.read_i2c_block_data(address,0x00,2) # 0x48のI2Cスレーブのレジスタ0x00から2バイト読み取る
temp = (block[0] << 8 | block[1]) >> 3
if(temp >= 4096):
temp -= 8192
print("温度: "+temp/16.0)
pigpio
I2Cに限らず,Raspberry PiのGPIO制御するのに便利な環境.バックでプログラム(pigpio)を走らせて,そこにアクセスすることでGPIOやらI2Cを使えるようにしています
Python関数参考: pigpio library
インストールと準備
sudo apt install pigpio python-pigpio
sudo systemctl start pigpiod
再起動後も自動的にpigpiodを起動させるには,
sudo systemctl enable pigpiod
使い方
AM2322を例に温度と湿度を読み取ってみます
import pigpio
import time
pi = pigpio.pi()
addr = 0x5c
h = pi.i2c_open(1,addr) # ハンドル取得
try:
pi.i2c_write_quick(h, 0) # AM2322のスリープ解除
except:
pass
pi.i2c_write_i2c_block_data(h,0x03,[0x00,0x04])
time.sleep(0.003)
(count, buf) = pi.i2c_read_device(h,0x08)
hum = (buf[2]*256 + buf[3])/10.0
temp = ((buf[4]&0x7f)*256 + buf[5])/10.0 * ( -1 if buf[4]&0x80 > 0 else 1 ) # tempの最上位ビット(7)が負数ビット
print("温度: {:.1f}, 湿度: {:.1f}".format(temp,hum))
pi.i2c_close(h)
注意点(ハマりどころ)
AM2322の温湿度をログするためにcronで定期的に実行させていたのですが,当初i2c_close
を書いておらず,しばらくすると実行されなくなることがありました.
その時,単発で実行すると以下のエラーが出ます
pigpio.error: 'no handle available'
pigpioライブラリで取得しているi2c用のハンドル(上記のh
)は32個までしか割り当てられないとのことで,ちゃんとcloseしないと枯渇することが原因だったようです.
しばらく動いてしまうので分かりにくいハマりポイントでした.
参考: https://www.raspberrypi.org/forums/viewtopic.php?t=88545
I2Cの注意点
Raspberry Piに限りませんが,I2Cモジュールはものによって操作が結構異なるみたいなので,使うモジュールのデータシートをよく読まないとハマります(ハマりました)
ADT7410の場合
データシートP19: http://akizukidenshi.com/download/ds/analog/ADT7410a.pdf
Reading back from any register first requires a single-byte write operation to the address pointer register to set up the address of the register that is going to be read from. In the case of reading back from the 2-byte registers, the address pointer automatically increments from the MSB register address to the LSB register address.
読みたいレジスタのアドレスを1バイト書き込んだ後,2バイトの読み取り操作をします.SMBusでは複数バイトが読み取れるread_i2c_block_data
を使いました.
AM2322の場合
データシートP13 : http://akizukidenshi.com/download/ds/aosong/AM2321_e.pdf
ホストから "0x03" "開始アドレス" "読み取りレジスタ数" を書き込み,その後スレーブから "0x03" "レジスタ数" "実際のデータ" "CRC" が送られます.
アドレス0x00から順に湿度MSB・LSB,温度MSB・LSBの4バイトなので,"0x03, 0x00, 0x04" を書き込んだあと,8バイトの読み取りをする必要があります.
しかし,SMBusでは書き込みと読み取り別々に行う関数が用意されていなかったため,pigpioのi2c_read_device
を使うことになりました.
-
I2Cポートは
ls /dev/i2c*
で出てきた方の数字を使えばいいはず ↩