Adafruit INA219 issue: wrong value returned

With a correctly working ina219 module and using the example program by Adafruit (getcurrent.ino) I get correct current values returned (in my case: 0mA).

When using my own program, using the same module, and with correct I2C connections, the returned current value = 65535.

This is when both programs are using the same hardware setup (I2C connections SDA & SCL, working ina219 module, same power supply connections, ..).

Ultimately I cannot see the forrest through the trees anymore, so I turn to this forum.

In my program I use currentValue to store the current value (mA) retrieved from the ina219.

Any help, suggestions, comments, .. will be greatly appreciated.

The output of

    Serial.print(F("currentValue = "));
    Serial.print(currentValue);
    Serial.print(F("  cumul = "));
    Serial.print(cumul);
    Serial.print(F("  cum.volt. = "));
    Serial.print(cumulVoltage);
    Serial.print(F("  cum.amp. = "));
    Serial.print(cumulCurrent);
    Serial.print(F("  volt.Disp. = "));
    Serial.print(voltageDisplay);
    Serial.print(F("  amp.Disp. = "));
    Serial.println(currentDisplay);

is

currentValue = 65535  cumul = 20  cum.volt. = 0  cum.amp. = 13041465  volt.Disp. = 0.00  amp.Disp. = 65.21

Current through the ina219 = 0mA.

My program:

#include <Wire.h>
#include <LCD.h> // will force using NewLiquidCrystal library
#include <LiquidCrystal_I2C.h>
#include <Adafruit_INA219.h>
Adafruit_INA219 ina219; //declare an instance of INA219
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// const int RELAIS = 10;
#define RELAIS 10 // PB2 set relais/LED output on pin 10 overtemp detection
#define BEEP 11   // PB3 set piezo beep output on pin 11 (PWM pin)
#define fan 9     // PB1 ventilator output pin
unsigned long now1 = millis(); // temperature measurement interval time
unsigned long now2 = millis(); // voltage and current measurement interval time
unsigned long interval;
const word interval1 = 1000;  // delay time in milliseconds, temperature measuerements
const word interval2 = 500; // delay time in milliseconds, voltage and current measurements
const word interval3 = 750; // delay time in milliseconds, LCD refresh
byte T1 = 70; // max normal operating temperature darlington & heatsink
const byte T1a = T1 - 2;  // hysteresis set variable high temperature low end at -2C
const byte T1b = T1; // hysteresis reset
const byte T2 = 85; // overtemperature darlington or heatsink
const byte T3 = 65; // kick-in temp for fan, fanspeed = 25%
const byte T4 = 85; // temp for max fan speed
const byte T5 = 5; // hysteresis value, used to substract from kick-in temperature
byte fanValue; // output value to cooling fan
int T6; // intermediate temp value for fan speed usage
const byte fanMin = 125; // minimum fan speed
const byte fanMax = 254; // maximum fanspeed
const byte v1 = 2; // max voltage when short circuit occurs
const byte C1 = 2; // min current (A) when short circuit occurs
const int displaydelay = 500; // display update delay in millis
boolean OC = false; // overcurrent status
boolean warning; // warning status (temperature and/or current)
const byte x = 8; // number of loops to remove a pos and a neg maximum = x+2
const byte cumul = 20; // number of repeats for x+2 loops
boolean message1;
boolean message2;
float voltageDisplay;
float currentDisplay;
unsigned int temp1Value; // temp1 darlington
unsigned int temp2Value; // temp2 heatsink
unsigned int voltageValue; // spanning
unsigned int currentValue; // stroom
unsigned long cumulVoltage;
unsigned long cumulCurrent;


