INA226 Strom- und Leistungssensor

Über den Beitrag

Nachdem ich in meinem letzten Beitrag über den INA219 berichtet habe, möchte ich in diesem Beitrag den INA226 und meine zugehörige Bibliothek INA226_WE vorstellen.

In erster Näherung ist der INA226 ein INA219 mit Alarmfunktion, wodurch man ihn besonders gut zur Überwachung von Strömen verwenden kann. Darüber hinaus ist der INA226 sowohl auf der High-Side wie auf der Low-Side einsetzbar. Auf weitere Unterschied zum INA219 komme ich im Laufe des Beitrages zurück.

Zunächst gehe ich auf das Messprinzip und die technischen Daten ein. Danach stelle ich die Bibliothek mit ihren zahlreichen Beispielsketchen vor. Der letzte Teil schließlich ist für diejenigen, die tiefer einsteigen wollen. Er beschäftigt sich mit inneren Details des INA226 und der Bibliothek.

Das Messprinzip

Ein INA226 Modul
Ein INA226 Modul, Vor- und Rückseite

Im Prinzip funktioniert der INA226 genauso wie der INA219. Ihr leitet den zu messenden Strom über die Anschlüsse IN+ und IN- durch einen Shunt (Stromesswiderstand). Ein A/D-Wandler misst den Spannungsabfall über dem Shunt und daraus berechnet der INA226 den Strom.

Wenn ihr den blanken INA226 verwendet (der achtbeinige IC auf dem Modul), dann seid ihr frei in der Wahl der Größe des Shunts. Die Module haben Shunts von 0,1 Ohm. Jedenfalls gilt das für alle Modelle, die mit untergekommen sind.

Zusätzlich misst der INA226 die Busspannung, also den Spannungsabfall über dem Verbraucher. Das passiert zwischen den Anschlüssen VBUS und GND. Der INA219 hingegen misst die Busspannung zwischen IN- und GND. Deswegen müsst ihr den INA219 vor den Verbraucher setzen (High-Side). Beim INA226 seid ihr flexibler, ihr könnt ihn sowohl auf der High-Side wie auch auf der Low-Side einsetzen.

Aus dem Strom und dem Spannungsabfall über dem Verbraucher berechnet der INA226 die Leistung. Die ermittelten Messwerte legt er in seinen Datenregistern ab, von wo ihr sie per I2C abholen könnt.

INA226 in High-Side Konfiguration
INA226 in High-Side Konfiguration

Typische Schaltung

Typische INA226 Schaltung (wird für die Beispiele verwendet)
Typische INA226 Schaltung (wird für die Beispiele verwendet)

Die oben abgebildete (High-Side) Schaltung habe ich für alle Beispielsketche verwendet. Wichtig ist, dass der INA226 und der Verbraucher ein gemeinsames GND haben, sonst funktioniert die Messung der Busspannung nicht. Falls ihr IN+ und IN- untereinander vertauscht, erhaltet ihr negative Werte für die Shuntspannung und den Strom.

Einige technische Daten des INA226 Moduls

  • Busspannung: 0 – 36 Volt
  • maximaler Busstrom: 800 Milliampere
  • Versorgungsspannung: 3 – 5.5 Volt
  • Stromverbrauch (selbst ermittelt):
    • kontinuierlicher Modus: 0,35 mA
    • Power-Down Modus: 2,3 µA 
  • Messmodi: kontinuierlich („continuous“) oder on-Demand („triggered“);
  • Mittelwertbildung aus 1, 4, 64, 128, 256, 512 oder 1024 Einzelmessungen
  • A/D-Wandlungszeit in acht Stufen einstellbar: 0,14 bis 8,2 ms
  • Datenregister:
    • Shunt Spannung (shunt voltage register)
    • Bus Spannung (bus voltage register)
    • Strom (current register)
    • Leistung (power register)
  • Kommunikation über I2C, 4 Adressen einstellbar (Modulrückseite):
    • 0x40: A0, A1 offen
    • 0x41: A0 geschlossen, A1 offen
    • 0x44: A0 offen, A1 geschlossen
    • 0x45: A0, A1 geschlossen
  • programmierbarer Alarm Pin für Limitüberschreitungen und verfügbare Messwerte

Weitere technische Daten findet ihr im Datenblatt des Herstellers.

Die meisten INA226 Module besitzen den 0.1 Ω Shunt. Es gibt aber auch Modelle mit beispielsweise 0.01 oder 0.02 Ω. Mit dem 0.1 Ω Shunt liegt die maximale Stromstärke bei 0.819175 A. Wenn ihr das blanke Modul einsetzt, seid ihr entsprechend flexibler. Ich habe eine Funktion implementiert, mit der ihr einen anderen Widerstand einsetzen könnt.

Gebrauch der INA226 Bibliothek

Ihr könnt die Bibliothek INA226_WE hier von Github herunterladen oder auch direkt über die Arduino IDE Bibliotheksverwaltung installieren.

Ich habe insgesamt sieben Beispielsketche erstellt, anhand derer ich die Funktionen der Bibliothek vorstelle. Am intensivsten gehe ich auf das Beispiel für den kontinuierlichen Modus ein. Viele der Funktionen werden in allen Sketchen verwendet und müssen deshalb nur einmal erläutert werden. 

Beispiel 1: Kontinuierlicher (Continuous) Modus

Nachdem ihr die Bibliothek installiert und euren INA226 verdrahtet habt, ladet ihr den Sketch „Continous.ino“ hoch.

#include <Wire.h>
#include <INA226_WE.h>
#define I2C_ADDRESS 0x40

/* There are several ways to create your INA226 object:
 * INA226_WE ina226 = INA226_WE()              -> uses Wire / I2C Address = 0x40
 * INA226_WE ina226 = INA226_WE(ICM20948_ADDR) -> uses Wire / I2C_ADDRESS
 * INA226_WE ina226 = INA226_WE(&wire2)        -> uses the TwoWire object wire2 / I2C_ADDRESS
 * INA226_WE ina226 = INA226_WE(&wire2, I2C_ADDRESS) -> all together
 * Successfully tested with two I2C busses on an ESP32
 */
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ina226.init();

  /* Set Number of measurements for shunt and bus voltage which shall be averaged
  * Mode *     * Number of samples *
  AVERAGE_1            1 (default)
  AVERAGE_4            4
  AVERAGE_16          16
  AVERAGE_64          64
  AVERAGE_128        128
  AVERAGE_256        256
  AVERAGE_512        512
  AVERAGE_1024      1024
  */
  //ina226.setAverage(AVERAGE_16); // choose mode and uncomment for change of default

  /* Set conversion time in microseconds
     One set of shunt and bus voltage conversion will take: 
     number of samples to be averaged x conversion time x 2
     
     * Mode *         * conversion time *
     CONV_TIME_140          140 µs
     CONV_TIME_204          204 µs
     CONV_TIME_332          332 µs
     CONV_TIME_588          588 µs
     CONV_TIME_1100         1.1 ms (default)
     CONV_TIME_2116       2.116 ms
     CONV_TIME_4156       4.156 ms
     CONV_TIME_8244       8.244 ms  
  */
  //ina226.setConversionTime(CONV_TIME_1100); //choose conversion time and uncomment for change of default
  
  /* Set measure mode
  POWER_DOWN - INA226 switched off
  TRIGGERED  - measurement on demand
  CONTINUOUS  - continuous measurements (default)
  */
  //ina226.setMeasureMode(CONTINUOUS); // choose mode and uncomment for change of default
  
  /* If the current values delivered by the INA226 differ by a constant factor
     from values obtained with calibrated equipment you can define a correction factor.
     Correction factor = current delivered from calibrated equipment / current delivered by INA226
  */
  // ina226.setCorrectionFactor(0.95);
  
  Serial.println("INA226 Current Sensor Example Sketch - Continuous");
  
  ina226.waitUntilConversionCompleted(); //if you comment this line the first data might be zero
}

void loop() {
  float shuntVoltage_mV = 0.0;
  float loadVoltage_V = 0.0;
  float busVoltage_V = 0.0;
  float current_mA = 0.0;
  float power_mW = 0.0; 

  ina226.readAndClearFlags();
  shuntVoltage_mV = ina226.getShuntVoltage_mV();
  busVoltage_V = ina226.getBusVoltage_V();
  current_mA = ina226.getCurrent_mA();
  power_mW = ina226.getBusPower();
  loadVoltage_V  = busVoltage_V + (shuntVoltage_mV/1000);
  
  Serial.print("Shunt Voltage [mV]: "); Serial.println(shuntVoltage_mV);
  Serial.print("Bus Voltage [V]: "); Serial.println(busVoltage_V);
  Serial.print("Load Voltage [V]: "); Serial.println(loadVoltage_V);
  Serial.print("Current[mA]: "); Serial.println(current_mA);
  Serial.print("Bus Power [mW]: "); Serial.println(power_mW);
  if(!ina226.overflow){
    Serial.println("Values OK - no overflow");
  }
  else{
    Serial.println("Overflow! Choose higher current range");
  }
  Serial.println();
  
  delay(3000);
}

 

Parametereinstellung am Beispiel des kontinuierlichen Modus

INA226_WE ina226 = INA226_WE() erzeugt euer IN226 Objekt. Ihr könnt die I2C Adresse und / oder ein Wire Objekt übergeben. Letzteres erlaubt euch z.B. beide I2C Busse eines ESP32 zu nutzen. 

Die Funktion init() aktiviert den INA226 mit den Standardwerten. Um diese Grundeinstellungen zu ändern, könnt ihr im Setup an drei verschiedenen Schrauben drehen:

  1. Anzahl Einzelmessungen für die Shunt- und Busspannungskonversion mit setAverage() einstellen
    • 1, 4, 16, 64, 128, 256, 512 oder 1024 Einzelmessungen werden gemittelt
  2. Einstellung der A/D-Wandlungszeit für die Shunt- und Busspannung mit setConvTime()
    • 8 Stufen zwischen 140 µs und 8,244 ms einstellbar
    • zu beachten: ein Set aus Shunt- und Busspannung braucht die doppelte Zeit
  3. Messmodus über setMeasureMode() einstellen
    • CONTINUOUS – kontinuierliche Messung 
    • TRIGGERED – „auf Anfrage“: erkläre ich im nächsten Beispiel.
    • POWER_DOWN – schaltet den INA219 ab. Verwendet dazu aber besser die komfortablere powerDown() Funktion, welche weiter unten erläutert wird.
    • Der INA226 erlaubt es eigentlich auch, Shunt- oder Busspannungen zu ermitteln – das habe ich aber nicht implementiert. Bei mir gibt es die Messungen nur im Doppelpack.

