段々夏らしい気温になってきた.そこで,今回は RaspberryPi を使って持て余していた湿度センサを例にI2Cデバイスを使う方法を書く.
必要なもの
- RaspberryPi
- 湿度センサ(HTU21D)
- センサとRasPiを接続する適当な線
手元にあったこの赤いセンサは既に販売終了しているようだが,こっちの青いセンサでも使い方は同じ.
RaspberryPiを設定する
raspi-configでI2Cを有効にする
$ sudo raspi-config
設定箇所は Interfacing Options > I2C .
必要なパッケージをインストールする
$ sudo apt install i2c-tools bc
I2Cを使う方法はC言語やPythonなど色々あるけれど,今回はあくまで簡単に使うだけなのでi2cget/i2csetコマンドを使ってモジュールを操作していく.加えてモジュールから取得した値を計算するためにbcコマンドもインストールしておく.
ここまでの状態でカーネルモジュールも読み込まれ,1番のI2Cバスが生成されている.
$ lsmod | grep i2c i2c_bcm2835 16384 0 i2c_dev 20480 0 $ ls /dev/i2c* /dev/i2c-1
I2Cモジュールの使い方
RaspberryPiとモジュールを接続
RaspberryPiとモジュールを図のような形で接続する.どのピンが何なのかわからないときは公式の情報を参照する.公式情報に記載のある通り,Pinout Leafを使うとわかりやすい.
モジュールを操作する
仕様書を読んでI2Cのスレーブアドレスとコマンドの仕様を確認する.
アドレス:0x40
I2Cのアドレスは先頭から7bit部分で,残りの1bitはコマンドを送る際のread/writeを表すのに使う.これはどのモジュールでも共通.
I2Cバスの状態を確認するとモジュールが認識されていることがわかる.
$ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
仕様書から抜粋したコマンドは以下の通りで,湿度と気温の測定が出来る.各コマンドRead/Writeどちらで使うかは仕様書を読んで確認する.慣れてくると感覚で判別出来るようになるかもしれない.
Command | Code | Comment |
---|---|---|
Trigger Temperature Measurement | 0xE3 | Hold master |
Trigger Humidity Measurement | 0xE5 | Hold master |
Trigger Temperature Measurement | 0xF3 | No Hold master |
Trigger Humidity Measurement | 0xF5 | No Hold master |
Write user register | 0xE6 | |
Read user register | 0xE7 | |
Soft Reset | 0xFE |
例えば設定を読み取る(0xE7)場合,シーケンス図は次のようになっている.2列目の部分までが設定を読み取っている部分で,0xE7をwriteで送信した後にreadで結果を待っている.
これはi2cget
コマンドを使って次のようになる.今回はデフォルトのままで問題ないので,どのビットが何を表しているのかは説明しない.詳細は仕様書の「User register」の項目を参照のこと.ついでに設定を変更する場合はi2cset
コマンドを使って書き込む.
$ i2cget -y 1 0x40 0xE7 0x02 $ i2cset -y 1 0x40 0xE6 0x02 i
i2cget/i2csetコマンドの挙動についてはこのページがよく検証されているので参考にするといい.
ここまででコマンドの使い方がわかってきたと思うので,いよいよ気温を測定してみる.気温の計算には応答の先頭16bitが必要なので,コマンド末尾にオプションw
をつける.
$ i2cget -y 1 0x40 0xE3 w 0x3870
ここでRaspberryPiはリトルエンディアンなので,i2cget
コマンドの結果は 0x7038 として処理する必要がある.
$ lscpu | grep 'Byte Order'
Byte Order: Little Endian
また,末尾2bitは測定したデータが気温か湿度のどちらなのか判別する部分であり,仕様書にある通り計算前に0にしておく必要がある.
The two status bits, the last bits of LSB, must be set to ‘0’before calculating physical values.
ここまでの情報を整理して,仕様書の変換式に当てはめて計算すると次のようになる.bashだけでは複雑な計算は難しいので,計算出来るのは気温と湿度くらい.C言語やPythonなどなど計算しやすい言語を使えば他の変換式も使えるが,今回の目的は簡単にI2Cモジュールを使うことなので,気温と湿度が計算できれば良しとする.
$ RET=$(i2cget -y 1 $ADDRESS $CMD_mTemp_HM w) $ RAW=$(( ($RET & 0xfc00)>>8 | ($RET & 0x00ff)<<8 )) $ TEMP=$(echo "scale=2; -46.85+175.72*$RAW/65536" | bc ) # 65536 = 2^16 $ echo $TEMP 30.17
簡単に使えるように簡単なスクリプトを書いた.需要があれば参考にどうぞ.
$ ./htu21d.sh help # HELP Usage: htu21d.sh [OPTION] t measure temperature h measure relative humidity help show this message
おわりに
HTU21Dを例にRaspberryPiで簡単にI2Cデバイスを使う方法を書いた.bashだけではあまり複雑な計算は出来ないので,変換式が複雑なものは別の言語も使う必要がある.
$ echo -e "temp=$(./htu21d.sh t)\nhumi=$(./htu21d.sh h)" temp=33.66 humi=57.94
そろそろ暑い...
コメント