void setup()
{
  Serial.begin(9600);
  delay(5);
  Serial.println(__FILE__);
  Serial.println("Arduino_LCD_voltage_current_ina219_v11.ino");
  analogReference(EXTERNAL);  // externe referntiespanning: 5,000 V
  if (! ina219.begin()) {
    Serial.println("Failed to find INA219 chip");
    while (1) {
      delay(10);
    }
  }  lcd.begin(16, 2);
  pinMode (RELAIS, OUTPUT);
  pinMode (BEEP, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(fan, OUTPUT); //set fan as ventilator output
  digitalWrite(RELAIS, LOW);
  lcd.backlight();
  lcd.setBacklight(HIGH);
  //initialise display on startup
  lcd.home (); // go home on LCD
  lcd.print(F("    Labo PSU"));
  digitalWrite(LED_BUILTIN, HIGH);
  delay(100);
  lcd.setCursor (0, 1);
  lcd.print(F("    Erik /V10a    "));
  digitalWrite(LED_BUILTIN, LOW);
  delay(10);
  for (int i = 0; i < 4; i++)
  {
    lcd.noBacklight();
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    lcd.backlight();
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);
  }
  lcd.clear();
}

void printToLCD(float value1, byte width, byte dp)  // print to LCD: value, number of digits, number of digits after comma
{
  char out[10];
  dtostrf(value1, width, dp, out);
  lcd.print(out);
}

void printToLcdLine2Reset(float value2, unsigned int value3)
{
  // digitalWrite(BEEP, LOW);
  digitalWrite(LED_BUILTIN, LOW);
  lcd.print(F("I="));
  printToLCD(value2, 5, 2);
  lcd.print(F("A T2="));
  printToLCD(value3, 3, 0); // heatsink temp on line 2
  lcd.print(F("C"));
}