Mit setCorrectionFactor() könnt ihr einen Korrekturfaktor einführen, falls die mit dem INA226 ermittelten Stromwerte von solchen abweichen sollten, die ihr zum Beispiel mit kalibrierten Messgeräten ermittelt habt. Der Faktor ist dabei der Quotient aus dem exakten und dem INA226 Wert. 

Weitere Funktionen des Beispiels

Die Datenregister des INA226 könnt ihr jederzeit abfragen. Sie enthalten den jeweils zuletzt gemessenen Wert. Vor der ersten abgeschlossenen Messung sind alle Werte Null. Mit waitUntilConversionCompleted() könnt ihr warten bis die aktuelle Messung abgeschlossen ist.

Mit readAndClearFlags() werden die Überlauf- und Alarmflags ausgelesen. In diesem Beispielsketch brauchen wir diesen Aufruf nur, um den Status der Variable overflow zu aktualisieren, die – wenn sie „true“ ist – den Überlauf eines Registers signalisiert.

Die Funktionen zum Auslesen der Datenregister, wie zum Beispiel getShuntVoltage_mV(), sollten selbsterklärend sein.

Berechnung der Messdauer

Die Dauer einer Messung ergibt sich aus:

Messdauer = Anzahl_{Messungen} (Averages) \cdot Conversion\  Time\cdot 2

Ausgabe

Und so sieht dann die Ausgabe des Sketches auf dem seriellen Monitor aus:

Ausgabe des Continuous Sketches
Ausgabe des Continuous Sketches

Beispiel 2: On-Demand (Triggered) Modus

Den Triggered Modus stellt ihr mit setMeasureMode(TRIGGERED) ein (Zeile 47 in Triggered.ino).  Jede Messung wird manuell mit startSingleMeasurement() gestartet (Zeile 74). Ich habe die Funktion so programmiert, dass sie automatisch wartet, bis die aktuellen Messwerte verfügbar sind. Ihr braucht waitUntilConversionCompleted() im Triggered Modus also nicht aufzurufen.

Ansonsten ist der Sketch identisch mit Continous.ino.

#include <Wire.h>
#include <INA226_WE.h>
#define I2C_ADDRESS 0x40

INA226_WE ina226(I2C_ADDRESS);
// INA226_WE ina226 = INA226_WE(); // Alternative: sets default address 0x40

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ina226.init();

  /* Set Number of measurements for shunt and bus voltage which shall be averaged
  * Mode *     * Number of samples *
  AVERAGE_1            1 (default)
  AVERAGE_4            4
  AVERAGE_16           8
  AVERAGE_64          64
  AVERAGE_128        128
  AVERAGE_256        256
  AVERAGE_512        512
  AVERAGE_1024      1024
  */
  //ina226.setAverage(AVERAGE_1); // choose mode and uncomment for change of default

  /* Set conversion time in microseconds
     One set of shunt and bus voltage conversion will take: 
     number of samples to be averaged x conversion time x 2
     
     * Mode *         * conversion time *
     CONV_TIME_140          140 µs
     CONV_TIME_204          204 µs
     CONV_TIME_332          332 µs
     CONV_TIME_588          588 µs
     CONV_TIME_1100         1.1 ms (default)
     CONV_TIME_2116       2.116 ms
     CONV_TIME_4156       4.156 ms
     CONV_TIME_8244       8.244 ms  
  */
  //ina226.setConversionTime(CONV_TIME_1100); //choose conversion time and uncomment for change of default
  
  /* Set measure mode
  POWER_DOWN - INA219 switched off
  TRIGGERED  - measurement on demand
  CONTINUOUS  - Continuous measurements (default)
  */
  ina226.setMeasureMode(TRIGGERED); // choose mode and uncomment for change of default
  
  /* If the current values delivered by the INA226 differ by a constant factor
     from values obtained with calibrated equipment you can define a correction factor.
     Correction factor = current delivered from calibrated equipment / current delivered by INA226
  */
  // ina226.setCorrectionFactor(0.95);
  
  Serial.println("INA226 Current Sensor Example Sketch - Triggered");
   
  // ina226.waitUntilConversionCompleted(); //makes no sense - in triggered mode we wait anyway for completed conversion
}

void loop() {
  float shuntVoltage_mV = 0.0;
  float loadVoltage_V = 0.0;
  float busVoltage_V = 0.0;
  float current_mA = 0.0;
  float power_mW = 0.0; 
  
  ina226.startSingleMeasurement();
  ina226.readAndClearFlags();
  shuntVoltage_mV = ina226.getShuntVoltage_mV();
  busVoltage_V = ina226.getBusVoltage_V();
  current_mA = ina226.getCurrent_mA();
  power_mW = ina226.getBusPower();
  loadVoltage_V  = busVoltage_V + (shuntVoltage_mV/1000);
    
  Serial.print("Shunt Voltage [mV]: "); Serial.println(shuntVoltage_mV);
  Serial.print("Bus Voltage [V]: "); Serial.println(busVoltage_V);
  Serial.print("Load Voltage [V]: "); Serial.println(loadVoltage_V);
  Serial.print("Current[mA]: "); Serial.println(current_mA);
  Serial.print("Bus Power [mW]: "); Serial.println(power_mW);
  if(!ina226.overflow){
    Serial.println("Values OK - no overflow");
  }
  else{
    Serial.println("Overflow! Choose higher current range");
  }
  Serial.println();
  
  delay(3000);
}

 

Beispiel 3: Power-Down Modus

Im Power-Down Modus bringt ihr den Strombedarf des INA226 von ca. 0.35 mA auf ca. 2,3 µA herunter (eigene Messungen).

Der Beispielsketch PowerDown.ino zeigt den Power-Down Modus in Aktion. Der Sketch startet den INA226 mit den Standardparametern. Fünf Messwert-Pakete werden im Abstand von je drei Sekunden ausgegeben. Die Funktion powerDown() sichert dann den Inhalt des Konfigurationsregisters und schaltet den INA226 ab. Die Funktion powerUp() schreibt die Kopie des Konfigurationsregisters wieder zurück. Zum einen weckt dieser Schreibvorgang den INA226 auf, zum anderen stellt er sicher, dass der INA226 in den zuvor gewählten Modus (hier: kontinuierlich) zurückkehrt.

#include <Wire.h>
#include <INA226_WE.h>
#define I2C_ADDRESS 0x40

INA226_WE ina226(I2C_ADDRESS);
// INA226_WE ina226 = INA226_WE(); // Alternative: sets default address 0x40

void setup() {
  Serial.begin(9600);
  Wire.begin();
  // default parameters are set - for change check the other examples
  ina226.init();
  Serial.println("INA226 Current Sensor Example Sketch - PowerDown");
  Serial.println("Continuous Sampling starts");
  Serial.println();
}

void loop() {
  for(int i=0; i<5; i++){
    continuousSampling();
    delay(3000);
  }
  
  Serial.println("Power down for 10s");
  ina226.powerDown();
  for(int i=0; i<10; i++){
    Serial.print(".");
    delay(1000);
  }
  
  Serial.println("Power up!");
  Serial.println("");
  ina226.powerUp();
}

void continuousSampling(){
  float shuntVoltage_mV = 0.0;
  float loadVoltage_V = 0.0;
  float busVoltage_V = 0.0;
  float current_mA = 0.0;
  float power_mW = 0.0; 

  ina226.readAndClearFlags();
  shuntVoltage_mV = ina226.getShuntVoltage_mV();
  busVoltage_V = ina226.getBusVoltage_V();
  current_mA = ina226.getCurrent_mA();
  power_mW = ina226.getBusPower();
  loadVoltage_V  = busVoltage_V + (shuntVoltage_mV/1000);
  
  Serial.print("Shunt Voltage [mV]: "); Serial.println(shuntVoltage_mV);
  Serial.print("Bus Voltage [V]: "); Serial.println(busVoltage_V);
  Serial.print("Load Voltage [V]: "); Serial.println(loadVoltage_V);
  Serial.print("Current[mA]: "); Serial.println(current_mA);
  Serial.print("Bus Power [mW]: "); Serial.println(power_mW);
  if(!ina226.overflow){
    Serial.println("Values OK - no overflow");
  }
  else{
    Serial.println("Overflow! Choose higher current range");
  }
  Serial.println();
}

 

Beispiel 4: Conversion Ready Alarm

Ladet nun den Sketch „Continous_Alert_Controlled.ino“ hoch. Mit diesem Beispiel lernt ihr den Alert Pin kennen. Zunächst wird mit 1024 die größtmögliche Zahl an zu mittelnden Einzelmessungen eingestellt. Dann gehen wir auch mit der Conversion Time an die obere Grenze, nämlich 8,244 Millisekunden. Damit braucht die Kombi aus Shunt- und Busspannungsmessung circa 16,9 Sekunden. Als Messmodus wählen wir CONTINOUS. Die Funktion enableConvReadyAlert() aktiviert den Alert Pin, der in seiner Standardeinstellung active-low ist. Der Alert Pin ist mit dem Arduino Pin 2 verbunden, für den wir einen Interrupt einrichten.

Wenn eine Messung beendet ist, dann geht der Alert Pin auf LOW und es wird ein Interrupt ausgelöst. Die Variable „event“ wird wahr und die if-Konstruktion in der Hauptschleife abgearbeitet. Zunächst wird readAndClearFlags() ausgeführt. Dadurch wird das Conversion Ready Flag wieder gelöscht und außerdem das Überlauf Flag gelesen. Die Messdaten werden ausgelesen und angezeigt. Der Interrupt an Pin 2 wurde nach dem Auslösen deaktiviert und wird nach der Ausgabe der Werte wieder angeschaltet. 

#include <Wire.h>
#include <INA226_WE.h>
#define I2C_ADDRESS 0x40

int interruptPin = 2;
volatile bool event = false;

