I am using an INA219 current/power monitor to measure the output of a small PV panel under low-light conditions over a period of several days. The short-circuit current (from a multimeter) is never above a mA for the size of panel I am looking to test. The INA I am using is on an Adafruit breakout board, and I am controlling it using an I2C interface to a Particle Electron. I have been using the Adafruit code library available on the Particle IDE for my purposes, which works well for larger panels with a bigger output, but there is no function that will allow me to change the settings to make the desired measurements.
My primary question is: Is it possible to make the measurements required with reasonable precision (down to a uA if possible, but 5uA is acceptable) using the INA219?
If it is, I could do with some help with the implementation,
What I have done so far:
The library I have been using includes functions to change the input range of the INA, the options included are 32V/2A (default), 32V/1A, and 16V/400mA. I have tried adapting one of these functions to work for 100mV/1mA, the code for which I have included below. When testing it, I initially got better numbers (bigger, so implying that I had succeeded in changing the gain), but these no longer made any sense in context - as the output should be in mA, but the output readings were now much too big. I thought this was to do with the "ina219_currentdivider_mA" value which was then at 20, but changing it to a larger number returns to the original problem of the readings not registering such a small current (for some reason the output the library code gives is limited to two decimal places, I'm not sure why, if anyone could explain that as well I would be grateful).
For background, I have a basic grasp of C++ language and a theoretical understanding of things like I2C and bit-wise communication, but am not very well equipped for low-level programming of these things, can anyone point me to a good resource about them that would help me be a little less dependent on libraries?
void Adafruit_INA219::setCalibration_100mV_1mA(void)
{ //declare variables float VBUS_MAX; float VSHUNT_MAX; float RSHUNT; float MaxPossible_I; float MaxExpected_I; float MinimumLSB; float MaximumLSB; float CurrentLSB; uint32_t Cal; float PowerLSB; float Max_Current; float Max_Current_Before_Overflow; float Max_ShuntVoltage; float Max_ShuntVoltage_Before_Overflow; float MaximumPower; VBUS_MAX = 0.05; //in V VSHUNT_MAX = 0.1; //(Assumes Gain 1, 40mV) RSHUNT = 18; //(Resistor value in ohms) // 1. Determine max possible current MaxPossible_I = VSHUNT_MAX / RSHUNT; //0.005A = 5mA // 2. Determine max expected current MaxExpected_I = 0.001; //1mA // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit) MinimumLSB = MaxExpected_I/32767; //3.05 x 10^-8 = 0.03uA MaximumLSB = MaxExpected_I/4096; //2.44 x 10^-7 = 0.24uA // 4. Choose an LSB between the min and max values // (Preferrably a roundish number close to MinLSB) CurrentLSB = 0.00000004; //(0.04uA per bit) // 5. Compute the calibration register Cal = (String(0.04096 / (CurrentLSB * RSHUNT))).toFloat(); //This is a hotch-potched version of "trunc()" because the IDE was not compiling "trunc()" ina219_calValue = Cal; // 6. Calculate the power LSB PowerLSB = 20 * CurrentLSB; // 7. Compute the maximum current and shunt voltage values before overflow Max_Current = CurrentLSB * 32767; if(Max_Current > MaxPossible_I){ Max_Current_Before_Overflow = MaxPossible_I; } else { Max_Current_Before_Overflow = Max_Current; } Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT; if(Max_ShuntVoltage >= VSHUNT_MAX) { Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX; } else{ Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage; } Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX; // 8. Compute the Maximum Power MaximumPower = Max_Current_Before_Overflow * VBUS_MAX; // Set multipliers to convert raw current/power values ina219_currentDivider_mA = 33333; // Current LSB = 0.03uA per bit (1000/0.03 = ) ina219_powerDivider_mW = 1; // Power LSB = 1mW per bit // Set Calibration register to 'Cal' calculated above wireWriteRegister(INA219_REG_CALIBRATION, ina219_calValue); // Set Config register to take into account the settings above uint16_t config = INA219_CONFIG_BVOLTAGERANGE_16V | INA219_CONFIG_GAIN_1_40MV | INA219_CONFIG_BADCRES_12BIT | INA219_CONFIG_SADCRES_12BIT_1S_532US | INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; wireWriteRegister(INA219_REG_CONFIG, config); }
float Adafruit_INA219::getCurrent_mA() {
float valueDec = getCurrent_raw();
valueDec /= ina219_currentDivider_mA;
return valueDec;
}