PCB が組みあがったのですが、これを RasPi で i2c するサンプルをググってみたら、いくつかありました。
RasPi は、i2c が使えるようにモジュールをロードしておきました。RasPi でi2c は初めて使います。無事に出来るでしょうか?
# lsmod Module Size Used by ★i2c_dev 6027 0 cfg80211 386508 0 rfkill 16651 1 cfg80211 rpcsec_gss_krb5 20958 0 nfsd 263569 2 snd_bcm2835 18649 0 snd_pcm 73475 1 snd_bcm2835 snd_seq 53078 0 snd_seq_device 5628 1 snd_seq snd_timer 17784 2 snd_pcm,snd_seq snd 51038 5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device ★i2c_bcm2708 4990 0 joydev 8879 0 spi_bcm2708 5137 0 evdev 9950 2 uio_pdrv_genirq 2958 0 uio 8119 1 uio_pdrv_genirq
先輩たちがサンプルコードは書いているはずなので、探したところ、python でやるのとか、ruby でやるのとかがすぐ見つかりました。
とりあえず、動作確認したいので以下のサイトのコードを参考に必要な部分だけ使わせてもらいました。
Rabbit Note
BeagleBone Black で作るロギング機能付き電力計 (ソフト編)
BeagleBone Black(BBBと略するようです)での環境ですが、大変参考になりました。
使わせていただいたコードは最下部に付けておきます。で、配線は写真のようにちょっと雑ですが配線。負荷には、ちっさいファンをつけてみました。
スレーブアドレスは、何も設定しないと、0x40 が設定されるようです。
# 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: -- -- -- -- -- -- -- --
プログラムを起動すると、以下のようになります。
# ./test.ruby --------- 2016/01/25, 01:33:22 4.78125 V 151 mA 0.29 W --------- 2016/01/25, 01:33:22 4.78125 V 151 mA 0.289 W --------- 2016/01/25, 01:33:23 4.78875 V 152 mA 0.291 W --------- 2016/01/25, 01:33:23 4.7875 V 151 mA 0.29 W --------- 2016/01/25, 01:33:24 4.7875 V 150 mA 0.289 W --------- 2016/01/25, 01:33:24 4.7875 V 151 mA 0.29 W --------- 2016/01/25, 01:33:25 4.79 V 152 mA 0.292 W
負荷にLED を点けてみると、以下のようです。
# ./test.ruby --------- 2016/01/25, 01:35:31 4.88 V 2 mA 0.005 W --------- 2016/01/25, 01:35:31 4.88 V 2 mA 0.005 W --------- 2016/01/25, 01:35:31 4.9125 V 2 mA 0.005 W --------- 2016/01/25, 01:35:32 4.91375 V 2 mA 0.005 W --------- 2016/01/25, 01:35:32 4.91375 V 2 mA 0.005 W
まだあまりちゃんと理解していませんが、内部のレジスタの ox05 に、キャリブレーションする設定値を入れるようです。
以下の C のサンプルコードから、シャント抵抗に0.025R を使っている場合は、以下のように計算した16進数を入れればよいようです。書き込むとき、以下のコードでは、リトルエンディアンに変換していました。
https://github.com/jarzebski/Arduino-INA226/blob/master/INA226.cpp
0.025Ω = 0.00512/(0.025*0.0001)=2048 = 0x08 0x00
0x05 の補正レジスタを見てみると、
# i2cget -y 1 0x40 0x05 w
0x0008
という値が帰ってきました。
さて、そんな感じでとりあえずコードは以下のようにしてみました。
#!/usr/bin/env ruby # -*- coding: utf-8 -*- IOCTL_I2C_SLAVE = 0x0703 # Script for power meter using the following parts # - Power Meter module (IC: INA226) # # 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: -- -- -- -- -- -- -- -- class PowerSenseor def initialize(i2c_bus=1, dev_addr=0x40) @i2c = File.open(sprintf('/dev/i2c-%d', i2c_bus), 'rb+') @i2c.ioctl(IOCTL_I2C_SLAVE, dev_addr) @dev_addr = dev_addr @v_val = 0 @c_val = 0 @p_val = 0 # shunt resistor = 0.002Ω = 0.00512/(0.002*0.001)=2560 = 0x0a 0x00 # 0.025Ω = 0.00512/(0.025*0.0001)=2048 = 0x08 0x00 # 内部レジスタ[0x04] (Current) = 内部レジスタ[0x01]×内部レジスタ[0x05] / 2048 exec_cmd("i2cset -y 1 0x#{dev_addr.to_s(16)} 0x05 0x08 0x00 i") # conversion time = 332us, number of average = 16 exec_cmd("i2cset -y 1 0x#{dev_addr.to_s(16)} 0x00 0x04 0x97 i") end def sense # i2cset/i2cget は 10ms オーダーの時間を消費するのでここでは使用しない @i2c.write(0x02) @v_val = conver_signed(@i2c.read(2)) # 0x04 電流レジスタ @i2c.write(0x04) @c_val = conver_signed(@i2c.read(2)) # 0x03 Powerレジスタ @i2c.write(0x03) @p_val = conver_signed(@i2c.read(2)) end def conver_signed(bytes) # convert endian return bytes.unpack('n').pack('S').unpack('s')[0].abs end def get_voltage return calc_voltage(@v_val) end def get_current return calc_current(@c_val) end def get_power return calc_power(@p_val) end def exec_cmd(cmd) val=`#{cmd} 2> /dev/null` raise StandardError, "FAIL: #{cmd}" unless $?.success? return val end def calc_voltage(v_val) return v_val * 1.25 / 1000.0 end # 0x04 電流レジスタ def calc_current(c_val) return c_val / 10 end # 0x03 Powerレジスタ def calc_power(p_val) # return p_val * 0.025 return p_val * 0.001 end end require 'optparse' params = ARGV.getopts('lq') data_list = [] Signal.trap(:INT){ if params['l'] then printf("time,voltage,current,power\n") data_list.each{|data| printf("%10d,%.3f,%.3f,%.3f\n", data[0], data[1], data[2], data[3]) } end exit(0) } sensor = PowerSenseor.new require "date" start_time = Time.now i = 0 while true sensor.sense v = sensor.get_voltage c = sensor.get_current p = sensor.get_power dt = DateTime.now print "--------- " print(dt.strftime("%Y/%m/%d, %H:%M:%S"), "\n") print v print " V\n" print c print " mA\n" print p print " W\n" if ((i & 0x7F) == 0) then else sleep 0.5 end i = (i & 0xff) + 1 end
▼まとめ
・0x05 にシャント抵抗値を入れた補正値を書き込む
・書き込む最は、16進をリトルエンディアンにして書き込む
・0x04 はPowerレジスタで、0x04 は電流レジスタ。
・LSB ってなに?
・ちっこい今使っているファンは、150mA くらい使っていて0.3W ほど
・c のサンプルはすぐに見つからなかったけども、どうんな感じになるんだろう?
・自分で作ったハードが動いてうれしぃ!
・レジスタって、どういう回路なの? どういう仕組みで覚えているんだろう?