INA226_WE ina226(I2C_ADDRESS);
// INA226_WE ina226 = INA226_WE(); // Alternative: sets default address 0x40

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ina226.init();

  /* Set Number of measurements for shunt and bus voltage which shall be averaged
  * Mode *     * Number of samples *
  AVERAGE_1            1 (default)
  AVERAGE_4            4
  AVERAGE_16          16
  AVERAGE_64          64
  AVERAGE_128        128
  AVERAGE_256        256
  AVERAGE_512        512
  AVERAGE_1024      1024
  */
  ina226.setAverage(AVERAGE_1024); 

  /* Set conversion time in microseconds
     One set of shunt and bus voltage conversion will take: 
     number of samples to be averaged x conversion time x 2
     
     * Mode *         * conversion time *
     CONV_TIME_140          140 µs
     CONV_TIME_204          204 µs
     CONV_TIME_332          332 µs
     CONV_TIME_588          588 µs
     CONV_TIME_1100         1.1 ms (default)
     CONV_TIME_2116       2.116 ms
     CONV_TIME_4156       4.156 ms
     CONV_TIME_8244       8.244 ms  
  */
  ina226.setConversionTime(CONV_TIME_8244); // Conversion ready after conversion time x number of averages x 2
  
  /* Set measure mode
  POWER_DOWN - INA219 switched off
  TRIGGERED  - measurement on demand
  CONTINUOUS  - Continuous measurements (default)
  */
  //ina226.setMeasureMode(CONTINUOUS); // choose mode and uncomment for change of default
  
  /* If the current values delivered by the INA226 differ by a constant factor
     from values obtained with calibrated equipment you can define a correction factor.
     Correction factor = current delivered from calibrated equipment / current delivered by INA226
  */
  // ina226.setCorrectionFactor(0.95);
  
  Serial.println("INA226 Current Sensor Example Sketch - Continous_Alert_Controlled");
  
  attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);

  ina226.enableConvReadyAlert(); // an interrupt will occur on interrupt pin when conversion is ready
}

void loop() {
  if(event){
    ina226.readAndClearFlags(); // reads interrupt and overflow flags and deletes them 
    displayResults();
    attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING); 
    event = false;  
  }
  
  delay(100);
}

void displayResults(){
  float shuntVoltage_mV = 0.0;
  float loadVoltage_V = 0.0;
  float busVoltage_V = 0.0;
  float current_mA = 0.0;
  float power_mW = 0.0; 
  
  shuntVoltage_mV = ina226.getShuntVoltage_mV();
  busVoltage_V = ina226.getBusVoltage_V();
  current_mA = ina226.getCurrent_mA();
  power_mW = ina226.getBusPower();
  loadVoltage_V  = busVoltage_V + (shuntVoltage_mV/1000);
    
  Serial.print("Shunt Voltage [mV]: "); Serial.println(shuntVoltage_mV);
  Serial.print("Bus Voltage [V]: "); Serial.println(busVoltage_V);
  Serial.print("Load Voltage [V]: "); Serial.println(loadVoltage_V);
  Serial.print("Current[mA]: "); Serial.println(current_mA);
  Serial.print("Bus Power [mW]: "); Serial.println(power_mW);
  if(!ina226.overflow){
    Serial.println("Values OK - no overflow");
  }
  else{
    Serial.println("Overflow! Choose higher current range");
  }
  Serial.println();
}

void alert(){
  event = true;
  detachInterrupt(2);
}

 

Praktische Anwendung des Conversion Ready Alerts

Während der langen 17 Sekunden zwischen den Messungen hat der Arduino bzw. der Microcontroller, den ihr in eurem Projekt einsetzt, nichts zu tun. Das verbraucht in batteriebetriebenen Projekten wertvollen Strom. Also schickt euren Microcontroller doch einfach schlafen und lasst ihn durch den Interrupt wecken. Falls ihr nicht wisst, wie das geht, schaut hier in meinen Beitrag zu dem Thema.

Beispiel 5: Limit Alert

Den Limit Alarm möchte ich euch anhand des Sketches Limit_Alert.ino näherbringen. Der INA226 läuft dabei im kontinuierlichen Modus. Auf der Arduino Seite wird wieder ein Interrupt an Pin 2 eingerichtet.

Durch die Funktion enableAlertLatch() wird der Alarm Pin so eingerichtet, dass er bei Auslösung eines Alarms so lange aktiv ist, bis er manuell durch readAndClearFlags() wieder inaktiv gesetzt wird. Ohne diese Einrichtung würde der Pin bei der nächsten Messung innerhalb der Limits automatisch zurückgesetzt werden.

Mit setAlertType() bestimmt ihr, welcher der Messwerte beobachtet wird und wo das Limit liegt. Ihr könnt ein Min- oder Max-Limit für die Shuntspannung, die Busspannung oder den Strom angeben. Für die Leistung ist nur ein Max-Limit vorgesehen. Von Haus aus ist übrigens keine Alarmfunktion für den Strom vorgesehen, das habe ich über einen Umweg implementiert.

Und das war es eigentlich auch schon. Wenn das eingestellte Limit gerissen wird, wird der Alarm Pin aktiv, der Interrupt ausgelöst und die Messwerte ausgelesen. Es sind wieder die aktuellen Messwerte. Bei schneller Messfrequenz erwischt ihr deshalb nicht unbedingt genau den Messwert, der den Alarm ausgelöst hat. Wenn ihr das wolltet, könntet ihr den INA226 bei Auslösung des Alarms in den Power-Down Modus schicken. Dann könnt ihr euch Zeit lassen mit dem Auslesen.

Mit der Funktion readAndClearFlags() müsst ihr ein bisschen vorsichtig sein. Wenn ihr die Flags lest, um sie auszuwerten, löscht ihr sie. Wenn dann die Alarmbedingung noch besteht, wird der Alarm Pin gleich wieder aktiv. Passiert das, bevor der Interrupt wieder aktiviert ist, kommt alles durcheinander. Der Alarm Pin wäre schon Low und der Interrupt Pin wartete auf ein Falling. Das kann er dann sehr lange tun! Deswegen wird readAndClearFlags() nochmal aufgerufen, nachdem der Interrupt wieder aktiviert wurde. Eine Trennung von Lesen und Löschen der Flags wäre etwas einfacher zu kontrollieren, das ist aber im INA226 so nicht implementiert.

#include <Wire.h>
#include <INA226_WE.h>
#define I2C_ADDRESS 0x40

int interruptPin = 2;
volatile bool event = false;

INA226_WE ina226(I2C_ADDRESS);

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ina226.init();

  /* Set Number of measurements for shunt and bus voltage which shall be averaged
  * Mode *     * Number of samples *
  AVERAGE_1            1 (default)
  AVERAGE_4            4
  AVERAGE_16          16
  AVERAGE_64          64
  AVERAGE_128        128
  AVERAGE_256        256
  AVERAGE_512        512
  AVERAGE_1024      1024
  */
  // ina226.setAverage(AVERAGE_1024); 

  /* Set conversion time in microseconds
     One set of shunt and bus voltage conversion will take: 
     number of samples to be averaged x conversion time x 2
     
     * Mode *         * conversion time *
     CONV_TIME_140          140 µs
     CONV_TIME_204          204 µs
     CONV_TIME_332          332 µs
     CONV_TIME_588          588 µs
     CONV_TIME_1100         1.1 ms (default)
     CONV_TIME_2116       2.116 ms
     CONV_TIME_4156       4.156 ms
     CONV_TIME_8244       8.244 ms  
  */
  // ina226.setConversionTime(CONV_TIME_8244); 
  
  /* Set measure mode
  POWER_DOWN - INA219 switched off
  TRIGGERED  - measurement on demand
  CONTINUOUS  - Continuous measurements (default)
  */
  //ina226.setMeasureMode(CONTINUOUS); // choose mode and uncomment for change of default
  
  /* If the current values delivered by the INA226 differ by a constant factor
     from values obtained with calibrated equipment you can define a correction factor.
     Correction factor = current delivered from calibrated equipment / current delivered by INA226
  */
  // ina226.setCorrectionFactor(0.95);
  
  Serial.println("INA226 Current Sensor Example Sketch - Limit_Alert");
  
  /* In the default mode the limit interrupt flag will be deleted after the next measurement within limits. 
     With enableAltertLatch(), the flag will have to be deleted with readAndClearFlags(). 
  */
    ina226.enableAlertLatch();
  
  /* Set the alert type and the limit
      * Mode *        * Description *           * limit unit *
    SHUNT_OVER     Shunt Voltage over limit          mV
    SHUNT_UNDER    Shunt Voltage under limit         mV
    CURRENT_OVER   Current over limit                mA
    CURRENT_UNDER  Current under limit               mA
    BUS_OVER       Bus Voltage over limit            V
    BUS_UNDER      Bus Voltage under limit           V
    POWER_OVER     Power over limit                  mW
  */
  ina226.setAlertType(POWER_OVER, 230.0);
 
  attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);
}

void loop() {
  if(event){
    ina226.readAndClearFlags(); // reads interrupt and overflow flags and deletes them 
    displayResults();
    attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING); 
    event = false;
    ina226.readAndClearFlags();
  }  
  delay(1000);
}

void displayResults(){
  float shuntVoltage_mV = 0.0;
  float loadVoltage_V = 0.0;
  float busVoltage_V = 0.0;
  float current_mA = 0.0;
  float power_mW = 0.0; 
  
  shuntVoltage_mV = ina226.getShuntVoltage_mV();
  busVoltage_V = ina226.getBusVoltage_V();
  current_mA = ina226.getCurrent_mA();
  power_mW = ina226.getBusPower();
  loadVoltage_V  = busVoltage_V + (shuntVoltage_mV/1000);
    
  Serial.print("Shunt Voltage [mV]: "); Serial.println(shuntVoltage_mV);
  Serial.print("Bus Voltage [V]: "); Serial.println(busVoltage_V);
  Serial.print("Load Voltage [V]: "); Serial.println(loadVoltage_V);
  Serial.print("Current[mA]: "); Serial.println(current_mA);
  Serial.print("Bus Power [mW]: "); Serial.println(power_mW);
  if(!ina226.overflow){
    Serial.println("Values OK - no overflow");
  }
  else{
    Serial.println("Overflow! Choose higher current range");
  }
  Serial.println();
}

void alert(){
  event = true;
  detachInterrupt(2);
}

 

Beispiel 6: Limit und Conversion Alert

Ich hoffe, ihr könnt noch – das ist aber auch das letzte Beispiel. Mit dem Sketch Limit_And_Conversion_Alert.ino möchte ich zeigen, wie ihr den Limit und den Conversion Ready Alarm nebeneinander nutzen könnt. Beide Alarme werden wie in den vorhergehenden Sketchen aktiviert.

Im Alarmfall wollt ihr nun unterscheiden können, welche Bedingung den Alarm ausgelöst hat. Lest dazu im Alarmfall die Flags über readAndClearFlags(). Dadurch aktualisiert ihr die Variablen limitAlert und convAltert und könnt sie abfragen.