void loop()
{
  //initialise variables and reset loop totals to 0
  unsigned long temp1Total = 0; // temp1 darlington cumulated
  unsigned long temp2Total = 0; // temp2 heatsink cumulated
  unsigned long voltageTotal = 0; // voltage values cumulated
  unsigned long currentTotal = 0; // current values cumulated
  unsigned int signalMax0 = 0; // max value from analog 0 (temp1Value)
  unsigned int signalMin0 = 65000; // min value from analog 0, temp1 Darlington
  unsigned int signalMax1 = 0; // max value from analog 1 (temp2Value)
  unsigned int signalMin1 = 65000; // min value from analog 1, temp2 heatsink
  unsigned int signalMax2 = 0; // max value from analog 2 (voltageValue)
  unsigned int signalMin2 = 65000; // min value from analog 2, output voltage
  unsigned int signalMax3 = 0; // max value from INA219 (currentValue)
  unsigned int signalMin3 = 100000; // min value from INA219, output current
  bool fanOn = false;

  /**********************************************************************/
  // test for overtemperatures, elke 1 seconde
  /**********************************************************************/

  if (millis() - now1 >= interval1) // execute every interval1 milliseconds (1000)
  {
    for (int j1 = 0; j1 < (x + 2); j1++)   // read values x+2 times, and deduct min. and max, the divide by x
    {
      //read values from analog inputs and accumulate
      temp1Value = (analogRead(0) * 50000 / 1023); // darlington temp read m°C LM35 = 10mV/°C, 5V = 500000 m°C, temp1Value = integer = actual temperature * 100 = unsigned int
      delayMicroseconds(10);
      temp1Value = (analogRead(0) * 50000 / 1023); // repeat
      delayMicroseconds(10);
      temp2Value = (analogRead(1) * 50000 / 1023); // heatsink temp read m°C LM35 = 10mV/°C, 5V = 500000 m°C, temp1Value = integer = actual temperature * 100 = unsigned int
      delayMicroseconds(10);
      temp2Value = (analogRead(1) * 50000 / 1023); // repeat
      delayMicroseconds(10);
      if (temp1Value < signalMin0)signalMin0 = temp1Value;
      if (temp1Value > signalMax0)signalMax0 = temp1Value;
      if (temp2Value < signalMin1)signalMin1 = temp2Value;
      if (temp2Value > signalMax1)signalMax1 = temp2Value;
      temp1Total += temp1Value; // temp1 darlington accum m°C*(x+2)
      temp2Total += temp2Value; // temp2 cooling fins accum m°C*(x+2)
    }

    // remove minimum and maximum outliers
    temp1Total -= signalMin0; // Darlington temp m°C
    temp1Total -= signalMax0;
    temp2Total -= signalMin1; // heatsink temp m°C
    temp2Total -= signalMax1;

    // calculate average temperatures, voltage and current
    temp1Value = temp1Total / x / 100; // temp darlington °C
    temp2Value = temp2Total / x / 100; // temp heatsink °C

    /**********************************************************************/
    // fan cooling ventilator control section, output on pin 9
    /**********************************************************************/
    if (temp1Value > T4) //then it's already at max speed...
    {
      T6 = 100;
    }
    if (temp1Value > T3) // min temp1Value for fan kick-in
    {
      fanOn = true;
      T6 = temp1Value;
    }
    else if (temp1Value < (T3 - T5)) // min temp1Value - hysteresis for fan kick-out
    {
      fanOn = false;
      analogWrite(fan, 0);
    }
    if (fanOn)
    { // calculate fanspeed if temp1Value > T3
      if (temp1Value > T3)
      {
        T6 = temp1Value;
        fanValue = map(T6, T3, T4, fanMin, fanMax);
        analogWrite(fan, fanValue);
      }
      else {
        analogWrite(fan, fanMin);    // fanspeed if T3 - T5 < temp1Value < T3
      }
    }

    /**********************************************************************/
    // test for overtemp conditions without overcurrent
    /**********************************************************************/
    if ((temp1Value >= T1 && temp1Value < T2 && OC == false) || (temp2Value >= T1 && temp2Value < T2 && OC == false))  // warning high temp darlington or heatsink, no shortcircuit
    {
      Serial.println(F("  high temp conditions"));
      Serial.print(F("  darl = "));
      Serial.print(temp1Value);
      Serial.print(F("  HS. = "));
      Serial.println(temp2Value);

      T1 = T1a; // hysteresis set to value 0°C: T2
      warning = true;
      lcd.setCursor (0, 1); // go to start of 2nd line

      if (message1 == true)   // alarm, after second passage after interval3, print to LCD second line
      {
        message1 = false;
        interval = interval1;     // faster interval
        lcd.print(F("HIGH TEMP WARN!!"));
        digitalWrite(LED_BUILTIN, HIGH);
      }
      else                    // alarm reset, or first passage after high temp detect, print to LCD second line
      {
        message1 = true;
        interval = interval3;     // LCD regular refresh
        printToLcdLine2Reset(currentDisplay, temp2Value);
      }
    }

    // alarm overtemperature darlington or heatsink, no shortcircuit
    if ((temp1Value >= T2 && OC == false) || (temp2Value >= T2 && OC == false))
    {
      // T2b = T2a; // hysteresis st -2°C
      lcd.setCursor (0, 1); // go to start of 2nd line
      warning = true;
      digitalWrite(RELAIS, HIGH);         // overtemperature, relay opens
      lcd.setCursor (0, 1); // go to start of 2nd line

      if (message2 == true)   // alarm, after second passage after interval3
      {
        message2 = false;
        interval = interval2;     // faster interval
        lcd.print(F("OVERTEMP WARNING"));
        digitalWrite(LED_BUILTIN, HIGH);
        digitalWrite(RELAIS, HIGH);         // overtemperature, relay opens
        tone(BEEP, 4000);        // overtemperature, beep sounds
      }
      else                    // alarm reset, or first passage after high temp detect
      {
        message2 = true;
        interval = interval3;     // LCD regular refresh
        noTone(BEEP);  // turn off buzzer
        printToLcdLine2Reset(currentDisplay, temp2Value);
        Serial.println(F("  alarm reset"));
        Serial.print(F("  currentDisplay = "));
        Serial.println(currentDisplay);
      }
    }
    now1 = millis();
  }

  /**********************************************************************/
  // voltage and current measurements every 500ms
  /**********************************************************************/

  if (millis() - now2 >= interval2)
  {
    // repeat 'cumul' times current and voltage minus outliers and accumulate voltage and current values
    for (int j2 = 0; j2 < cumul; j2++)
    {
      // read x+2 times values from analog inputs and accumulate
      for (int j1 = 0; j1 < (x + 2); j1++)   // read values x+2 times, and deduct min. and max, the divide by x
      {
        currentValue = ina219.getCurrent_mA(); //mA, unsigned int
        voltageValue = (analogRead(2) * 45000 / 1023); // mV // actual voltage * 1000, unsigned int
        delayMicroseconds(10);
        voltageValue = (analogRead(2) * 45000 / 1023); // repeat
        delayMicroseconds(10);
        if (voltageValue < signalMin2)signalMin2 = voltageValue;  // voltage in mV
        if (voltageValue > signalMax2)signalMax2 = voltageValue;
        // if (currentValue < signalMin3)signalMin3 = currentValue;
        // if (currentValue > signalMax3)signalMax3 = currentValue;
        voltageTotal += voltageValue; // spanning mV*(x+2), unsigned long
        currentTotal += currentValue; // stroom mA*(x+2)
      }

      // Subtract minimum and maximum outliers from totalled voltage values
      voltageTotal -= signalMin2; // output voltage in mV
      voltageTotal -= signalMax2;
      // currentTotal -= signalMin3; // measured mA current
      // currentTotal -= signalMax3;

      cumulVoltage += voltageTotal; // cumulated voltage ('cumul' times) over x measurements, in mV
      cumulCurrent += currentTotal; // cumulated current ('cumul' times) over x+2 measurements, in mA
      voltageTotal = 0; // reset
      currentTotal = 0; // reset
    }
    float voltageDisplay = cumulVoltage / cumul / 1000.0 / x; // average voltage measurement over 'cumul' times measurement during (x+2 times minus mi and max outliers)
    float currentDisplay = cumulCurrent / cumul / 1000.0 / (x+2); // average current measurement
    Serial.print(F("currentValue = "));
    Serial.print(currentValue);
    Serial.print(F("  cumul = "));
    Serial.print(cumul);
    Serial.print(F("  cum.volt. = "));
    Serial.print(cumulVoltage);
    Serial.print(F("  cum.amp. = "));
    Serial.print(cumulCurrent);
    Serial.print(F("  volt.Disp. = "));
    Serial.print(voltageDisplay);
    Serial.print(F("  amp.Disp. = "));
    Serial.println(currentDisplay);
    cumulVoltage = 0;
    cumulCurrent = 0;

    /**********************************************************************/
    // test conditions for overcurrent warnings
    /**********************************************************************/

    // shortcircuit where v1 = c1 = 2
    if (voltageValue <= v1 && currentDisplay >= C1) // shortcircuit where v1 = c1 = 2
    {
      OC = true;
      lcd.setCursor (0, 1);
      lcd.print(F("kortsluiting    "));
      digitalWrite(LED_BUILTIN, HIGH);
    }
    else                                 // no shortcircuit, warning reset
    {
      OC = false;
      if (warning == false)
      {
      }
    }

    /**********************************************************************/
    // LCD print line 0: voltage and  temp1 (Darlington) value
    /**********************************************************************/

    lcd.home ();
    lcd.print(F("U="));
    printToLCD(voltageDisplay, 5, 2);
    lcd.print(F("V T1="));
    printToLCD(temp1Value, 3, 0); // Darlington temp on line 0
    lcd.print(F("C"));
    lcd.setCursor (0, 1); // go to start of 2nd line

    if (warning == false && OC == false)    // when alarm is reset, re-display regular values on line 1 (second line)
    {
      printToLcdLine2Reset(currentDisplay, temp2Value);  // current value and heatsink temperature

      Serial.println(F("  regular current display"));
      Serial.print(F("  currentDisplay = "));
      Serial.println(currentDisplay);
    }
    now2 = millis();
  }

  /**********************************************************************/
  // temperatures back to normal, no short circuit, protection relay and beep reset
  /**********************************************************************/

  if (temp1Value < T1 && temp2Value < T1 && OC == false)
  {
    lcd.setCursor (0, 1);
    noTone(BEEP);  // reset buzzer, turn off buzzer
    digitalWrite(RELAIS, LOW);
    digitalWrite(LED_BUILTIN, LOW);
    warning = false;
    T1 = T1b; // reset T1 hysteresis to 0°C
  }
}

