1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

電流・電力監視IC INA219 をライブラリーを使わずに読む

Last updated at Posted at 2022-04-07

お手頃価格でモジュールが売っている,電流の測定ができるIC INA219 を,勉強のため,偉大な先人たちが作ったライブラリーを使わずに,データシートを参照しながら読んでみました。すっごく勉強になりました。

デフォルトで電圧と電流値が得られる

きちんと接続して,レジスターの値を読むだけで電圧と電流が得られます。

電圧を読む

((POINTER ADDRESS 02番のレジスター値)>>3)/*4で,[mV]が得られます。

MicroPythonスクリプト例.py
# d[2] = Register Value [2]

print("Bus Voltage Register: 0x%04X %d(d)" % (d[2],d[2]))
print("  Voltage: %d[mV]" % ((d[2]>>3)*4))
実行例.REPL
Bus Voltage Register: 0x2582 9602(d)
  Voltage: 4800[mV]

分解能は4mVです。データシートに記載があります。
d[2]には16ビットのレジスター値が入っている前提です。以下同じ

ここではLSBの3ビットは無視します。

電流を読む

Calibration Register を設定することで,デバイスから電流(計算)値を読むことができます。

しかし,シャント抵抗の両端電圧は,Calibration Register を設定しなくても読めます。(POINTER ADDRESS 01番のレジスター値)/100で,[mV]が得られます。

シャント抵抗の両端の電圧がわかれば,それをシャント抵抗値で割れば電流値が計算できます。

電流 =(シャント抵抗の両端の電圧)/(シャント抵抗の値)

MicroPythonスクリプト例.py
# d[1] = Register Value [1]

print("====")
print("Shunt Voltage Register: 0x%04X %d(d)" % (d[1],d[1]))
print("  Shunt Voltage: %f[mV]"%(toSigned16(d[1])/100))
実行例.REPL
Shunt Voltage Register: 0xFE19 65049(d)
  Shunt Voltage: -4.869999[mV]

ここでは0.1オームのシャント抵抗を使っていますので,-4.869999 / 0.1 ≒ -48.6[mA]となります。

この Shunt Register Voltage は符号付き16ビットです。上記はそれを変換する自前の関数を使っています。

電流を読む 続き

シャント抵抗の値を加味したレジスター値を設定することで,電流の計算をしてくれます。

  • Calibrationレジスター(POINTER ADDRESS 05番)に,40.96/シャント抵抗の値 を書き込みます。
  • POINTER ADDRESS 4番のレジスター値を読むことで,電流値[mA]が得られます。
MicroPythonスクリプト例.py
writeRegisterI2C16(5, 40.96 / 0.1) # Rshunt=0.1
d=readAllRegister()
print("Current Register: 0x%04X %d(d)" % (d[4],d[4]))
print("  Current: %f[mA]"%(toSigned16(d[4])))
実行例.REPL
Current Register: 0xFFCF 65487(d)
  Current: -49.000001[mA]

このレジスターは符号付きです。
writeRegisterI2C16は自前で書いたINA219のレジスターに書く関数,readAllRegisterは6個すべてのINA219のレジスター値を読む関数です。

消費電力を読む

Calibrationレジスターが設定されていればINA219が計算してPowerレジスター(POINTER ADDRESS 03番)に書いてくれます。(POINTER ADDRESS 03番のレジスター値)*0.02で,[W]が得られます。

MicroPythonスクリプト例.py
print("Power Register: 0x%04X %d(d)" % (d[3],d[3]))
print("  Power: %f[W]"%(d[3]*0.02))
実行例.REPL
Power Register: 0x000B 11(d)
  Power: 0.220000[W]

補足

  • 電流と電力への換算はバックグラウンドで行われる旨,データシートに記載がありました。そのため,電流と電力をデバイスに計算させても,サンプリング時間には影響がないようです。

そもそもですが...

I2Cデバイスのレジスターを読み書きするには...

MicroPythonスクリプト例.py
from machine import Pin, I2C

i2c = I2C(sda=Pin(4), scl=Pin(5), freq=400000)

def readRegisterI2C16(a): # a=pointer address
    i2c.writeto(64,bytearray([a]))
    d=list(i2c.readfrom(64,2))
    return(d[0]*256+d[1])

def writeRegisterI2C16(a, d): # a=pointer address, d=16bit data
    i2c.writeto(64,bytearray([a, int(d)>>8, int(d) & 0xff]))

def readAllRegister():
    return([
        readRegisterI2C16(0), # Configuration
        readRegisterI2C16(1), # Shunt Voltage
        readRegisterI2C16(2), # Bus Voltage
        readRegisterI2C16(3), # Power
        readRegisterI2C16(4), # Current
        readRegisterI2C16(5)  # Calibration
        ])

def printRegisterSummery(d):
    print("ADD: 0:con 1:s-v 2:b-v 3:pow 4:cur 5:cal")
    print("REG: ",end="")

    for i in range(6):
        print("%04X  "%(d[i]),end="")

    print("")

writeRegisterI2C16(5, 40.96 / 0.1) # Rshunt=0.1
d=readAllRegister()
printRegisterSummery(d)
実行例.REPL
ADD: 0:con 1:s-v 2:b-v 3:pow 4:cur 5:cal
REG: 399F  FE19  2582  000B  FFCF  0198  

(2022/4/8 修正)
データシート16ページ目に記載がありました。

レジスターに16ビット書く場合は,
[pointer address W] [上位 8バイト W] [下位 8ビット W] [ストップビット]
の順で書きます。

レジスターから読む場合は,
[pointer address W] [ストップビット] [上位 8バイト R] [下位 8ビット R]

という感じです。

使ったスクリプト

MicroPythonスクリプト例.py
from machine import Pin, I2C

i2c = I2C(sda=Pin(4), scl=Pin(5), freq=400000)

def readRegisterI2C16(a): # a=pointer address
    i2c.writeto(64,bytearray([a]))
    d=list(i2c.readfrom(64,2))
    return(d[0]*256+d[1])

def writeRegisterI2C16(a, d): # a=pointer address, d=16bit data
    i2c.writeto(64,bytearray([a, int(d)>>8, int(d) & 0xff]))

def readAllRegister():
    return([
        readRegisterI2C16(0), # Configuration
        readRegisterI2C16(1), # Shunt Voltage
        readRegisterI2C16(2), # Bus Voltage
        readRegisterI2C16(3), # Power
        readRegisterI2C16(4), # Current
        readRegisterI2C16(5)  # Calibration
        ])

# summery

def printRegisterSummery(d):
    print("ADD: 0:con 1:s-v 2:b-v 3:pow 4:cur 5:cal")
    print("REG: ",end="")

    for i in range(6):
        print("%04X  "%(d[i]),end="")

    print("")

# set shunt resister

print("Set Calibration register as R[SHUNT]=0.1")
print("====")

writeRegisterI2C16(5, 40.96 / 0.1) # Rshunt=0.1
d=readAllRegister()
printRegisterSummery(d)

# Bus Voltage

print("====")
print("Bus Voltage Register: 0x%04X %d(d)" % (d[2],d[2]))
print("  OVF:",(d[2] & 1)) # bit0
print(" CNVR:",((d[2]>>1) & 1)) # bit1
print(" Voltage: %d[mV]" % ((d[2]>>3)*4))

# convert 2's complement (ref)
# https://note.com/suujyou3/n/n35fca266f7b6

def toSigned16(d):
    return((d>>15) * (2**15) * (-1) + (d & 0x7FFF))

# Shunt Voltage

print("====")
print("Shunt Voltage Register: 0x%04X %d(d)" % (d[1],d[1]))
print("  Shunt Voltage: %f[mV]"%(toSigned16(d[1])/100))

# Current

print("====")
print("Current Register: 0x%04X %d(d)" % (d[4],d[4]))
print("  Current: %f[mA]"%(toSigned16(d[4])))

# Power

print("====")
print("Power Register: 0x%04X %d(d)" % (d[3],d[3]))
print("  Power: %f[W]"%(d[3]*0.02))
実行例.REPL
Set Calibration register as R[SHUNT]=0.1
====
ADD: 0:con 1:s-v 2:b-v 3:pow 4:cur 5:cal
REG: 399F  FE19  2582  000B  FFCF  0198  
====
Bus Voltage Register: 0x2582 9602(d)
  OVF: 0
 CNVR: 1
 Voltage: 4800[mV]
====
Shunt Voltage Register: 0xFE19 65049(d)
  Shunt Voltage: -4.869999[mV]
====
Current Register: 0xFFCF 65487(d)
  Current: -49.000001[mA]
====
Power Register: 0x000B 11(d)
  Power: 0.220000[W]

負の電流値を確認するために,あえて

VBUS - VIN- ... Vin+ - 100Ω抵抗 - GND

と接続してみました。モジュール内蔵のシャント抵抗は0.1オームです。

Thanks to 感謝です!

https://qiita.com/kanade_k_1228/items/3234317e456a5999f663
https://garchiving.com/current-voltage-measurement-with-arduino/
https://qiita.com/z589app/items/2818483fbbbc233762ec

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?