はじめに
この記事では次のようなことをしています。
- Raspberry Piを使います
- OSはRaspbianを使います
- 温度湿度センサーはAM2321を使います
- AM2321はI2Cで接続します
- センサーの読み出しにはRubyのコードを使用します
- 値の読み出しのみでWebに連携するなどは行なっていません
AM2321センサー
温度と湿度を同時に測定できるセンサーモジュールです。I2Cの他に1-wireに似た方式で通信できます。
ピンは1.27mmピッチなので汎用のブレッドボードに繋ぐ場合は2.54mmピッチに変換してあげる必要があります。
参考サイト
配線
配線は次の図の通りです。
なお、通常I2Cの接続にはプルアップ抵抗が必要ですが、Raspberry Piは標準で入っているため不要です。
参考サイト
- [Raspberry PiでIO制御] (http://www.pwv.co.jp/~take/TakeWiki/index.php?raspberrypi%2FRaspberry%20Pi%E3%81%A7IO%E5%88%B6%E5%BE%A1#f82dc47c)
- i2c pull up resistors
Raspbianの設定
Raspbianの標準ではi2cが有効になっていないので有効にします。
i2c-toolsのインストール
次のコマンドでインストールされます
$ sudo apt-get install i2c-tools
使用するユーザー(UserId=pi)をi2cのグループに追加する
piユーザーでi2cにアクセスできるようにするため、i2cグループに追加します。
$ sudo adduser pi i2c
/etc/modules
次のコマンドで/etc/modulesを編集します。
$ sudo vi /etc/modules
次の2行を追加します。
i2c-bcm2708
i2c-dev
/etc/modprobe.d/raspi-blacklist.conf
次のコマンドで/etc/modprobe.d/raspi-blacklist.confを編集します。
$ sudo vi /etc/modprobe.d/raspi-blacklist.conf
次の1行をコメントアウトします。
#blacklist i2c-bcm2708
参考サイト
疎通確認
前述でインストールしたi2c-toolsのi2cdetectコマンドを使って疎通確認します。
「i2cdetect -y 1」コマンドで確認できます。
$ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
AM2321のアドレスである0x5cが検出されました。
ちなみにAM2321はセンサーが自己発熱による湿度誤差を低減するため、休止状態になるという機構があるそうです。
このため、休止状態のときにi2cdetectコマンドを実行すると検出されないことがります。
この場合、複数回連続で実行すると検出されるようになります。
この休止状態の機構のためか、私の環境ではi2c-toolsのコマンドは全般的に正しく動きませんでした。ちょっと辛いです。
Rubyのコード
Rubyからi2cを操作するため、i2cのGemが必要になるのでインストールします。
sudo gem install i2c
次のコードはi2c経由でAM2321経由でRubyで値を取得するコードです。
- Wake up sensorの箇所は休止状態のセンサーを起こす処理です
- Read sensor valuesの"\x03\x00\x04"は、AM2321固有のコマンドです 参考
- CRC16は自前で計算しています
#!/usr/bin/env ruby
require 'rubygems'
require 'i2c'
class AM2321
def initialize(path, address = 0x5c)
@device = I2C.create(path)
@address = address
end
def crc16(data)
crc = 0xFFFF
data.each do |b|
crc ^= b;
8.times do
if (crc & 0x01) != 0 then
crc = crc >> 1
crc ^= 0xA001
else
crc = crc >> 1
end
end
end
return crc
end
def read
# Wake up sensor
begin
@device.write(@address, "")
rescue
# ignore
end
# Read sensor values
begin
s = @device.read(@address, 8, "\x03\x00\x04")
rescue
return nil
end
func_code, ret_len, hum_h, hum_l, temp_h, temp_l, crc_l, crc_h = s.bytes.to_a
orig_crc = (crc_h << 8) | crc_l
hum = (hum_h << 8) | hum_l
temp = (temp_h << 8) | temp_l
# Calc CRC
crc = crc16(s[0,6].bytes)
return nil if crc != orig_crc
return hum/10.0, temp/10.0
end
end
sensor = AM2321.new('/dev/i2c-1')
100.times do
p sensor.read
sleep(0.5)
end
参考サイト
おわりに
AM2321をRaspberryPiで動作させたくて始めたのですが意外にやることが多くて結構嵌りました。
Rubyにしたのは勉強がてらというので特に意味はありません。
とりあえず値が読み出せたので、ここからCrondで定期的に値を読み取り、Webにアップロードしたり、Google Spread Sheetに保存したりするなどの応用に繋げられるようになりました。
繋げられるものを繋いでいって面白いものが作れればと思います。