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 のサンプルはすぐに見つからなかったけども、どうんな感じになるんだろう?
・自分で作ったハードが動いてうれしぃ!
・レジスタって、どういう回路なの? どういう仕組みで覚えているんだろう?