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.

Es ist sehr schade, dass das INA226 Modul keinen kleineren Shunt besitzt, denn mit 800 mA ist die Stromobergrenze nicht sehr üppig. Das ist wie Fahren mit angezogener Handbremse. Warum dieses Stromlimit nur ein Viertel des INA219 Limits bei gleichem Shunt beträgt, erläutere ich später. 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
  
  /* Set Current Range
    * Mode *   * Max Current *
     MA_400          400 mA
     MA_800          800 mA (default)
  */
  //ina226.setCurrentRange(MA_800); // choose gain 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 vier 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.
  4. Strombereich über setCurrentRange() einstellen
    • Ihr könnt 400 oder 800 mA als maximalen Strom einstellen. Je kleiner der Strombereich, desto höher ist die Auflösung für den Strom und die Leistung.

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
  
  /* Set Current Range
    * Mode *   * Max Current *
     MA_400          400 mA
     MA_800          800 mA (default)
  */
  //ina226.setCurrentRange(MA_800); // choose gain 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
  
  /* Set Current Range
    * Mode *   * Max Current *
     MA_400          400 mA
     MA_800          800 mA (default)
  */
  //ina226.setCurrentRange(MA_800); // choose gain 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
  
  /* Set Current Range
    * Mode *   * Max Current *
     MA_400          400 mA
     MA_800          800 mA (default)
  */
  //ina226.setCurrentRange(MA_800); // choose gain 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.

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 bisschen 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 0,8 und 0,4 A gewählt. 0,8 A, weil dieser Wert, wie weiter oben erklärt, der maximale Strom des Moduls ist und 0,4 A, um eine Abstufung zu haben und die dadurch höhere Auflösung nutzen zu können. Die Formel für CAL ergibt einen „krummen“ Wert, den man nach oben hin aufrundet, um in der Folge handlichere Zahlen zu haben. 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.

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 die implementierten Strombereiche
Werte für die implementierten Strombereiche

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.

22 thoughts on “INA226 Strom- und Leistungssensor

  1. 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

  2. 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.

  3. 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

  4. 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);

  5. 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

  6. 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…

  7. 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.

  8. 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

  9. 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!

  10. 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.