#include <Wire.h>
#include <INA226_WE.h>
#define I2C_ADDRESS 0x40

int interruptPin = 2;
volatile bool event = false;

INA226_WE ina226(I2C_ADDRESS);

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ina226.init();

  // Conversion will be ready after conversion time x number of averages x 2
  ina226.setAverage(AVERAGE_512); 
  ina226.setConversionTime(CONV_TIME_8244); 
  // ina226.setCorrectionFactor(0.95);
  
  Serial.println("INA226 Current Sensor Example Sketch - Limit_And_Conversion_Alert");
  
  /* In the default mode the limit interrupt flag will be deleted after the next measurement within limits. 
     With enableAltertLatch(), the flag will have to be deleted with readAndClearFlags(). 
  */
  ina226.enableAlertLatch();
  
  /* Set the alert type and the limit
      * Mode *        * Description *           * limit unit *
    SHUNT_OVER     Shunt Voltage over limit          mV
    SHUNT_UNDER    Shunt Voltage under limit         mV
    CURRENT_OVER   Current over limit                mA
    CURRENT_UNDER  Current under limit               mA
    BUS_OVER       Bus Voltage over limit            V
    BUS_UNDER      Bus Voltage under limit           V
    POWER_OVER     Power over limit                  mW
  */
  ina226.setAlertType(CURRENT_UNDER, 45.0);
  ina226.enableConvReadyAlert(); // In this example we also enable the conversion ready alert interrupt
 
  attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING);
}

void loop() {
  if(event){
    ina226.readAndClearFlags();
    displayResults();
    attachInterrupt(digitalPinToInterrupt(interruptPin), alert, FALLING); 
    ina226.readAndClearFlags(); 
    event = false;
  }  
  delay(1000);
}

void displayResults(){
  float shuntVoltage_mV = 0.0;
  float loadVoltage_V = 0.0;
  float busVoltage_V = 0.0;
  float current_mA = 0.0;
  float power_mW = 0.0; 
   
  shuntVoltage_mV = ina226.getShuntVoltage_mV();
  busVoltage_V = ina226.getBusVoltage_V();
  current_mA = ina226.getCurrent_mA();
  power_mW = ina226.getBusPower();
  loadVoltage_V  = busVoltage_V + (shuntVoltage_mV/1000);
    
  if(ina226.limitAlert){
    Serial.println("Limit Alert !!!!");
  }
  if(ina226.convAlert){
    Serial.println("Conversion Alert!!!!");
  }
  Serial.print("Shunt Voltage [mV]: "); Serial.println(shuntVoltage_mV);
  Serial.print("Bus Voltage [V]: "); Serial.println(busVoltage_V);
  Serial.print("Load Voltage [V]: "); Serial.println(loadVoltage_V);
  Serial.print("Current[mA]: "); Serial.println(current_mA);
  Serial.print("Bus Power [mW]: "); Serial.println(power_mW);
  if(!ina226.overflow){
    Serial.println("Values OK - no overflow");
  }
  else{
    Serial.println("Overflow! Choose higher current range");
  }
  Serial.println();
}

void alert(){
  event = true;
  detachInterrupt(2);
}

 

Ausgabe von Limit_And_Conversion_Alert.ino

Für die folgende Ausgabe habe ich das gesetzte Limit dauerhaft überschritten. Entsprechend meldet der Sketch Limitüberschreitungen im Sekundentakt. Bei den oben eingestellten Bedingungen gibt der Sketch zusätzlich ca. alle 8 Sekunden ein Conversion Ready Alert aus:

Ausgabe des Limit_And_Conversion_Alert.ino Sketches
Ausgabe des Limit_And_Conversion_Alert.ino Sketches

Beispiel 7: Continuous mit alternativem Widerstand

Ein fleißiger Contributor hat meiner Bibliothek noch eine Funktion spendiert, mit der ihr alternative Shunts einsetzen könnt:

  • setResistorRange(0.005, 10.0) setzt den Widerstand in Ohm und die Range in Ampere.

Der Sketch funktioniert wie der Continuous.ino Sketch, nur mit der zusätzlichen Funktion. Ihr findet ihn in den mitgelieferten Beispielsketchen. Zu beachten ist, dass ihr setCurrentRange() nicht benutzen dürft.

Aber Achtung: viele INA226 Module mit kleineren Shunts sind Schrott! Dazu habe ich hier auf Github etwas geschrieben.

Alle Funktionen auf einen Blick

Hier seht ihr noch einmal alle Funktionen auf einen Blick. Das ist in Englisch, da ich die Tabelle auch für die Dokumentation auf Github verwende.

Liste der (öffentlichen) Funktionen der INA226_WE Bibliothek
Liste der (öffentlichen) Funktionen der INA226_WE Bibliothek

Details zur Bibliothek und den Registern das INA226

Wer noch immer nicht genug hat, kann jetzt noch etwas tiefer in den INA226 und die Bibliothek einsteigen.

Die Register des INA226

Der INA226 besitzt 10 Register, also deutlich mehr als der INA219 mit seinen 6 Registern. Alle Register umfassen 16 Bit.

Register des INA226
Register des INA226

Configuration Register

Configuration Register des INA226

Im Configuration Register könnt ihr grundlegende Einstellungen vornehmen:

  • RST – Reset Bit: ist es gesetzt, wird ein Reset ausgelöst.
  • AVGX – Average Bits: damit legt ihr die Anzahl der zu mittelnden Einzelmessungen fest.
  • VBUSCTX – Bus Voltage Conversion Time Bits: siehe Tabelle.
  • VSHCTX – Shunt Voltage Conversion Time Bits: siehe Tabelle.
    • Ich habe die Vereinfachung vorgenommen, dass nur eine Conversion Time wählbar ist, sie gilt dann für die Wandlung der Bus- und der Shuntspannung gleichermaßen.
  • MODEX – MODE Bits: legen den Modus fest, siehe Tabelle.
Average Bits des INA226
Average Bits
Shunt und Bus Voltage Conversion Time Bits des INA226
Shunt und Bus Voltage Conversion Time Bits
Mode Bits - nur die grün hervorgehobenen Modi habe ich implementiert
Mode Bits – nur die grün hervorgehobenen Modi habe ich implementiert

Mask/Enable Register

Ich springe zum Mask/Enable Register, weil dies neben dem Configuration Register das andere Register ist, in dem ihr Einstellungen vornehmen könnt.

Mask/Enable Register des INA226

Die Bits 10 bis 15 dienen zum Aktivieren der Alarme:

  • SOL / SUL: Shunt voltage over / under limit alert
  • BOL / BUL: Bus voltage over / under limit alert
  • POL: Power over limit alert
  • CNVR: Conversion ready alert

Von den Limit Alerts könnt ihr nur jeweils einen aktivieren. Setzt ihr mehrere Bits, dann gilt das höchste. Nur den Conversion Ready Alarm könnt ihr parallel aktivieren.

In meiner Bibliothek gibt es noch einen Current over und Current under Alarm. Intern wird dabei das SOL bzw. SUL Bit gesetzt und das Current Limit in ein Shunt Voltage Limit umgerechnet.

Weitere Einstellungen könnt ihr mit dem APOL und dem LEN Bit vornehmen:

  • APOL: Alert Pin Polarity Bit – Polarität des Alarm Pins. Standardeinstellung ist active-high (APOL = 0).
  • LEN: Latch Enable Bit. Standardeinstellung ist Latch disabled (LEN = 0). Das bedeutet, dass der Alarm Pin deaktiviert und das Alarm Flag Bit gelöscht werden, sobald eine OK – Messung erfolgt, also kein Limit gerissen wird. Ist LEN gesetzt, bleibt der Alarm Pin aktiviert und das Alarm Flag Bit gesetzt, bis das Mask/Enable Register gelesen wird (readAndClearFlags()).

Der INA226 setzt je nach Einstellung und Messergebnissen drei Flags:

  • AFF: Alarm Function Flag – ein Limit wurde überschritten.
  • CVRF: Conversion Ready Flag – Messwerte stehen bereit.
  • OVF: Overflow Flag – ein Datenregister ist übergelaufen.

Das CVRF Bit wird gelöscht, wenn das Mask/Enable Register gelesen oder Configuration Register beschrieben wird.

Ich habe die Funktion readAndClearFlags() so programmiert, dass sie den Zustand von AFF, CVRF und OVF in den Variablen limitAlert, convAlert und overflow speichert.

Shunt Voltage Register

Das Shunt Voltage Register enthält die Shunt Spannung mit einem LSB (least significant bit) von 2,5 µV. Mit anderen Worten: die Auflösung des Shunt Registers beträgt 2,5 µV pro Bit. Da das Register ein Vorzeichenbit besitzt, ist der Wertebereich der Shuntspannung begrenzt auf: 

Shuntspannungsbereich = \pm (2^{15}-1)\cdot 2,\!5 \text{\ µ\!V}=81,\!9175 \text{\ m\!V}

Über die Größe des Shunts könntet ihr theoretisch den maximal messbaren Strom festlegen. Allerdings habt ihr beim Modul keine Wahl und müsst mit den 0,1 Ohm vorlieb nehmen. Daraus ergibt sich ein Messbereich von +/- 819,175 mA für den Strom. Beim INA219 hingegen beträgt das Current LSB 10 µV. Damit ist der maximal messbare Strom dort viermal größer, wenn auch mit geringerer Auflösung. 

Bus Voltage Register

Das Ergebnis der Busspannungswandlung legt der INA226 im Bus Voltage Register ab. Vom Bus Voltage Register werden nur 15 Bit genutzt – das Vorzeichen ist immer positiv. Das LSB beträgt 1.25 mV, woraus sich eine maximale Busspannung von 40,96 V ergibt.

Current Register

Den aus der Shuntspannung berechneten Strom speichert der INA226 im Current Register. Hier wird es jetzt ein wenig kompliziert, da ein Kalibrierfaktor CAL ins Spiel kommt, der vom maximal zu erwartenden Strom und der Größe des Shunts abhängt:

C\!AL = \frac{0,\!00512}{Current\_LSB \cdot R_{Shunt}}\\ 
Current\_LSB = \frac{Maximum\ expected\ current }{2^{15}}

