INA219: Simple Arduino current measurement up to 3.2A. How your Arduino can
measure 3.2A at 100uA resolution, measuring the voltage and power
consumption at the same time, using an I2C chip.
The INA219 :
Measures current using a high-side shunt resistor.
Uses a simple I2C interface.
Has a resolution of 100uA (with a 0.1R shunt resistor).
Measures voltage and current and therefore power.
This chip measures voltage
across a known resistance (usually 0.1R - see above image). You program
the value of the resistance into the chip and it returns a value in
Amps.
The breakout board version below can measure ~3.2A but the chip can
measure 10~15A using a different sense resistor (See the datasheet for example calculations).
Interesting features:
1. Current (~3.2A) and voltage (~26V) measurement; these are independent of 5V (Vcc).
2. You can change the maximum current measured or the resolution measurement (change sense resistor + software).
3. The polarity of the measured input does not matter (but no reading for -ve).
4. Uses an internal opamp - no external amplification needed - it also has a defined accuracy so it does not need calibrating.
5.Can report power used in the load (as it measures I and V).
6. You make a measurement by connecting to high supply Voltage
(usually 5V ~ but can be up to 26V) and then to your circuit, to the
supply of the chip/unit you want to observe the current.
[1] The total voltage between +Ain and -Ain must not exceed 0.3~26V. [2] The device comes in two accuracy standards A, B with B more accurate. [3] Offset voltage is lower for the B part - see datasheet.
[4] Inputs are reversible but you can only measure if +Ain > -Ain.
[5] 15 bit resolution is achieved by averaging for ±320mV range.
How to Wire INA219
How to connect INA219: It's simple just connect Vin+ to your supply
voltage (this is the high side voltage), and connect Vin- to your
circuit - this is the power supply to your circuit.
The bus voltage (VIN-) is the voltage measured at your circuit. So it is the Supply voltage minus the voltage developed
across the shunt resistor - which is small because the resistor is
0.1Ohms. As your circuit draws more current more voltage is dropped
across the shunt resistor and the bus voltage drops. That's the price of any measuring circuit.
Resolution
Current resolution is set by the minimum detectable voltage (across RSHUNT); 1
LSB of the ADC; fixed at 10uV. This is an internally set value
controlled in the chip but you can change the current resolution by changing the value of RSHUNT.
Therefore minimum detectable current = 10uV/ Shunt resistor.
Typically RSHUNT = 0R1 so...
Minimum detectable current (12 bit res.) = 10uV/0.1R = 100uA.
Normally the shunt resistor is 0.1Ohms, as these are commonly fitted
to breakout boards. However, you can select any shunt resistor e.g.
2mOhm and the current resolution will change; changing the calculation above.
You can find an example design that uses a different shunt resistance value in the data sheet.
Note The bus voltage resolution, different to the current resolution and is set at 4mV per LSB.
Resolution with Averaging
The device resolution is odd as the physical ADC is 12-bit but the data
sheet mentions 15-bits.
Oversampling is used to increase the effective ADC bits from the physical 12-bit ADC, to a 15bit oversampled ADC output. This is why equations below
(and in the datasheet) reference 215. Very confusing as the data sheet does not really mention oversampling!
Inside the INA219 there is an ADC which can only measure voltage; Specifically the differential input VIN+ - VIN-, and using internal switches it also measures VIN- referenced to ground (using the same amplifier).
[Source: datasheet]
The INA219 cannot measure current unless it knows
the value of the external shunt resistance. This why there is are
programmable registers for configuration and calibration (See Table 2 in
the datasheet "Summary of Register Set").
[Source: datasheet]
These registers and their operation are shown in the diagram below:
[Source: datasheet]
Resolution Bits and Sampling Trade Off
By averaging any ADC reading you can increase the number of bits
available. This chip can do that for you using up to 128 samples. The
default start-up register state is set to 12bit conversion with a
conversion time of 532us.
You can select a lower resolution result to give a faster read rate
or you can allow the chip to oversample which results in a more accurate
reading - but the read rate is slower. The table below shows the rate for the lower bit numbers:
Bits/Samples
Conversion Time (typ)
Conversion Time (max)
9 bit
84us
93us
10 bit
148us
163us
11 bit
276us
304us
12 bit [default]
532us
586us
2 samples
1.06ms
1.17ms
128 samples
68.10ms
75.01ms
[Source: Datasheet Table 5 ADC Settings, and main specs.]
You can also use sample rates 4, 8, 16, 32, and 64. To find the
conversion time simply multiply the sample rate chosen by the 12bit
sample time e.g. 128 samples gives 128 * 532e-6 = 0.068096 (this is a typical value - the max is 75ms).
Bit Range and PGA Gain
The total number of bits collected depends on the PGA gain selected:
PGA Gain
ADC Bits (n)
FSR (mV)
LSB calc mV/pow(2,n)
8 [default]
15
320
9.765uV
4
14
160
9.765uV
2
13
80
9.765uV
1
12
40
9.765uV
[Source: Datasheet 8.6.3.1 Shunt Voltage Register]
FSR is the Full Scale Range and is measured across the shunt resistor.
As the gain is increased so the number of ADC bits increases keeping
the LSB value the same. Increasing the number of bits by oversampling
means the time to gather the result increases.
Notice how the LSB calculation is kept the same with changing gain -
this keeps the resolution consistent across different gain settings.
As well as the functions that retrieve data there are two calibration functions:
setCorrectionFactor setShuntVoltOffset_mV
The function setShuntVoltOffset_mV is used to compensate the
offset voltage ±100uV (o error) for the internal ADC. Note that this
offset changes with the programmed gain (see the specifications above).
You can use this function to zero the output for zero current -
otherwise the offset makes it appear to indicate current flow when there
is none!
You can use the other calibration function setCorrectionFactor
to calibrate the INA219 if you have an accurate current meter you can
compensate for the gain error of the ADC i.e. the slope ADC.
Default settings (Simple use)
The following explanation does not follow the process outlined in the
datasheet because it is the simplest way to use the chip. It does
however rely on the shunt resistor being a power of 10. That allows the
fixed point method used here to work.
This is a statement from that datasheet that allows simple use:
"The Calibration Register can also be selected to provide values in
the Current Register (04h) and Power Register (03h) that either provide
direct decimal equivalents of the values being measured, or yield a
round LSB value for each corresponding register."
The idea is to use the minimal (I2C) read and write, and obtain an
output that can be processed using fixed point maths - and this will
save Flash memory.
If you don't program the chip then these are the defaults:
PG Programmable Gain (8) Shunt voltage ±320mV.
Resolution
12 bit.
Bus Range
32V
Mode
Shunt and Bus continuous.
The datasheet indicates that without programming you can read the
shunt voltage as an indication of current. So the voltage will be
proportional to the current used. In fact the shunt voltage will be the
shunt register value multiplied by 10uV (Datasheet: 8.5.1 Programming the
Calibration Register).
Since you know the shunt resistance value then the current is simply:
I = VSHUNT / Resistance
You can just make this calculation in the microcontroller and save
messing around. For the power you just multiply the bus voltage reading
(VBUS)
by the current value calculated.
Note: The code also sets the sample number to 128 for increased accuracy and resolution.
Sketch using simple equations
This section shows how to use the equations to derive voltage and
current with minimal programming and without using floating point. This
can save a lot of memory - for instance if you use a ATTiny85 saving
memory is paramount.
Simple Current
The easiest way to get the current reading is to use the shunt voltage register directly. The equation is:
RealShuntVoltage = ShuntVoltageRegister * 10e-6
Each LSB of the shunt voltage register is worth 10uV . What you need is the current so (when Rshunt = 0.1Ohm):
Current = V/R = (ShuntVoltageRegister * 10e-6 ) / Rshunt
Current = (ShuntVoltageRegister * 1e-4)
The 1e-4 value is saying the decimal point is four places to the left (see below for examples).
If the full maximum value of the shunt voltage is dropped across the
shunt resistor (320mV) then it means that 3.2Amps is flowing
(0.32V/0.1Ohms=3.2A). The value in the current register will be 32000
(Datasheet: Table 7).
Taking this value as a fixed point value means that the decimal point is 4 places to the left so:
For a current of 3.2A, the shunt register will contain 32000:
32000 -> 3.2000A
Some more examples:
For a current of 100mA, the shunt register will contain 1000:
01000 -> 0.1000A
For a current of 10mA, the shunt register will contain 100:
00100 -> 0.0100A
For a current of 1mA, the shunt register will contain 10:
00010 -> 0.0010A
Warning: This technique only works easily
for Shunt resistances with a power of 10. e.g. 0.1Ohm, 10mOhm, 1.0 Ohm etc.
These register values can easily be processed without floating point.
For instance you could make a limit detect at 300mA just by detecting
if the value is greater than 3000.
You can also display these values by converting them to an ASCII
representation e.g. using itoa, and then displaying leading zeros as
necessary. One example is shown here: ina219-compare.ino.
Bus Voltage
The bus voltage conversion has an LSB value of 4mV and we want a reading in millivolts. The bus register
is shifted left by 3 bits in the hardware of the INA219.
To get the reading you could shift it right by 3 bits, then
multiply by four, but since these are simple powers of two, a shift right by 1 bit results in the correct millivolt reading.
Fixed Point Reading Example
To output a useful value for display requires a little bit of formatting (and knowing where to place the fixed point). See ina219-compare.ino for how to do this.
This link lets you download a pdf that explains the INA219 equations (they were previously on this page).
The following sketch examines three use cases:
Raw register output
Library use with floating point calculations.
Fixed point output.
You can see from the results that they all give the same "output".
This works because the shunt resistor is a power of 10 - 0.1Ohms. You
would have to use the "library" flocating point functions if you change
the shunt resistor to a non power-of -ten value.
TIP: Using Fixed point (with no floating point used elsewhere) saves 2k Flash.
Just to illustrate the readings you get using fixed point the
following sketch shows "normal" use of the library compared to, "raw register values", and "fixed
point" formatting:
#include <Wire.h>
#include <INA219_WE.h>
INA219_WEina219(0x45);
voidsetup(void){
Wire.begin();
Serial.begin(119200);
ina219.init();
ina219.setADCMode(SAMPLE_MODE_128);}
// Print fixed point with dp decimal places to left.
voidprintFixedPointdp(longv,intdp){
longdpdiv=1;
for(inti=0;i<dp;i++,dpdiv*=10);
longleft=v/dpdiv;
longrght=v%dpdiv;
if(left==0)Serial.print('0');elseSerial.print(left);
Serial.print('.');
if(rght==0)Serial.print("000");elseSerial.print(rght);
}
voidloop(void){
// "Normal usage"
Serial.println("float--------");
floatf=ina219.getCurrent_mA();
Serial.print("I ");Serial.print(f,4);Serial.println("mA");
f=ina219.getShuntVoltage_mV();
Serial.print("VS ");Serial.print(f,4);Serial.println("mV");
f=ina219.getBusVoltage_V();
Serial.print("VB ");Serial.print(f,4);Serial.println("V");
f=ina219.getBusPower();
Serial.print("P ");Serial.print(f,4);Serial.println("mW");
Serial.println("RAW--------");
intvshuntreg=ina219.readRegister(INA219_SHUNT_REG);
Serial.print("raw VS ");Serial.println(vshuntreg);
longcurrent=vshuntreg*10;
Serial.print("raw I ");Serial.println(current);
intbusvoltagereg=(ina219.readRegister(INA219_BUS_REG)&0xfff8)>>1;// BV is shifted left 3 bits.
Serial.print(" BV ");Serial.println(busvoltagereg);
longbuspower=current*(long)busvoltagereg;
Serial.print(" P ");Serial.println(buspower);
// Print formatted fixed point values.
Serial.println("Fixed------");
Serial.print(" I ");printFixedPointdp(current,2);Serial.println("mA");
Serial.print("VS ");printFixedPointdp(vshuntreg,2);Serial.println("mV");
Serial.print("BV ");printFixedPointdp(busvoltagereg,3);Serial.println("V");
Serial.print(" P ");printFixedPointdp(buspower,5);Serial.println("mW");
delay(1000);
}
[ ina219-compare.ino ]
This is the typical output from the sketch above:
float--------
I 15.5000mA
VS 1.5500mV
VB 4.7880V
P 76.0000mW
RAW--------
raw VS 155
raw I 1550
BV 4788
P 7421400
Fixed------
I 15.50mA
VS 1.55mV
BV 4.788V
P 74.21400mW
INA219 Observations
There are a lot of complicated equations that used to be on this page stored here.
I removed them as the fundamental operation of the chip is simply to
return the ADC value of the voltage developed across the shunt
resistance (see fixed point code above). From that you can calculate
everything else within your program.
The datasheet makes a great play of how the device has registers for
Power
Current
Voltage
However until you calculate the calibration register value and
program it in, the device returns power and current as zero (because the
calibration register defaults to zero).
The calibration register is set to use the shunt resistance value to allow power and current to be reported.
Consider using the INA219 as it was intended
You program the calibration register using your shunt resistance value.
The chip calculates power and current using the calibration register.
You get the "integer" values of power and current.
The data sheet says:
Shunt voltage is calculated by multiplying the Shunt Voltage Register contents with the Shunt Voltage LSB of 10µV.
(Note: this equation allows fixed point operation as it uses a power of 10)
The data sheet also says:
The Bus Voltage register bits are not right-aligned. In order to compute the value of the Bus Voltage, Bus Voltage
Register contents must be shifted right by three bits. This shift puts the BD0 bit in the LSB position so that the
contents can be multiplied by the Bus Voltage LSB of 4-mV to compute the bus voltage measured by the device.
Your program must now use floating point calculations to obtain the final readings:
To get the shunt voltage calculate shunt_register * 10e-6
To get the current divide the shunt voltage by RSHUNT.
To get the bus voltage multiply bus_voltage_register by 4e-3.
The value expected in the Power register (03h) can be calculated by
multiplying the Current register value by the Bus Voltage register value
and then dividing by 5000 as shown in Equation 5. [datasheet]
The key issue is that these registers always contain an integer
value. So when you want to get the "real" value from them you you have to do some calculations - probably floating point.
My point is why bother? - just get Vshunt out and calculate
everything else within your program (or just use a library - or just use
Fixed point as explained in this page). Even if the chip does an
"integer" calculation you still have to do calculations anyway.
However the datasheet also says:
The Calibration Register can also be selected to provide values in the Current Register
(04h) and Power Register (03h) that either provide direct decimal equivalents of the values being measured, or
yield a round LSB value for each corresponding register
So you can probably get round having to do calculations in your program if you do some mental gymnastics in using the chip!
INA219 Conclusions
The INA219 is a very easy chip to use (if you use a library and don't
look at the complicated equations!) and it is really plug in and go - as
long as your measurement voltage is within 26V. You can use the
standard libraries to easily obtain readings for current, bus voltage
and power.
TIP: Using fixzed point calculations saves 2k Flash.
It can measure with a resolution of 100uA using the default sense resistor: 0.1Ohms.
TIP: Change the shunt resistance -lower- to measure higher current.
For instance, if you changed the shunt resistor to 0.02 Ohms you can measure 10~15A.
(See the datasheet for an example). You have to re-calculate the
calibration register settings for this resistance.
Written by John Main, who has a degree in Electronic Engineering.
Unlock the secrets of Arduino scrolling displays! This beginner-friendly guide shows you how to create real-time, dynamic graphics using an SSD1306 OLED, perfect for tracking sensor data and building…
How to get accurate DHT22 digital humidity sensor readings with an Arduino. Did you know it also measures temperature as Well? Find out why, in this page...
A PIR sensor lets your Arduino sense movement without contact. This tutorial covers PIR sensor basics, connecting one to an Arduino board and coding a motion detector.
Arduino Hall Effect Sensor: Add magnetic sensing superpowers to your Arduino projects with an easy-to-use hall effect sensor. With full code and layout...
Comments
Have your say about what you just read! Leave me a comment in the box below.
Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.