Your currentValue variable is of type unsigned int, whereas the getCurrent_mA() function returns a type float value. I would guess that something weird might be happening with the conversion. Both unsigned long and float are 32-bit values so why not try it with currentValue and currentTotal defined as float.

Try compiling with compiler warnings set to All instead of Default in preferences. Do you get any warnings for that line?

I changed currrentValue and cumulCurrent to float (not sure if the latter one needs to be changed from unsigned long) and it is soilved, thank you @BitSeeker

I was under the assumption that an integer divided by a float results in a float? But upon closer look at the Adafruit getcurrent.ino example I see that they too assign a float to the variable getting the current from ina219.getCurrent_ma()

I need to take a closer look into the various variable types and their consequences.

I will look into that tomorrow and let you know.

Try printing temp1Value right after this. It may not be what you expect

Maybe, but the result was being stored in an unsigned int. In a float zero can be represented as +0 or -0 (OK, I know that sounds weird) but a negative representation when converted to an unsigned type will result in unexpected results due to the way that negative values are represented. A +0 will be represented as all zeroes, but a -0 might be represented as all ones, which if transferred directly to in an unsigned int would result in a truncated maximum value for that type.

Not 100% whether that was the case here, but the compiler often gives warnings for mathematical operations that involve a mix of signed and unsigned variables where the results might be unexpected. The default setting shows only the minimum of messages but setting to More or All will provide more detail. Warnings do not stop a compile from completing and can sometimes be ignored, but can also provide useful information.