Man startet bei der Berechnung des Kalibrierwertes mit dem maximal zu erwartenden Strom. Für meine Bibliothek habe ich als Maximum 0.8192 Ampere gewählt.  Die Formel für CAL gäbe für 0.819175 „krummen“ Wert, deshalb habe ich etwas nach oben aufgerundet. Der Inhalt des Current Registers ergibt sich aus:

Current\ Reg = \frac{Shunt\ Voltage\ Reg \cdot C\!AL}{2048}

Am Ende müsst ihr den Inhalt des Current Registers mit dem Current_LSB multiplizieren, um den Strom zu erhalten.

Für andere Shuntgrößen errechnet die Bibliothek den Kalibrierfaktor automatisch.

Power Register

Das Power Register enthält den berechneten Wert für die Leistung gemäß der folgenden Formel:

Power\ Reg = \frac{Current\ Reg \cdot Bus\ Voltage\ Reg}{20000}

Und schließlich ist die Leistung dann der Inhalt des Power Registers, multipliziert mit dem Power_LSB. Für den Power_LSB gilt (intern festgelegt):

Power\_LSB = Current\_LSB\cdot 25

Calibration Register

Das Calibration Register enthält den oben erwähnten Kalibrierwert.

Alert Limit Register

Das Alarm Limit tragt ihr in das Alert Limit Register ein. Ich habe das so implementiert, dass ihr die Grenzwerte direkt über die Funktion setAlertType() in den jeweils vorgesehenen Einheiten übergeben könnt.

Berechnung der Kalibrierfaktoren und der LSBs

Den Inhalt der Datenregister rechnet die Bibliothek mit den LSBs und weiteren Faktoren in die gewünschten Einheiten um:

Umrechnung der Datenregisterinhalte
Umrechnung der Datenregisterinhalte

Um handliche Umrechnungsfaktoren zu erhalten, habe ich einen Current Divider und einen Power Multiplier eingeführt:

Current\ \text{[mA]}=\frac{Current\ Register}{Current\ Divider}\ \ \\ 
\text{mit}\ \ Current\ Divider = \frac{1}{Current\_LSB\cdot 1000}

und

Power\ \text{[mW]} = Power\ Register \cdot Power\ Multiplier
Power\ Multiplier = Power\_LSB \cdot 1000

Die folgenden Werte habe ich dann in der Bibliothek implementiert:

Werte für den implementierten Strombereich

Danksagung

Das Bild von dem Strommesser stammt aus dem Free-Photos Fundus von Pixabay. Ebenso stammen die Alarmleuchte von Alexey Hulsov und die Anzeige von den OpenClipart-Vectors aus Pixabay.

