├── .gitignore ├── examples ├── hardware_mounting │ ├── ina219_hardware_mount.fzz │ └── ina219_hardware_mount_bb.png ├── ina219_test │ └── ina219_test.ino ├── ina219_test_nondefault │ └── ina219_test_nondefault.ino └── ina219_morechecks │ └── ina219_morechecks.ino ├── keywords.txt ├── library.properties ├── library.json ├── README.md ├── INA219.h └── INA219.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | -------------------------------------------------------------------------------- /examples/hardware_mounting/ina219_hardware_mount.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flav1972/ArduinoINA219/HEAD/examples/hardware_mounting/ina219_hardware_mount.fzz -------------------------------------------------------------------------------- /examples/hardware_mounting/ina219_hardware_mount_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flav1972/ArduinoINA219/HEAD/examples/hardware_mounting/ina219_hardware_mount_bb.png -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | INA219 KEYWORD1 2 | begin KEYWORD2 3 | calibrate KEYWORD2 4 | configure KEYWORD2 5 | reset KEYWORD2 6 | shuntVoltageRaw KEYWORD2 7 | busVoltageRaw KEYWORD2 8 | shuntCurrentRaw KEYWORD2 9 | shuntVoltage KEYWORD2 10 | busVoltage KEYWORD2 11 | shuntCurrent KEYWORD2 12 | busPower KEYWORD2 13 | reconfig KEYWORD2 14 | recalibrate KEYWORD2 15 | ready KEYWORD2 16 | overflow KEYWORD2 17 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ArduinoINA219 2 | version=1.1.1 3 | author=DeCristofaro John , Jukka-Pekka Sarjanen , gandy92 , Flavius Bindea , Robert Wolff 4 | maintainer=Flavius Bindea 5 | sentence=INA219 hi-side i2c current/power sensor Library 6 | paragraph=INA219 hi-side i2c current/power sensor Library 7 | category=Sensors 8 | url=https://github.com/flav1972/ArduinoINA219 9 | architectures=* 10 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ArduinoINA219", 3 | "version": "1.1.1", 4 | "description": "TI INA219 hi-side i2c current/power monitor Library", 5 | "keywords": "sensors, i2c, driver, sensor, battery, monitor, current, voltage", 6 | "repository": 7 | { 8 | "type": "git", 9 | "url": "https://github.com/flav1972/ArduinoINA219" 10 | }, 11 | "authors": 12 | [ 13 | { 14 | "name": "DeCristofaro John", 15 | "email": "johngineer@yahoo.com" 16 | }, 17 | { 18 | "name": "Jukka-Pekka Sarjanen", 19 | "email": "jukka-Pekka.sarjanen@kone.com" 20 | }, 21 | { 22 | "name": "gandy92", 23 | "email": "gandy92@googlemail.com" 24 | }, 25 | { 26 | "name": "Flavius Bindea", 27 | "email": "flav@flav.com", 28 | "maintainer": true 29 | }, 30 | { 31 | "name": "Robert Wolff", 32 | "email": "bob.wolff68@gmail.com" 33 | } 34 | ], 35 | "frameworks": "arduino" 36 | } 37 | -------------------------------------------------------------------------------- /examples/ina219_test/ina219_test.ino: -------------------------------------------------------------------------------- 1 | /********************************************** 2 | * INA219 library example 3 | * 10 May 2012 by johngineer 4 | * 5 | * 9 January 2016 Flavius Bindea: changed default values and begin() 6 | * 7 | * this code is public domain. 8 | **********************************************/ 9 | 10 | 11 | #include 12 | #include 13 | 14 | INA219 monitor; 15 | 16 | 17 | void setup() 18 | { 19 | Serial.begin(9600); 20 | monitor.begin(); 21 | // begin calls: 22 | // configure() with default values RANGE_32V, GAIN_8_320MV, ADC_12BIT, ADC_12BIT, CONT_SH_BUS 23 | // calibrate() with default values D_SHUNT=0.1, D_V_BUS_MAX=32, D_V_SHUNT_MAX=0.2, D_I_MAX_EXPECTED=2 24 | // in order to work directly with ADAFruit's INA219B breakout 25 | } 26 | 27 | void loop() 28 | { 29 | 30 | Serial.println("******************"); 31 | 32 | Serial.print("raw shunt voltage: "); 33 | Serial.println(monitor.shuntVoltageRaw()); 34 | 35 | Serial.print("raw bus voltage: "); 36 | Serial.println(monitor.busVoltageRaw()); 37 | 38 | Serial.println("--"); 39 | 40 | Serial.print("shunt voltage: "); 41 | Serial.print(monitor.shuntVoltage() * 1000, 4); 42 | Serial.println(" mV"); 43 | 44 | Serial.print("shunt current: "); 45 | Serial.print(monitor.shuntCurrent() * 1000, 4); 46 | Serial.println(" mA"); 47 | 48 | Serial.print("bus voltage: "); 49 | Serial.print(monitor.busVoltage(), 4); 50 | Serial.println(" V"); 51 | 52 | Serial.print("bus power: "); 53 | Serial.print(monitor.busPower() * 1000, 4); 54 | Serial.println(" mW"); 55 | 56 | Serial.println(" "); 57 | Serial.println(" "); 58 | 59 | delay(10000); 60 | 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /examples/ina219_test_nondefault/ina219_test_nondefault.ino: -------------------------------------------------------------------------------- 1 | /********************************************** 2 | * INA219 library example 3 | * 9 January 2016 by Flavius Bindea 4 | * 5 | * this code is public domain. 6 | **********************************************/ 7 | 8 | 9 | #include 10 | #include 11 | 12 | #define SHUNT_MAX_V 0.04 /* Rated max for our shunt is 75mv for 50 A current: 13 | we will mesure only up to 20A so max is about 75mV*20/50 lets put some more*/ 14 | #define BUS_MAX_V 16.0 /* with 12v lead acid battery this should be enough*/ 15 | #define MAX_CURRENT 20 /* In our case this is enaugh even shunt is capable to 50 A*/ 16 | #define SHUNT_R 0.015 /* Shunt resistor in ohm */ 17 | 18 | INA219 monitor; 19 | 20 | void setup() 21 | { 22 | Serial.begin(57600); 23 | monitor.begin(); 24 | // setting up our configuration 25 | // default values are RANGE_32V, GAIN_8_320MV, ADC_12BIT, ADC_12BIT, CONT_SH_BUS 26 | monitor.configure(INA219::RANGE_16V, INA219::GAIN_2_80MV, INA219::ADC_64SAMP, INA219::ADC_64SAMP, INA219::CONT_SH_BUS); 27 | 28 | // calibrate with our values 29 | monitor.calibrate(SHUNT_R, SHUNT_MAX_V, BUS_MAX_V, MAX_CURRENT); 30 | } 31 | 32 | void loop() 33 | { 34 | Serial.println("******************"); 35 | 36 | Serial.print("raw shunt voltage: "); 37 | Serial.println(monitor.shuntVoltageRaw()); 38 | 39 | Serial.print("raw bus voltage: "); 40 | Serial.println(monitor.busVoltageRaw()); 41 | 42 | Serial.println("--"); 43 | 44 | Serial.print("shunt voltage: "); 45 | Serial.print(monitor.shuntVoltage() * 1000, 4); 46 | Serial.println(" mV"); 47 | 48 | Serial.print("shunt current: "); 49 | Serial.print(monitor.shuntCurrent() * 1000, 4); 50 | Serial.println(" mA"); 51 | 52 | Serial.print("bus voltage: "); 53 | Serial.print(monitor.busVoltage(), 4); 54 | Serial.println(" V"); 55 | 56 | Serial.print("bus power: "); 57 | Serial.print(monitor.busPower() * 1000, 4); 58 | Serial.println(" mW"); 59 | 60 | Serial.println(" "); 61 | Serial.println(" "); 62 | 63 | delay(1000); 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/ina219_morechecks/ina219_morechecks.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Baterry Monitor 3 | * by Flavius Bindea 4 | * this sketch uses averaging and check of ready status 5 | */ 6 | #include 7 | #include 8 | 9 | // Current sensor and shunt used 10 | INA219 ina219; 11 | 12 | #define R_SHUNT 0.00375 13 | #define V_SHUNT_MAX 0.075 14 | #define V_BUS_MAX 16 15 | #define I_MAX_EXPECTED 20 16 | 17 | boolean led=true; 18 | 19 | // current and voltage readings 20 | float shuntvoltage = 0; 21 | float busvoltage = 0; 22 | float current_A = 0; 23 | float batvoltage = 0; 24 | float power = 0; 25 | float Ah = 0; 26 | unsigned long lastread = 0; // used to calculate Ah 27 | unsigned long tick; // current read time - last read 28 | 29 | // different intervals for each Task 30 | int intervalReadData = 50; 31 | int intervalDisplay = 1000; 32 | 33 | // last taks call 34 | unsigned long previousMillisReadData = 0; 35 | unsigned long previousMillisDisplay = 0; 36 | 37 | void setup() { 38 | // put your setup code here, to run once: 39 | Serial.begin(57600); 40 | Serial.println("Hello - Arduino_INA219 !"); 41 | 42 | ina219.begin(); 43 | // configure INA219 for averaging at 16 samples (8.51ms) 44 | ina219.configure(INA219::RANGE_16V, INA219::GAIN_2_80MV, INA219::ADC_16SAMP, INA219::ADC_16SAMP, INA219::CONT_SH_BUS); 45 | // configure INA219 for averaging at 128 samples 46 | //ina219.configure(INA219::RANGE_16V, INA219::GAIN_2_80MV, INA219::ADC_128SAMP, INA219::ADC_128SAMP, INA219::CONT_SH_BUS); 47 | lastread = millis(); 48 | // calibrate INA219 with out shunt values 49 | ina219.calibrate(R_SHUNT, V_SHUNT_MAX, V_BUS_MAX, I_MAX_EXPECTED); 50 | 51 | // for led blinking 52 | pinMode(13, OUTPUT); 53 | 54 | /* 55 | // use timer 1 to launch current reading 56 | // this is a test only and not sure it works 57 | Timer1.initialize(READFREQ); // 100ms reading interval 58 | Timer1.attachInterrupt(readCurrent); 59 | */ 60 | delay(1000); 61 | } 62 | 63 | void loop() { 64 | 65 | // get current time stamp 66 | // only need one for both if-statements 67 | unsigned long currentMillis = millis(); 68 | 69 | if ((unsigned long)(currentMillis - previousMillisReadData) >= intervalReadData) { 70 | previousMillisReadData = millis(); 71 | readCurrent(); 72 | Serial.print("tick: "); Serial.print(tick); Serial.println(" ms"); 73 | } 74 | if ((unsigned long)(currentMillis - previousMillisDisplay) >= intervalDisplay) { 75 | previousMillisDisplay = millis(); 76 | // displays data 77 | Serial.print("Bus Voltage: "); Serial.print(busvoltage,3); Serial.println(" V"); 78 | Serial.print("Shunt Voltage: "); Serial.print(shuntvoltage,3); Serial.println(" mV"); 79 | Serial.print("Bat Voltage: "); Serial.print(batvoltage,3); Serial.println(" V"); 80 | Serial.print("Current: "); Serial.print(current_A,3); Serial.println(" A"); 81 | Serial.print("Power: "); Serial.print(power,3); Serial.println(" W"); 82 | Serial.print("Ah: "); Serial.print(Ah,3); Serial.println(" Ah"); 83 | Serial.println(""); 84 | } 85 | // blink led 86 | digitalWrite(13, led); 87 | led = !led; 88 | 89 | delay(10); 90 | } 91 | 92 | void readCurrent() { 93 | uint32_t count = 0; 94 | unsigned long newtime; 95 | 96 | // Serial.println("waiting data ready"); 97 | 98 | // reads busVoltage 99 | busvoltage = ina219.busVoltage(); 100 | // waits for conversion ready 101 | while(!ina219.ready() && count < 500) { 102 | count++; 103 | delay(1); 104 | busvoltage = ina219.busVoltage(); 105 | } 106 | 107 | // Serial.print("Count: "); Serial.println(count); 108 | 109 | // read the other values 110 | shuntvoltage = ina219.shuntVoltage() * 1000; 111 | current_A = ina219.shuntCurrent(); 112 | batvoltage = busvoltage + (shuntvoltage / 1000); 113 | power = ina219.busPower(); 114 | newtime = millis(); 115 | tick = newtime - lastread; 116 | Ah += (current_A * tick)/3600000.0; 117 | lastread = newtime; 118 | 119 | // prepare for next read -- this is security just in case the ina219 is reset by transient curent 120 | ina219.recalibrate(); 121 | ina219.reconfig(); 122 | } 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TI INA219 hi-side i2c current/power monitor Library for Arduino 2 | =============================================================== 3 | # Authors 4 | ## John De Cristofaro 5 | * Initial releases 6 | 7 | ## Jukka-Pekka Sarjanen 8 | * Quite much small changes to Johns's original lib mostly documentation and 9 | C++ "mambo jambo" Doxy documentation etc. 10 | * One major change / fix: 11 | calibrate() function fixed to give correct ratings. 12 | 13 | ## gandy92 14 | * Fix compiling issue due to case sensitivity on linux systems 15 | 16 | ## Flavius Bindea 17 | * More examples 18 | * added shuntCurrentRaw() 19 | * changed begin() and default values for ADAFRUIT INA219 breakout 20 | * Added rewrite modes, read conversion ready, overflow functions 21 | * Fixed bug in calibrate() in order to use class variable cal 22 | 23 | # Tests and fonctionalities 24 | * Tested at standard i2c 100kbps signaling rate. 25 | * This library does not handle triggered conversion modes. It uses the INA219 26 | in continuous conversion mode. All reads are from continous conversions. 27 | * A note about the gain (PGA) setting: 28 | The gain of the ADC pre-amplifier is programmable in the INA219, and can 29 | be set between 1/8x (default) and unity. This allows a shunt voltage 30 | range of +/-320mV to +/-40mV respectively. Something to keep in mind, 31 | however, is that this change in gain DOES NOT affect the resolution 32 | of the ADC, which is fixed at 1uV. What it does do is increase noise 33 | immunity by exploiting the integrative nature of the delta-sigma ADC. 34 | For the best possible reading, you should set the gain to the range 35 | of voltages that you expect to see in your particular circuit. See 36 | page 15 in the datasheet for more info about the PGA. 37 | 38 | # Known bugs: 39 | * may return unreliable values if not connected to a bus or at bus currents below 10uA. 40 | 41 | # Dependencies: 42 | * Arduino Wire library 43 | 44 | # Usage 45 | ## Basic 46 | Look at [ina219_test](examples/ina219_test/ina219_test.ino) exemple sketch. 47 | This example works out of the box for Adafruit's INA219 Breakout. 48 | 49 | Include defintions and define needed object: 50 | ```Arduino 51 | #include 52 | #include 53 | 54 | INA219 monitor; 55 | ``` 56 | 57 | In the `setup()` function initialise the INA219: 58 | ```Arduino 59 | monitor.begin(); 60 | ``` 61 | 62 | Then in the `loop()` function make calls to different functions that are returning the values: 63 | ```Arduino 64 | Serial.print("raw shunt voltage: "); 65 | Serial.println(monitor.shuntVoltageRaw()); 66 | 67 | Serial.print("raw bus voltage: "); 68 | Serial.println(monitor.busVoltageRaw()); 69 | 70 | Serial.println("--"); 71 | 72 | Serial.print("shunt voltage: "); 73 | Serial.print(monitor.shuntVoltage() * 1000, 4); 74 | Serial.println(" mV"); 75 | 76 | Serial.print("shunt current: "); 77 | Serial.print(monitor.shuntCurrent() * 1000, 4); 78 | Serial.println(" mA"); 79 | 80 | Serial.print("bus voltage: "); 81 | Serial.print(monitor.busVoltage(), 4); 82 | Serial.println(" V"); 83 | 84 | Serial.print("bus power: "); 85 | Serial.print(monitor.busPower() * 1000, 4); 86 | Serial.println(" mW"); 87 | ``` 88 | ## Enhanced setup 89 | If you want to use a different setup or if you do not use the Adafruit's breakout then in the `setup()` function you need to call `configure()` and `calibrate()`. 90 | 91 | An exemple is in [ina219_test_nondefault](examples/ina219_test_nondefault/ina219_test_nondefault.ino). 92 | 93 | Extract of the `setup()` function: 94 | ```Arduino 95 | monitor.begin(); 96 | 97 | // setting up our configuration 98 | monitor.configure(INA219::RANGE_16V, INA219::GAIN_2_80MV, INA219::ADC_64SAMP, INA219::ADC_64SAMP, INA219::CONT_SH_BUS); 99 | 100 | // calibrate with our values 101 | monitor.calibrate(SHUNT_R, SHUNT_MAX_V, BUS_MAX_V, MAX_CURRENT); 102 | ``` 103 | 104 | ## functions 105 | All the functions are well comented in [INA219.h](INA219.h) and [INA219.cpp](INA219.cpp) 106 | * `begin()` 107 | starts the communication with the INA219 and does the default setup. 108 | * `configure()` 109 | setups the INA219 mode. 110 | 111 | The args are: `(range, gain, bus_adc, shunt_adc, mode)` 112 | * range : Range for bus voltage 113 | * RANGE_16V : Range 0-16 volts 114 | * RANGE_32V (default): Range 0-32 volts 115 | * gain : Set Gain for shunt voltage (choose the lowest possible depending on your hardware) 116 | * GAIN_1_40MV : 40mV 117 | * GAIN_2_80MV : 80mV 118 | * GAIN_4_160MV : 160mV 119 | * GAIN_8_320MV (default): 320mV 120 | * bus_adc : Configure bus voltage conversion 121 | * ADC_9BIT : 9bit, converion time 84us. 122 | * ADC_10BIT : 10bit, converion time 148us. 123 | * ADC_11BIT : 11bit, converion time 2766us. 124 | * ADC_12BIT (default): 12bit converion time 532us. 125 | * ADC_2SAMP : 2 samples converion time 1.06ms. 126 | * ADC_4SAMP : 4 samples converion time 2.13ms. 127 | * ADC_8SAMP : 8 samples converion time 4.26ms. 128 | * ADC_16SAMP : 16 samples converion time 8.51ms 129 | * ADC_32SAMP : 32 samples converion time 17.02ms. 130 | * ADC_64SAMP : 64 samples converion time 34.05ms. 131 | * ADC_128SAMP : 128 samples converion time 68.10ms. 132 | * shunt_adc: Configure shun voltage conversion. Same values as for bus_adc 133 | * mode: Sets operation mode. 134 | * PWR_DOWN : Power Down 135 | * ADC_OFF 136 | * CONT_SH : Shunt Continuous 137 | * CONT_BUS : Bus Continuous 138 | * CONT_SH_BUS (default): Shunt and Bus, Continuous. 139 | * `calibrate(r_shunt, v_shunt_max, v_bus_max, i_max_expected)` function is doing the calculations as described in the INA219 datasheet and sets up the calibration registers. 140 | 141 | The args are: 142 | * r_shunt : Value of shunt in Ohms. 143 | * v_shunt_max : Maximum value of voltage across shunt. 144 | * v_bus_max : Maximum voltage of bus. 145 | * i_max_expected : Maximum current draw of bus + shunt. 146 | * `reconfig()` rewrites the last used config to the INA219. 147 | * `recalibrate()` rewrites the calibration registers as they were calculated by `calibrate()` function. 148 | * `ready()` returns the value of the ready bit. It's value is updated according to the last call to `busVoltageRaw()` or `busVoltage()`. 149 | 150 | based on the datasheet page 30: 151 | Although the data from the last conversion can be read at any time, 152 | the INA219 Conversion Ready bit (CNVR) indicates when data from 153 | a conversion is available in the data output registers. 154 | The CNVR bit is set after all conversions, averaging, 155 | and multiplications are complete. 156 | CNVR will clear under the following conditions: 157 | 1.) Writing a new mode into the Operating Mode bits in the 158 | Configuration Register (except for Power-Down or Disable) 159 | 2.) Reading the Power Register 160 | 161 | page 15: 162 | The Conversion Ready bit clears under these 163 | conditions: 164 | 1. Writing to the Configuration Register, except 165 | when configuring the MODE bits for Power Down 166 | or ADC off (Disable) modes; 167 | 2. Reading the Status Register; 168 | 3. Triggering a single-shot conversion with the 169 | Convert pin. 170 | * `overflow()` returns the value of the overflow bit. It's value is updated according to the last call to `busVoltageRaw()` or `busVoltage()`. 171 | * `reset()` : Resets the INA219. 172 | * `shuntVoltageRaw()` : Returns the raw binary value of the shunt voltage 173 | * `busVoltageRaw()` : Returns raw bus voltage binary value. 174 | * `shuntCurrentRaw()` : Returns raw bus voltage binary value. 175 | * `shuntVoltage()` : Returns the shunt voltage in volts. 176 | * `busVoltage()` : Returns the bus voltage in volts. 177 | * `shuntCurrent()` : Returns the shunt current in amps. 178 | * `busPower()` : Returns the bus power in watts 179 | 180 | # Licence 181 | MIT license 182 | -------------------------------------------------------------------------------- /INA219.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * TI INA219 hi-side i2c current/power monitor Library 3 | * 4 | * http://www.ti.com/product/ina219 5 | * 6 | * 6 May 2012 by John De Cristofaro 7 | * 8 | * 9 | * Tested at standard i2c 100kbps signaling rate. 10 | * 11 | * This library does not handle triggered conversion modes. It uses the INA219 12 | * in continuous conversion mode. All reads are from continous conversions. 13 | * 14 | * A note about the gain (PGA) setting: 15 | * The gain of the ADC pre-amplifier is programmable in the INA219, and can 16 | * be set between 1/8x (default) and unity. This allows a shunt voltage 17 | * range of +/-320mV to +/-40mV respectively. Something to keep in mind, 18 | * however, is that this change in gain DOES NOT affect the resolution 19 | * of the ADC, which is fixed at 1uV. What it does do is increase noise 20 | * immunity by exploiting the integrative nature of the delta-sigma ADC. 21 | * For the best possible reading, you should set the gain to the range 22 | * of voltages that you expect to see in your particular circuit. See 23 | * page 15 in the datasheet for more info about the PGA. 24 | * 25 | * Known bugs: 26 | * * may return unreliable values if not connected to a bus or at 27 | * bus currents below 10uA. 28 | * 29 | * Arduino 1.0 compatible as of 6/6/2012 30 | * 31 | * Dependencies: 32 | * * Arduino Wire library 33 | * 34 | * MIT license 35 | ******************************************************************************/ 36 | 37 | #ifndef ina219_h 38 | #define ina219_h 39 | 40 | 41 | #if ARDUINO >= 100 42 | #include "Arduino.h" 43 | #else 44 | #include "WProgram.h" 45 | #endif 46 | 47 | #include 48 | 49 | // Uncomment to add some debug output 50 | //#define INA219_DEBUG 51 | 52 | // default values 53 | 54 | #define D_SHUNT 0.1 55 | #define D_V_BUS_MAX 32 56 | #define D_V_SHUNT_MAX 0.2 57 | #define D_I_MAX_EXPECTED 2 58 | 59 | 60 | class INA219 61 | { 62 | public: 63 | 64 | ///I2C address definations. 65 | /// Adafruit breakout board have two jumppers to set unique 66 | /// address for each board ( in case there is more than one in Your system) 67 | /// base address is 0x40, no jumpers needed) 68 | enum t_i2caddr{ 69 | I2C_ADDR_40 = 0x40, ///< address 0x40 no jumpers required. 70 | I2C_ADDR_41 = 0x41, ///< address 0x41 bridge A0. 71 | I2C_ADDR_44 = 0x44, ///< address 0x44 bridge A1. 72 | I2C_ADDR_45 = 0x45 ///< address 0x45 bridge A0 & A1. 73 | 74 | }; 75 | 76 | ///Sets PGA gain and range. Note that the PGA defaults to be divided by 8 (320mV range). 77 | ///Configuration reister bits 11, 12 are used for this. 78 | enum t_gain{ 79 | GAIN_1_40MV = 0, 80 | GAIN_2_80MV = 1, 81 | GAIN_4_160MV = 2, 82 | GAIN_8_320MV = 3 83 | }; 84 | 85 | ///Bus voltage range. 86 | ///Configuration register bit 13 defines this. 87 | enum t_range{ 88 | RANGE_16V = 0, ///< Range 0-16 volts 89 | RANGE_32V = 1 ///< Range 0-32 volts 90 | }; 91 | 92 | ///ADC resolution (9-, 10-, 11-, or 12-bit) or set the number of samples. 93 | ///Same definations are used both shunt and bus adc. 94 | ///Configuration register bits 3 to 6 are used for averaging results for the Shunt Voltage Register (01h). 95 | ///And bits 7-10 are used averaging results for the Bus Voltage Register (02h). 96 | /// \see t_reg 97 | enum t_adc{ 98 | ADC_9BIT = 0, ///< 9bit converion time 84us. 99 | ADC_10BIT = 1, ///< 10bit converion time 148us. 100 | ADC_11BIT = 2, ///< 11bit converion time 2766us. 101 | ADC_12BIT = 3, ///< 12bit converion time 532us. 102 | ADC_2SAMP = 9, ///< 2 samples converion time 1.06ms. 103 | ADC_4SAMP = 10, ///< 4 samples converion time 2.13ms. 104 | ADC_8SAMP = 11, ///< 8 samples converion time 4.26ms. 105 | ADC_16SAMP = 12, ///< 16 samples converion time 8.51ms 106 | ADC_32SAMP = 13, ///< 32 samples converion time 17.02ms. 107 | ADC_64SAMP = 14, ///< 64 samples converion time 34.05ms. 108 | ADC_128SAMP = 15, ///< 128 samples converion time 68.10ms. 109 | }; 110 | 111 | ///Selects continuous, triggered, or power-down mode of operation. These bits default to continuous shunt and bus measurement mode. 112 | ///\n Please note: Thus library does not support triggered converion I have comment out values to set trigged mode.\n 113 | ///Configuration register bits 0-2 are used for this. \see t_reg 114 | enum t_mode{ 115 | PWR_DOWN = 0, 116 | /* 117 | TRIG_SH = 1, 118 | TRIG_BUS = 2, 119 | TRIG_SH_BUS = 3, 120 | */ 121 | ADC_OFF = 4, 122 | CONT_SH = 5, /// 45 | #endif 46 | 47 | namespace{ 48 | // config. register bit labels 49 | const uint8_t RST = 15; 50 | const uint8_t BRNG = 13; 51 | const uint8_t PG_1 = 12; 52 | const uint8_t PG_0 = 11; 53 | const uint8_t BADC4 = 10; 54 | const uint8_t BADC3 = 9; 55 | const uint8_t BADC2 = 8; 56 | const uint8_t BADC1 = 7; 57 | const uint8_t SADC4 = 6; 58 | const uint8_t SADC3 = 5; 59 | const uint8_t SADC2 = 4; 60 | const uint8_t SADC1 = 3; 61 | const uint8_t MODE3 = 2; 62 | const uint8_t MODE2 = 1; 63 | const uint8_t MODE1 = 0; 64 | }; 65 | 66 | #define CNVR_B 1 // conversion ready bit in bus voltage register V_BUS_R 67 | #define OVF_B 0 // math overflow bit in bus voltage register V_BUS_R 68 | 69 | INA219::INA219(t_i2caddr addr): i2c_address(addr) { 70 | } 71 | 72 | uint8_t INA219::begin() { 73 | uint8_t ret; 74 | Wire.begin(); 75 | ret = reset(); 76 | if (ret) 77 | return ret; // Likely failed to address/find the device 78 | configure(); 79 | calibrate(); 80 | 81 | return ret; 82 | } 83 | 84 | void INA219::calibrate(float shunt_val, float v_shunt_max, float v_bus_max, float i_max_expected) { 85 | uint16_t digits; 86 | float min_lsb, swap; 87 | #ifdef INA219_DEBUG 88 | float max_current,max_before_overflow,max_shunt_v,max_shunt_v_before_overflow,max_power,i_max_possible,max_lsb; 89 | #endif 90 | 91 | r_shunt = shunt_val; 92 | 93 | min_lsb = i_max_expected / 32767; 94 | 95 | current_lsb = min_lsb; 96 | digits=0; 97 | 98 | /* From datasheet: This value was selected to be a round number near the Minimum_LSB. 99 | * This selection allows for good resolution with a rounded LSB. 100 | * eg. 0.000610 -> 0.000700 101 | */ 102 | while( current_lsb > 0.0 ){//If zero there is something weird... 103 | if( (uint16_t)current_lsb / 1){ 104 | current_lsb = (uint16_t) current_lsb + 1; 105 | current_lsb /= pow(10,digits); 106 | break; 107 | } 108 | else{ 109 | digits++; 110 | current_lsb *= 10.0; 111 | } 112 | }; 113 | 114 | swap = (0.04096)/(current_lsb*r_shunt); 115 | cal = (uint16_t)swap; 116 | power_lsb = current_lsb * 20; 117 | 118 | #ifdef INA219_DEBUG 119 | i_max_possible = v_shunt_max / r_shunt; 120 | max_lsb = i_max_expected / 4096; 121 | max_current = current_lsb*32767; 122 | max_before_overflow = max_current > i_max_possible?i_max_possible:max_current; 123 | 124 | max_shunt_v = max_before_overflow*r_shunt; 125 | max_shunt_v_before_overflow = max_shunt_v > v_shunt_max?v_shunt_max:max_shunt_v; 126 | 127 | max_power = v_bus_max * max_before_overflow; 128 | Serial.print("v_bus_max: "); Serial.println(v_bus_max, 8); 129 | Serial.print("v_shunt_max: "); Serial.println(v_shunt_max, 8); 130 | Serial.print("i_max_possible: "); Serial.println(i_max_possible, 8); 131 | Serial.print("i_max_expected: "); Serial.println(i_max_expected, 8); 132 | Serial.print("min_lsb: "); Serial.println(min_lsb, 12); 133 | Serial.print("max_lsb: "); Serial.println(max_lsb, 12); 134 | Serial.print("current_lsb: "); Serial.println(current_lsb, 12); 135 | Serial.print("power_lsb: "); Serial.println(power_lsb, 8); 136 | Serial.println(" "); 137 | Serial.print("cal: "); Serial.println(cal); 138 | Serial.print("r_shunt: "); Serial.println(r_shunt, 6); 139 | Serial.print("max_before_overflow: "); Serial.println(max_before_overflow,8); 140 | Serial.print("max_shunt_v_before_overflow: "); Serial.println(max_shunt_v_before_overflow,8); 141 | Serial.print("max_power: "); Serial.println(max_power,8); 142 | Serial.println(" "); 143 | #endif 144 | write16(CAL_R, cal); 145 | } 146 | 147 | void INA219::configure( t_range range, t_gain gain, t_adc bus_adc, t_adc shunt_adc, t_mode mode) { 148 | config = 0; 149 | 150 | config |= (range << BRNG | gain << PG_0 | bus_adc << BADC1 | shunt_adc << SADC1 | mode); 151 | #ifdef INA219_DEBUG 152 | Serial.print("Config: 0x"); Serial.println(config,HEX); 153 | #endif 154 | write16(CONFIG_R, config); 155 | } 156 | 157 | #define INA_RESET 0xFFFF // send to CONFIG_R to reset unit 158 | // Returns non-zero if unable to reset. 159 | // This is likely due to device not being functional/installed on I2C bus 160 | // Returned error values are defined in the Wire libraries. 161 | // Values of 2 indicates the address wasn't on the bus (NAK response) 162 | uint8_t INA219::reset(){ 163 | uint8_t ret = write16(CONFIG_R, INA_RESET); 164 | _delay_ms(5); 165 | return ret; 166 | } 167 | 168 | int16_t INA219::shuntVoltageRaw() const { 169 | return read16(V_SHUNT_R); 170 | } 171 | 172 | float INA219::shuntVoltage() const { 173 | float temp; 174 | temp = read16(V_SHUNT_R); 175 | return (temp / 100000); 176 | } 177 | 178 | uint16_t INA219::busVoltageRaw() { 179 | uint16_t bus_voltage_register = read16(V_BUS_R); 180 | _overflow = bitRead(bus_voltage_register, OVF_B); // overflow bit 181 | _ready = bitRead(bus_voltage_register, CNVR_B); // ready bit 182 | return bus_voltage_register; 183 | } 184 | 185 | 186 | float INA219::busVoltage() { 187 | uint16_t temp; 188 | temp = busVoltageRaw(); 189 | temp >>= 3; 190 | return (temp * 0.004); 191 | } 192 | 193 | int16_t INA219::shuntCurrentRaw() const { 194 | return (read16(I_SHUNT_R)); 195 | } 196 | 197 | float INA219::shuntCurrent() const { 198 | return (read16(I_SHUNT_R) * current_lsb); 199 | } 200 | 201 | float INA219::busPower() const { 202 | return (read16(P_BUS_R) * power_lsb); 203 | } 204 | 205 | /**************************************************************************/ 206 | /*! 207 | @brief Rewrites the last config register 208 | */ 209 | /**************************************************************************/ 210 | void INA219::reconfig() const { 211 | #ifdef INA219_DEBUG 212 | Serial.print("Reconfigure with Config: 0x"); Serial.println(config,HEX); 213 | #endif 214 | write16(CONFIG_R, config); 215 | } 216 | 217 | /**************************************************************************/ 218 | /*! 219 | @brief Rewrites the last calibration 220 | */ 221 | /**************************************************************************/ 222 | void INA219::recalibrate() const { 223 | #ifdef INA219_DEBUG 224 | Serial.print("Recalibrate with cal: "); Serial.println(cal); 225 | #endif 226 | write16(CAL_R, cal); 227 | } 228 | 229 | /**************************************************************************/ 230 | /*! 231 | @brief returns conversion ready bite from last bus voltage read 232 | 233 | @note page 30: 234 | Although the data from the last conversion can be read at any time, 235 | the INA219 Conversion Ready bit (CNVR) indicates when data from 236 | a conversion is available in the data output registers. 237 | The CNVR bit is set after all conversions, averaging, 238 | and multiplications are complete. 239 | CNVR will clear under the following conditions: 240 | 1.) Writing a new mode into the Operating Mode bits in the 241 | Configuration Register (except for Power-Down or Disable) 242 | 2.) Reading the Power Register 243 | 244 | page 15: 245 | The Conversion Ready bit clears under these 246 | conditions: 247 | 1. Writing to the Configuration Register, except 248 | when configuring the MODE bits for Power Down 249 | or ADC off (Disable) modes; 250 | 2. Reading the Status Register; 251 | 3. Triggering a single-shot conversion with the 252 | Convert pin. 253 | */ 254 | /**************************************************************************/ 255 | bool INA219::ready() const { 256 | return _ready; 257 | } 258 | 259 | /**************************************************************************/ 260 | /*! 261 | @brief returns overflow bite from last bus voltage read 262 | 263 | @note The Math Overflow Flag (OVF) is set when the Power or 264 | Current calculations are out of range. It indicates that 265 | current and power data may be meaningless. 266 | */ 267 | /**************************************************************************/ 268 | bool INA219::overflow() const { 269 | return _overflow; 270 | } 271 | 272 | /********************************************************************** 273 | * INTERNAL I2C FUNCTIONS * 274 | **********************************************************************/ 275 | 276 | // write16 returns a non-zero value in the case of a transmission error. 277 | uint8_t INA219::write16(t_reg a, uint16_t d, bool stop) const { 278 | uint8_t temp; 279 | temp = (uint8_t)d; 280 | d >>= 8; 281 | Wire.beginTransmission(i2c_address); // start transmission to device 282 | 283 | #if ARDUINO >= 100 284 | Wire.write(a); // sends register address to read from 285 | Wire.write((uint8_t)d); // write data hibyte 286 | Wire.write(temp); // write data lobyte; 287 | #else 288 | Wire.send(a); // sends register address to read from 289 | Wire.send((uint8_t)d); // write data hibyte 290 | Wire.send(temp); // write data lobyte; 291 | #endif 292 | 293 | temp = Wire.endTransmission(stop); // end transmission 294 | _delay_ms(1); 295 | return temp; 296 | } 297 | 298 | int16_t INA219::read16(t_reg a) const { 299 | uint16_t ret; 300 | 301 | // move the pointer to reg. of interest, null argument 302 | write16(a, 0, false); 303 | 304 | Wire.requestFrom((int)i2c_address, 2); // request 2 data bytes 305 | 306 | #if ARDUINO >= 100 307 | ret = Wire.read(); // rx hi byte 308 | ret <<= 8; 309 | ret |= Wire.read(); // rx lo byte 310 | #else 311 | ret = Wire.receive(); // rx hi byte 312 | ret <<= 8; 313 | ret |= Wire.receive(); // rx lo byte 314 | #endif 315 | 316 | return ret; 317 | } 318 | --------------------------------------------------------------------------------