With

unsigned int temp1Value
the output is '0' (with A0 shorted to ground).
With

float temp1Value
the output is 0.00

What is unexpected, @mancera1979 ?

With variables declarations as follows:

unsigned int temp1Value; // temp1 darlington
unsigned int temp2Value; // temp2 heatsink
unsigned int voltageValue; // spanning
unsigned int currentValue; // stroom
unsigned long cumulVoltage;
unsigned long cumulCurrent;

no compiler warnings (set to "All") were given except this one:

C:\Users\Erik\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\main.cpp: In function 'main':
C:\Users\Erik\Google Drive\documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp:119:10: warning: 'value' may be used uninitialized in this function [-Wmaybe-uninitialized]
   return value;
          ^
C:\Users\Erik\Google Drive\documents\Arduino\libraries\Adafruit_INA219\Adafruit_INA219.cpp:105:12: note: 'value' was declared here
   uint16_t value;
            ^

If your microcontroller uses 16-bit arithmetic to perform the multiplication, the result will be wrong.

Unless analog(0) is zero!

Try a test where A0 is not grounded. Tie it to 5V, for example.

@mancera1979 With all six variables assigned float, and A0 tied to 5V, serial output for temp1Value is 50000.
With all six variables assigned to float the serial output for temp1Value = 50000.00

Ok, so not very helpful this time then and the warning you did get is not even in your code. I guess that wasn't the best example to show how compiler messages can help then! :slight_smile:

Right, but your input did solve the issue for me, thanks! And thanks to all of you here for your helpfull comments!