58 thoughts on “INA226 Strom- und Leistungssensor

  1. Gute Erklärung und Kompliment zur eigenen Library, danke!
    Ich bin daran, ein ESP8266_D1mini mit INA226 zu betreiben und via MQTT auszugeben.
    Der Sketch wird erfolgreich compiliert aber die Ausgabe bleibt „nul“.
    Du betreibst deinen Arduino mit SCL mit A5 und SDA mit A4, ok. Ich muss aber meinen ESP mit SCL D1/GPIO 5 und SDA mit D2/GPIO 4 ansprechen. Ich vermute hier das Problem.
    Was meinst du mit „…Wire Objekt übergeben. Letzteres erlaubt euch z.B. beide I2C Busse eines ESP32 zu nutzen“? Wie kann ich dem INA226_WE-Objekt meine ESP-Pin-Adressen übergeben?
    I2C-Address 0x40 wird gescannt und ist ok.
    Freundliche Grüsse
    Andreas

    1. Hallo,
      die Kombination D1 Mini / INA226 funktioniert bei mir ohne Probleme mit den Pins D1 und D2, z.B. mit dem Sketch Continuous.ino ohne jede Änderung. Hast du diesen Sketch mal getestet? Wenn es ein Problem mit der I2C Verbindung gibt, dann sollte er „Failed to init INA226. Check your wiring.“ zurückmelden und stoppen. Der dem D1 Mini zugrundeliegende ESP8266 besitzt nur eine I2C Schnittstelle. Der ESP32 hat zwei. Aber wie gesagt, es muss auch so gehen.
      VG; Wolfgang

  2. hallo , Danke erst einmal für die tolle Doku .
    ich stolpere gerade über eine Sache ! Wird die Leistung ( power ) immer positiv gegeben ?
    Ich habe aktuell negativen Strom und eine Positive Leistung in der Ausgabe das passt irgendwie nicht zusammen

    1. Hi, Leistung P = U * I bzw. P = RShunt * I2. Da kommt immer ein positiver Wert heraus. Eine negative Leistung macht physikalisch auch nicht so viel Sinn.

      1. Ok das sehe ich anders Ob die Leistung aus oder in den Akku geht ist schon ein Unterschied
        P = U x I -> 5V x -2A = -10 W ?
        Deine Aussage ist nur Richtig wenn man den Shunt „isoliert“ betrachtet weil dann ja auch die Spannung-Shunt negativ wird .
        Egal dann muss ich P selber berechnen ( mit negativen Werten )

        1. Hallo,
          erst einmal eine Korrektur: RShunt in meiner Gleichung ist natürlich durch RVerbraucher zu ersetzen. Spielt allerdings keine Rolle.
          Ich weiß, was du meinst, aber es ist eine Interpretation, die Leistung negativ auszugeben, wenn der Strom in die andere Richtung fließt. Du gehst dabei von deiner spezifischen Anwendung aus und definierst, dass das Laden des Akkus eine negative Leistung ist. Ich gebe hier auch nur den Leistungswert aus, den der INA226 in seinem Power-Register bereitstellt und dieses liefert im Gegensatz zum Shunt Voltage und Current Register nur „unsigned“ Werte.
          Und noch eine kleine pedantische Anmerkung: Je nachdem, auf welcher Seite des Shunts du die Busspannung ermittelst und in welche Richtung der Strom fließt, beziehst du den Leistungsabfall am Shunt mit ein oder nicht. Bei 800 mA und einem Shunt von 0,1 Ohm sind das zwar nur 64 Milliwatt, aber wenn man es ganz genau nimmt, dann müsste man das herausrechnen.

  3. Herzlichen Dank für diesen sorgfältig aufgebauten Beitrag! Wenn man die Breakout-Boards mit eigenem R100/0,1 Ohm Shunt verwendet, ist man beim Strom mit 0,8A arg eingeschränkt. Wäre es möglich, mehrere Module parallel zu betreiben, um den Strombereich zu erhöhen? Natürlich müsste man dann die Messwerte addieren. Ich frage mich nur, ob sich der Strom tatsächlich „gerecht“ aufteilt. Der Widerstand müsste ja ziemlich präzise und gleich sein. Besten Dank!

    1. Interessanter Ansatz. Ja, wieso nicht. Aber einfacher wäre es dann doch, eine Ausführung mit einem anderem Shunt zu nehmen. Ich habe den INA226 schon mit Shunts von 0,01 und 0,002 Ohm gesehen. Bei Amazon ist die Auswahl begrenzt, aber bei AliExpress gibt es so Einiges. Dauert allerdings ein wenig mit der Lieferung aus China.

      1. Ich bin etwas verwirrt: offenbar soll der INA226 einen internen Verstärkungsfaktor besitzen, so dass man mit einem üblichen R100 Shunt bis zu 3,8A messen können soll, wenn man ihn auf den kleinsten Wert reduziert. Entweder übersehe ich etwas, oder ich bin einer Falschmeldung aufgesessen. Jedenfalls wäre es super, wenn die günstigen R100-Breakout Boards out of the box Stromstärken von etwas mehr als 0,8A messen könnten. Es müssen ja nicht gleich 3.8A sein. Gibt es zu diesem „Verstärkungsfaktor“ irgendwelche Infomationen? Vielen Dank!

        1. Könnte es richtig sein, dass nur der INA219 über diesen Gain-Faktor verfügt? Aus der Einleitung hatte ich angenommen, dass der INA226 einfach nur die „modernere“ Version des INA219 sei. Falls der INA226 indes über keine Anpassungsmöglichkeit für die Stromstärke mehr verfügt, wäre das aus meiner Sicht ein riesiger Unterschied. Mit den günstigen Breakout Boards könnte man dann mit einem INA219 flexibel bis zu ca. 3A messen (völlig ausreichend für die meisten kleineren Projekte und Akkucharger), mit dem INA226 halt nur im unter-1A-Bereich (dafür sind die Einsatzbereiche zumindest für mich eher theoretisch). Oder habe ich eine Anpassungsmöglichkeit beim INA226 womöglich einfach nur übersehen?
          Das Problem mit kleineren Shunts ist, dass es diese selbst bei Aliexpress nur selten gibt und wie von Dir auf github berichtet viele dieser Module schlecht sind.
          Herzlichen Dank!

          1. Richtig. Wenn du die INAs als Module mit 0.1 Ohm Shunts verwendest, dann kann der INA219 bis 3.2 A messen und der INA226 nur bis 0.8. Durch die verschiedenen GAIN Einstellungen ist der INA219 flexibler. Aber sowohl der INA219 als auch der INA226 können noch wesentlich höhere Ströme als 3.2 A messen. Das ist eine Frage des Shunts. Dass die Modulbauer hauptsächlich 0.1 Ohm verwenden, da kann der INA226 nichts für. Das Datenblatt schreibt das ja nicht vor. Ich habe ganz gute Erfahrungen mit Modellen gemacht, die kleinere Shunts haben. Damit will ich nicht behaupten, dass alle Kritiker dieser Teile in jedem Fall falschliegen, da gibt es bestimmt auch teilweise Schrott. Eine Alternative ist der Selbstbau. Ist mehr Aufwand, aber auch nicht so viel, wie man vielleicht meinen sollte:
            https://wolles-elektronikkiste.de/stromsensor-selber-bauen

  4. Hallo Wolfgang,
    noch eine Ergänzung zum Powerdownthema:
    Das oben beschriebene Board hat am Alert-Ausgang einen 10k Pullup (wegen open Drain Ausgang des Chips). D.h. man muss im Powerdownmode dafür sorgen, dass der Alarm-Pin auf HIGH liegt (der Alert Ausgang bleibt auch im Powerdown in seinem vorherigen Zustand!) – sonst sorgt dies auch für zusätzliche 500uA im Powerdownmode !
    Das Thema kommt ggf. beim Interruptbetrieb auf. Ein Möglichkeit hierzu ist wohl die Funktion ina226.reset_INA226() bevor der Powerdown eingeleitet wird. Allerdings ist dann auch nach jedem Wakeup eine kompl. Neuinitialisierung des INA226 notwendig.

  5. Hallo Wolfgang,
    wieder mal ein sehr schöner Beitrag !! Vielleicht hier noch ein kleiner HInweis für den Stromsparer 🙂

    Ich habe etwas mit dem Powerdown Mode experimemtiert – wenn man hier die letzen uA herausholen möchte und nicht mit der Standardadresse 0x40 arbeiten möchte, dann stören die auf dem Board verbauten Pulldownwiderstände an A0/A1 mit immerhin noch ca. 500uA!
    Abhilfe müsste dann ggf. durch Auslöten des betr. Widerstandes und hartes Klemmen von A0/A1 auf Vcc möglich sein.
    Wenn man mit der Standardkonfiguration ohne Lötbrücken arbeitet ist natürlich keine weitere Aktion nötig – dann stimmen deine ermittelten Ruheströme recht gut !

    1. Vielen Dank für die Anregung! Stimme zu, Pulldown-Widerstände verbrauchen Strom.
      VG, Wolfgang

  6. Wenn man für knapp 30€ sich einen Vierleiter Messwiderstand mit 0,01 Ω besorgt ist der Messbereich des INA226 schon 8A. Den gleichen Messwiderstans gibt es auch mit 0,001Ω, was einen Messbereich von 80A entspräche. Der Vorteil der Vierleiter Messwiderstände ist das man an den äußeren Anschlüssen die Last anschließt und an den inneren zwei Anschlüssen einen präzisen Abgriff hat. Aber 80 Ampere lässt sich kaum noch über Leiterbahnen führen. Bei 80 Ampere sind schon 25 mm² nötig. Bei 8 A kommt man mit 1.5 mm² hin

    1. Vielen Dank!

      Bei ganz hohen Strömen würde ich raten, den INA226 durch einen Selbstbau zu ersetzen. Das ist relativ einfach umzusetzen und es gibt sehr verlässliche Werte, wenn man richtig kalibriert:
      https://wolles-elektronikkiste.de/stromsensor-selber-bauen
      Allerdings sollte man bei hohen Strömen auch immer einen Fachmann drüber schauen lassen, wenn man selber keiner ist, damit einem nicht das Haus abbrennt!

  7. Hallo Wolfgang

    Eine wirklich schoene Beschreibung hast du hier gemacht. Respekt.
    Ist es moeglich mit dem INA226 sowohl das laden als auch das entladen zu messen.?
    Der INA 219 konnte das, meines wissens nach, nicht.
    D.H einmal liegt eine positive Spannung am Shunt beim laden und eine negative Spannung beim entladen.
    Geht das , High Side oder Low Side ?

    73

    1. Hallo Klaus,

      zumindest geht die Strommessung. Negative Shuntspannungswerte sind auch messbar und ergeben negative Ströme. Ich habe es kurz mal ausprobiert. High Side oder Low Side ist egal. Nur die Messung der Busspannung und, daraus abgeleitet, die Messung der Leistung wird nicht funktionieren, da du bei Umkehrung VBUS auf der GND Seite misst. Das könnte man mit zwei Anschlüssen für VBUS und einem Schiebeschalter lösen. Oder vielleicht elektronisch mit MOSFETS.

      Mit dem INA219 müsste die Messung negativer Ströme eigentlich auch funktionieren. Ich habe geschrieben, dass der INA219 nur High Side geeignet ist, das bezieht sich aber nicht auf die Strom-, sondern die Busspannungsmessung und die Leistung. Da der INA219 keinen VBUS Pin hat, sondern die Busspannung direkt am Shunt misst, funktioniert das auf der Low Side halt nicht.

      Hoffe, das hilft. Viel Erfolg!

  8. Danke für deinen tollen Beitrag und auch für die Mühe diese Bibliothek zu erschaffen. Ich habe Module mit 0.1ohm und mit 0.01 ohm. mit der Einstellung setResistorRange (0.021, 4) bekomme ich Recht brauchbare werte geliefert (0.01ohm)
    🤔

      1. Ich beschäftige mich gerade mit den Registern. Ich möchte nämlich den INA ohne Bibliothek nutzen und die Einträge in die Register selbst machen.
        Mir ist da aufgefallen dass das Current_LSB = 0,00002441 ist – Ich frage mich allerdings wieso man auf 0,00004 rundet? Auch bei dem Messbereich bis 400mA kann das doch nicht 0,00002 sein?!? Müsste das nicht 0,000024 und 0,00012 sein? Oder habe ich hier einen Denkfehler, oder ist dies vernachlässigbar?

        1. Keine Sorge, das ist keine Rundung, die sich proportional auf das Ergebnis auswirkt. Das rechnet sich nachher wieder raus. Wenn du die Formel für CAL in die Formel für das Current Register einsetzt, dann steht das Current_LSB im Nenner. Wenn du den Inhalt des Current Registers in den Strom umrechnest, musst du wieder mit Current_LSB multiplizieren. Das rechnet sich raus. Und mit den von mir gewählten Werten gibt es gerade Zahlen. Der CAL und Current_LSB sind nur Hilfsmittel, damit die Werte in das Current Register passen.

          Wenn du dir das Hirn verdrehen möchtest, dann schau dazu mal ins Datenblatt. Den Abschnitt zu den Berechnungen musste ich fünfmal lesen, bevor ich ihn verstanden habe.

          Im Grunde könnte man sich das ganze Gedönse auch sparen und den Strom schlicht direkt aus dem Inhalt des Shuntspannungsregisters errechnen. Strom = Shuntspannungsregisterwert * 2.5 µV / R_Shunt. Und über das Busspannungsregister und den Strom könnte man die Leistung errechnen. Deswegen kann man eigentlich auch mit sehr einfachen Mitteln einen Stromsensor selbst bauen. Du brauchst nur einen Shunt, und einen guten A/D-Wandler, ggf. noch einen Verstärker.

  9. Hallo Wolfgang,

    ich möchte mit einem INA226 Modul für -20A bis 20A eine Batterie laden und den Strom überwachen. Der Shunt hat 0.002Ohm. Ist demnach alles was ich machen muss: ina226.setResistorRange(0.002, 40); in der setup Funktion? Es hatte kurz funktioniert und jetzt nicht mehr. Der gemessene Shunt Voltage bei ca. 10A Strom ist 0.04mV und kommt mir ziemlich gering vor. Ist es vielleicht was mit dem Shunt Widerstand schiefgelaufen?

    Vielen Dank für deine ausführliche Dokumentation hier, hat mir schon sehr geholfen!

    VG
    Flo

    1. Hi Flo,

      da ist tatsächlich irgendwo ein Fehler. Bei 10A und einem Shunt von 0.002 Ohm kann man leicht ausrechnen, dass die Shuntspannung bei 0.02V = 20 mV liegen müsste. Die Shuntspannungsberechnung ist unabhängig von allen den anderen Eingaben (außer Korrekturfaktor). Hast du vielleicht getShuntVoltage_V() anstelle von getShuntVoltage_mV verwendet?

      VG, Wolfgang

  10. Hey Wolfgang, ich benutze in meinem Projekt auch den INA226. Ich möchte an einer Stelle nur die Spannung über den Vbus-Pin messen, kann ich dann die IN+ und IN- Kontakte einfach frei lassen oder benötigen diese eine Bechaltung?

    VG, Dennis

    1. Hi Dennis, ich wüsste keinen Grund, warum es nicht gehen sollte. Die VBus Messung ist unabhängig von der Shunt Messung. VG, Wolfgang

  11. Hallo Wolfgang, ich bin ahnungslos 🙂 was die Elektronik angeht…
    Dennoch konnte ich deinem Blog einiges abgewinnen, für mich gut geschrieben.
    Gefunden habe ich deine Seite auf der Suche nach einer Möglichkeit meine
    12V Batterie über i2C in SignalK zu überwachen (Spannung).
    ina219, ina 226, ina260(gibt es nicht mehr), ads1115, können die das alle ?
    Was kann ich dafür am besten einsetzen, was würdest du mir empfehlen ?

    Vielen Dank

    1. Hallo Kurt, die „INAs“ messen den Strom. Du möchtest die Spannung überwachen und deswegen ist ein A/D-Wandler die richtige Wahl. Wenn du es nicht zu genau brauchst, dann reicht der interne A/D-Wandler eines Arduinos aus. Sonst käme der ADS1115 in Frage. Du musst nur bedenken, dass beide Lösungen nur ca. 5 Volt vertragen, d.h. du müsstest die Spannung über einen Spannungsteiler messen. Der wiederum sollte nicht zu niedrigohmig sein, da permanent Strom über ihn fließt.
      VG, Wolfgang

      1. Hallo Wolfgang, das ging ja schnell , vielen Dank.
        Ja ich möchte die Spannung der 12 Volt Batterie überwachen.

        Das ganze soll mit einem Raspberry Pi funktionieren , der ist schon da.
        Als Software ist Openplotter installiert, da kann ich den ADS1115 in der i2C
        App einbinden und mir die Daten über SignalK ausgeben.
        Gibt es so einen Spannungsverteiler schon fertig aufgebaut ?
        Nach was muss ich denn da schauen ?
        Vielen Dank

        1. Hallo Kurt, Openplotter und SignalK kenne ich nicht, da kann ich nicht weiterhelfen. Aber zumindest beim Spannungsteiler. Du brauchst lediglich zwei Widerstände, die du in Reihe zwischen die V+ und V- der Batterie schaltest. Der Rest ist Ohmsches Gesetz. R_gesamt = R_1 + R_2. Gleiches gilt für die Spannungen. Der Rest ist Dreisatz.

          Der Raspberry Pi hat keinen internen A/D-Wandler, das heißt du musst auf einen externen Wandler gehen. Und der RPi wird meist mit Python programmiert. Ich bin mehr mit Arduino/C++ unterwegs.

          VG, Wolfgang

  12. Hallo Wolfgang,
    danke für deine detaillierte Beschreibung, hat mir viel weitergeholfen. Vielleicht kannst du mir bei einer sehr speziellen Situation weiterhelfen, oder zumindest deine Meinung kundtun.
    Ich möchte, zumindest testweise, einen 200 A Hallsensor an In+ / In- betreiben. Später einen 200 A Shunt; und dann die bessere Lösung implementieren. Den kleinen Shunt auf dem Board habe ich ausgelötet.
    Im INA226 Datenblatt steht: Shunt voltage input range –81.9175 to 81.92 mV und unter maximum ratings Differential (VIN+ – VIN-) –40 to 40 V, wobei jeder einzelne Pin zwischen – 0.3 und 40 V liegen darf.
    Der Hallsensor liefert 2,5 V +/- 0,625V bei +/- 200 A. Shunts bekommt man meist für 50 bis 150 mV.
    Darf man nun Sensoren mit einer höheren Spannung als die ca. 81 mV anschließen oder nicht? Wenn ja, kann man den Meßbereich mit SetResistorRange() korrekt einstellen?
    Zur Klarstellung: ja, man verliert signifikant Auflösung bei Anwendung des Hallsensors, es sind dann noch ca. 13,5 bit. Aber immer noch besser als die üblichen 10 bit. Und ich brauche speziell die Werte um 1 A einigermaßen aufgelöst.
    Alles Gute
    Dieter

    1. Hallo Dieter,
      die Grenzen für die Shuntspannung ( –81.9175 bis 81.92 mV) können nicht verschoben werden. Ein Bit des Shuntregisters entsprechen 2.5 µV und das Register 16 Bit breit, also -2^15 bis +2^15. Man muss also durch passende Auswahl des Shunts dafür sorgen, dass die Spannungsdifferenz vor und hinter dem Shunt diese Werte nicht überschreitet. Wenn man es trotzdem tut, misst man nur noch den Vollausschlag.
      Die Angabe im Datenblatt, dass die „Differential Voltage VIN+ – VIN-“ zwischen -40 und + 40 V liegen darf, finde ich auch etwas verwirrend. Aber Tatsache ist, dass Spannungsdifferenzen außerhalb –81.9175 bis 81.92 mV nicht erfasst werden können.
      VG, Wolfgang

  13. Hallo Wolfgang,
    darf ich eine kurze Frage zur Funktion setResistorRange(0.005, 10.0) stellen.

    Wie kann ich das verstehen, der INA misst ja bis max ca. 80mV am Shunt. Wenn nun der Widerstand auf 0,005 Ohm gestellt wird, mit einem Strombereich bis 10A, wäre das im Bereich der maximalen 80mV (10A*0,005Ohm = 0,05V), also möglich. Oder anders gesagt, bei 0,005Ohm könnte ich maximal einen Strombereich von 0,080V/0,005Ohm = 16A mit der Funktion einstellen, sodass dies noch funktioniert?

    Warum gibt man in dieser Funktion den Strombereich mit, was wird damit gemacht?

    danke!
    lg Wolfgang

    1. Hallo Wolfgang,

      erstmal ja, es ist richtig, dass der Shunt bis 80 mV misst und damit in Kombination mit der Shuntgröße den maximal messbaren Strom festlegt. Die Shuntspannung wird intern vom INA 226 in einen Strom umgerechnet und im Current Register abgelegt. Der INA226 kann aber nicht wissen, wie groß der Shunt ist. Dafür gibt es den Kalibrierwert, der mithilfe des maximal erwarteten Stroms berechnet. Wird. Anstelle des maximal erwarteten Strom könnte man auch einfach den maximal möglichen Strom zugrunde legen. Wenn der tatsächlich auftretende maximale Strom aber nun deutlich kleiner sein sollte, geht das auf die Auflösung der Stromwerte.
      Nehmen wir dein Beispiel mit dem Shunt von 0.005 Ohm. In der Tat ließen sich damit bis zu 16 Ampere messen. Wenn du nun 16 Ampere als maximalen erwarteten Strom angibst, dann wird der Kalibrierwert so gewählt, dass das Current Register bei 16 Ampere voll genutzt wird. Wenn die tatsächlichen Ströme nur bis sagen wir mal 4 Ampere auftreten nutzt du nur ein Viertel des Current Registers und verschenkst entsprechend Auflösung.
      Hoffe das ist halbwegs verständlich,
      Grüße von Wolfgang zu Wolfgang!

  14. Hallo Wolfgang,
    Dein Beitrag ist echt toll! Vielen Dank!
    Hast du dir auch schon mal den INA229 angesehen, wäre es möglich deine Bibliothek für diesen zu adaptieren?
    Vielen Dank,
    Lg
    Auch Wolfgang

    1. Hallo Wolfgang,

      ich habe ihn mir mal angeschaut. Interessantes Bauteil, sehr empfindlich und schnell. Der INA229 ist aber so anders, dass ich eine separate Bibliothek programmieren würde. Was mich noch davon abhält ist, dass ich die Teile bisher nur bei Mouser gefunden habe. 6 Euro das Stück und 20 Euro Versandkosten. Der Preis und die Tatsache, dass das gute Stück nicht als Modul verfügbar ist, wird viele vom Kauf abschrecken. Und das wiederum schreckt mich dann ab. Der Prgrammieraufwand soll sich auch lohnen.

      VG von Wolfgang zu Wolfgang!

  15. Hallo ich möchte mein Akku vom e-bike messen wie siehts aus die Spannung kann >36V bis 40V betragen
    welchen. Shunt- Modul kann ich da verwenden .
    Mit freundlichen Grüßen cio

    1. Hallo, erstmal hängt die Shuntgröße vom zu erwartenden Strom und nicht von der Spannung deines zu überwachenden Stromkreises ab. Der INA226 misst die Spannungsdifferenz vor und hinter dem Shunt und die wird nur durch den Strom und die Shuntgröße bestimmt. Die maximale Shuntspannung ist 81,9175 mV. Der Rest ist Ohmsches Gesetz:
      Shunt (max) [Ohm] = 0,0819175 [V] / I (erwartetes Max.) [A]

      Allerdings gibt es trotzdem eine Obergrenze für die Spannung, die der INA226 verträgt und die liegt bei 36 Volt. Du kannst den INA226 trotzdem für deine Anwendung zur Strommessung nutzen, indem du die Low-Side Konfiguration wählst, d.h. du setzt den INA226 zwischen Verbraucher und GND. Nur die Leistung wirst du nicht ohne weitere Maßnahmen messen können, da du dafür den VBS Anschluss vor den Verbraucher setzen müsstest und würdest damit das 36 Volt Limit überschreiten. Dieses Problem wiederum könntest du ganz einfach mit einem Spannungsteiler umgehen. Teile die Spannung zum Beispiel 50:50, dann musst du den Leistungswert einfach verdoppeln.

      Viel Spaß beim Projekt, Wolfgang

  16. Hallo Wolfgang
    Habe im Internet einiges zum INA226 gefunden. Da gibt es auch eine Tabelle mit 16 Adressen für den I2C Bus. Du hast 4 Adressen angegeben. Wie kommt es zu diesem Unterschied?

    1. Hallo Achim,
      das ist richtig, man kann 16 Adressen einstellen. Die Einrichtung der „fehlenden“ 12 Adressen ist nur nicht so bequem. Auf dem Modul sind A0 und A1 auf GND gezogen und man kann sie leicht mit VCC verbinden. Macht 2^2 Möglichkeiten. Man kann sie aber auch mit SDA und SCL verbinden, das macht dann 2^4 = 16 Möglichkeiten. Ist nur etwas unhandlicher Kabel an die Anschlüsse A0 und A1 zu löten, als die Verbindung zu VCC zu überbrücken.

  17. Hallo Wolfgang!
    Generell mal gesagt, finde ich Ihren Blog hochinteressant! Vor allen Dingen die ausführlichen Beispiele, Skizzen und die flotte, leicht verständliche Schreibweise sind immer wieder spannend zu lesen!

    Zum Artikel über den INA226:
    Eigentlich wollte ich einen Monitor zur Vermessung der Antriebe meiner E-Flugmodelle mit dem INA219 bauen. Da aber der INA226 schneller da war, ist also dieser zum Zug gekommen zur Messung der Parameter Spannung, Strom und Leistung. Die Ergebnisse zeige ich auf einem einfachen 2-Zeilen-LCD an. In ein kleines Holzgehäuse verfrachtet sieht das Ganze auch noch chic aus.
    Als Stromshunt (2,5mOhm) verwende ich ein kurzes Stück 1,5qmm Cu-Kabel, das schnell berechnet und „gewickelt“ war. Den 100mOhm-Shunt habe ich ausgelötet, hätte ihn aber auch drinlassen können. Mit Ihrer flexiblen Library wäre auch das kein Problem gewesen. Der Clou der Library aber ist, dass ich einfach den Shuntwert und den Strombereich definiere (in meinem Fall 2,5mOhm und 30A max.) und automatisch die korrekten Werte erhalte, ohne eigene Software stricken zu müssen.

    Wenn es dieses Feature auch in der Library für den INA219 gäbe!?

    Vielen Dank nochmal für Ihren Blog und weiter so!

    Viele Grüße

    W. Appel

    1. Hallo Willi,

      die Frage passt sehr gut, denn seid ein paar Tagen hat die INA219 Bibliothek eine Funktion namens setShuntSizeInOhms(). Ein Beispielsketch ist dabei. Der maximal messbare Strom ist 3.2 A x 0.1 / Shuntgröße bei der geringsten Verstärkung (PG_320 = 1fach). Wenn du diesen Bereich nicht ausnutzt, kannst ggf. eine höhere Verstärkung wählen. Bei 2.5 mOhm und max 30 Ampere kannst du mit PG_80 (4fache Verstärkung) arbeiten, dann hast du eine höhere Auflösung.
      Alles weitere wird im Hintergrund richtig berechnet.
      VG, Wolfgang

  18. Hey Wolfgang, der Artikel ist super!
    Der Code funktionierte sofort und ich habe mir die Kommentare durchgelesen und konnte problemlos 3 INA226 mit 5mOhm Shunt einbringen.
    Ist es möglich die Ausgabe statt 2 auf 3 oder 4 Nachkommastellen zu erhalten? Dafür hat man sich ja den genaueren 226 geholt 🙂
    Und ich habe im void loop current_mA_1 /= 1000; und power_mW_1 /= 1000;
    verwendet, um die Ampere und Watt ohne millis zu haben, geht das auch eleganter?

    Vielen Dank & großes Lob,

    1. Hi Karim,

      danke für das Feedback. Die Formatierung bei der Ausgabe Ergebnisse ist keine Frage meiner Bibliothek. 2 Nachkommastellen sind der Standard. Willst du z.B. vier Stellen der float Zahl x ausgeben, dann schreib einfach:

      Serial.print(x, 4);

  19. Hallo Wolfgang, oder besser Herr Ewald?

    Ich möchte mich für sehr guten Seiten zum ADS 1115 und speziell für diese hier zum 226 bedanken!
    Hat es mir doch genau das gezeigt, was ich für mein Projekt (Heizung/Lüftung Klein/Micro-Gewächshaus) zur Überwachung der Heizer brauche. Da ich zwei 12V Heizstränge habe mit je ca. 6A Arbeitsstrom, möchte ich gern zwei dieser INA benutzen/auslesen. Derzeit mache ich das noch mitACS 712, aber das gefällt mir nicht wirklich.
    Einen INA226 habe ich heute erhalten und sogleich im Test-Setup eingebaut, Lib und Code geladen. Läuft!

    Da ich noch nicht so sehr lange mit der Materie vertraut bin ist mir schleierhaft, wie ich zwei der Module ansprechen/Auslesen kann.

    VG, Lutz

    1. Hallo, also „Wolfgang“ ist mir viel lieber.
      Zwei Module auslesen ist kein Problem. Bei einem der Module musst du die Adresse ändern. Also z.B. A0 mit VCC verbinden dann ist die Adresse 0x41.
      Dann erzeugst du zwei INA226 Objekte:
      #define I2C_ADDRESS_1 0x40
      #define I2C_ADDRESS_2 0x41
      INA226_WE ina226_1(I2C_ADDRESS_1);
      INA226_WE ina226_2(I2C_ADDRESS_2);

      Beide Module kommen and die I2C Leitungen. Das eine sprichst du mit ina226_1 an, das andere mit ina226_2. Also einfach den Code entsprechend duplizieren. Klar? Viel Erfolg!

      VG, Wolfgang

  20. Hallo,
    Vielen Dank für das schöne Tutorial – funtkioniert einwandfei!
    Aber kann es sein, daß man bei Verwendung von „setResistorRange“ auch „setCorrectionFactor“ nicht verwenden darf? (beide Funktionen schreiben das Register „calVal“)

    Vg,
    Zitti

    1. Gut gesehen! Die setResistorRange() Funktion kam nachträglich in die Bibliothek. Sie ist noch nicht besonders gut in die Bibliothek integriert. Dafür muss ich aber ein bisschen tiefer eingreifen und habe mich bisher davor gedrückt…

  21. Hallo Herr Ewald,
    ich habe Ihren Beitrag gelesen und fand Ihn sehr Informativ. Leider bin ich kein Elektroniker und kein Programmierer spiele aber gerne ein bisschen mit den Dingen herum. Ich habe ein Arduino NANO den INA226 und Ihren Code runter geladen und es funktioniert auch was. Ich habe den INA226 Shunt aus gelötet und habe ein externen Shunt besorgt mit 100A mit 75mV und ich glaube der hat 0,5 Ohm (ein Kreis mit 0,5) . Was ich noch nicht Verstanden habe wo kann ich das einstellen das Ihr Code auch übernimmt, ich habe zwar das mit dem Befehl gelesen „setResistorRange(0.005, 10.0)“ aber sehr wahrscheinlich nicht verstanden. Ich habe den Befehl nicht einbauen können. Eine weitere Frage ist, kann ich mit dieser Konstellation ein LIFEPO4 12 Volt 275 ah Akku überhobt Überwachen?
    Ich hoffe sie können mir helfen.
    Viele Grüße aus Wuppertal

    1. Hallo Herr Brakel, mit der Bibliothek laden Sie auch den Beispielsketch Continuous_With_Resistor_Value.ino herunter. Den nehmen Sie als Basis. Als Parameter für die setResistorRange() Funktion tragen Sie den Widerstandswert ihres Shunts ein. Als zweiten Parameter wählen Sie den maximal zu erwartenden Strom. Wenn Ihr Shunt einen Widerstand von 0.5 Ohm hätte und 100 A gehen durch, dann würde er 50 Watt produzieren. Das wäre eher eine Heizung als ein Shunt. Ich gehe eher davon aus, dass er bei 100 A einen Spannungsabfall von 75mV hat. Das heißt er hätte einen Widerstand von 0,75 Milliohm. Sie würden also als ersten Parameter 0.00075 eingeben. Was Sie als maximalen Strom erwarten, das müssen Sie selbst überschlagen. 12 Volt sind kein Problem, der INA226 kann bis 36 Volt vertragen. Die Amperestunden spielen keine Rolle, nur der Strom interessiert. 275 Ah – das ist aber schon gewaltig.
      12 Volt sind zwar nicht viel, aber Lithiumakkus sind nicht ungefährlich. Und bei hohen Strömen und unterdimensionierten Leitungen kann es heiß werden – im Zweifelsfall sollten sie ihre Konstruktion durch einen Elektriker prüfen lassen, insbesondere wenn alles unbeaufsichtigt läuft.

  22. Hallo Wolfgang
    Vielen Dank für die coole Library! Sie funktioniert bei mir auch mit negativen Strömen einwandfrei.

    Allerdings habe ich ein kleines Problem: Ich möchte den Alert dazu nutzen, mit einem Transistor die Stromzufuhr zum Mikrocontroller überhaupt erst zu öffnen. Das funktioniert elektrisch alles einwandfrei.
    Ich nutze dein Beispiel 5 ohne enableAlertLatch().
    Das Problem ist nun, dass wenn der Mikrocontroller mit Strom versorgt wird,
    ina226.init();
    ina226.setAlertType(POWER_OVER, 100.0);
    ausgeführt wird, wodurch der Alert aber offenbar wieder ausgeschaltet wird. Obwohl Last 1 die den Alarm ausgelöst hat weiterhin mehr als 100mW Leistung zieht. Das wiederum kappt dann die Stromversorgung gleich wieder. Auch ina226.readAndClearFlags(); brachte keine Abhilfe.
    Erst wenn ich eine zusätzliche Last 2 anhänge, wird der Alarm wieder ausgelöst. Hänge ich die zusätzliche Last 2 wieder ab, bleibt der Alarm nun aktiv wegen Last 1.

    Siehst du eine Möglichkeit, dass der Alert eingeschaltet bleibt und nicht erst auf einen neuen Event warten muss?

    Besten Dank für deine Hilfe
    Silvan

    1. Hallo, ist immer ein bisschen schwierig aus der Entfernung. Bei so etwas probiere ich normalerweise ein bisschen herum. Was immer wieder eine Fehlerquelle ist: der INA226 lst einen Alarm aus und dadurch wird ein Interrupt am Microcontroller ausgelöst. Man schaltet den Interrupt aus (detachInterrupt()), behandelt den Interrupt (wg. event == true), und aktiviert die Interruptfunktion wieder. Wenn aber nun die Interruptbedingung die ganze Zeit erhalten bleibt, bleibt auch der Alarmpin des INA226 auf LOW (also ausgelöster Alarm). Nachdem du die Interruptfunktion wieder aktiviert hast, wartet der Interruptpin des Microcontrollers auf ein Falling. Allerdings ist er ja schon LOW, d.h. du kannst lange warten….
      Könnte es so etwas sein? Kannst du vielleicht mal anstelle mit FALLING als Interruptbedingung mit LOW experimentieren? VG, Wolfgang

    2. Hallo Wolfgang
      Danke für deine Antwort. Ich bin an einer PowerBank dran, die erkennt wenn ein Verbraucher angeschlossen wird und dadurch dann einen Arduino mit Strom versorgt, dass dieser wiederum ein paar Neopixels ansteuern kann. Der Arduino braucht aber zu viel Strom um ihn permanent an der Batterie zu betreiben.

      Das mit den Interrupts habe ich gesehen. Daher habe ich sie gar nicht verwendet und mit polling gearbeitet: alle paar Sekunden geschaut ob der Pin noch low ist. Wenn ja, dann den Alert mit ina226.readAndClearFlags(); gelöscht. Er ist natürlich wie du richtig gesagt hast gleich wieder aktiviert worden. Wird der Verbraucher aber abgehängt, wird der Alert nach spätestens einem Zyklus wirklich gelöscht, da die Alarmbedingung (over power) nicht mehr vorhanden ist.

      Ich habe gerade eben noch eine leicht elegantere Lösung gefunden. Und zwar kann der INA226 offenbar auch ohne Initialisierung genutzt werden (Seite 16 ganz unten im Datenblatt).
      Mit der Bus-Spannung und dem verwendeten Shunt-Widerstand kann man sich den Strom und die Leistung auch ausrechnen. Die anderen Werte in deinem Beispiel (Strom, Power) sind dann „inf“ oder = 0.
      Das ist zwar nicht sehr genau, aber man killt nicht mit jedem Initialisieren die Programmierung des Alerts. Die Alert-Programmierung bzw. der Init muss natürlich 1x gemacht werden. Da mein INA226 danach aber permanent an der Batterie hängt, geht diese nicht mehr verloren. Ich darf nur nicht bei jedem Neustart des Arduinos, hervorgerufen durch einen Alert, das Init durchführen.

      Falls du noch eine elegantere Methode weisst wie man verhindern kann, dass die Initialisierung auch die Alarmprogrammierung resetet, lass mich diese doch bitte trotzdem noch wissen.
      Danke und Gruss
      Silvan

  23. Hallo Wolle,

    sehr schöner Beitrag!
    Aber wie kann ich mit dem INA226 auch negative Spannungen/Ströme messen?
    Dann müsste die Beschaltung doch eine andere sein, oder?

    Gruß
    Wölle

    1. Hallo Wölle,

      danke für das Lob. Es müsste auch anders herum gehen. Die Register für die Shuntspannung und die Ströme sind vorzeichenbehaftet. Es sollte also funktionieren. Nur die Leistungsmessung dürfte nicht mehr funktionieren, wenn du den Pin nicht auf die Eingangsseite des Verbrauchers umhängst.

      VG, Wolle

      PS: Sieht immer wieder skurril aus, wenn Wölle an Wolle schreibt!

  24. Du kannst die Shunts ziemlich leicht austauschen: einfach genug Zinn dazu geben, dan die zwei seiten schnell hintereinander (oder beide zusammen flach mit der Lötspitze) erhitzen und den SMD teil zur Seite schieben.
    Geht eigentlich ganz flott.
    Da kann man einen R010 Shunt anstelle löten oder die Stelle leerlassen und ein externes großes 0.001 Ohm Shunt verbauen. Ist dann 80Ampere genug?
    😉

    1. Hi Laszlo, danke für den Hinweis! Irgendwann wird der Strom vielleicht für die Leiterbahn zum Shunt auf dem Modul ein Problem, wenn der Produzent gespart hat. Dann müsste man vielleicht doch lieber extern gehen oder eine separate Zuleitung löten.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert