Stromsensor selber bauen

Über den Beitrag

In vorherigen Beiträgen hatte ich die Strom- und Leistungssensoren INA219 und INA226 vorgestellt. Diese funktionieren nach dem einfachen Prinzip, dass der zu messende Strom durch einen niederohmigen Widerstand (Shunt) geleitet wird. Die Stromstärke ergibt sich nach dem Ohmschen Gesetz aus dem Spannungsabfall. Der Gedanke liegt nahe, dass man so einen Stromsensor doch auch selber bauen könnte und genau darum geht es in diesem Beitrag.

Die einzige Hürde liegt in der Messung der geringen Spannungsabfälle. Bei den zuvor behandelten Modulen hatte der Shunt einen Widerstandswert von 0,1 Ohm. Selbst bei einem recht hohen Strom von zum Beispiel einem Ampere liegt der Spannungsabfall gerade mal bei einhundert Millivolt. Eine direkte Messung mit dem A/D-Wandler des Arduino UNO wäre deshalb viel zu grob.

Also muss das Spannungssignal verstärkt werden. Ich habe zwei Wege ausprobiert:

  • Verstärkung und A/D-Wandlung über den ADS1115.
  • Verstärkung mit einem Operationsverstärker (OpAmp), A/D-Wandlung über den Arduino.

Auswahl und Verwendung des Shunts

Qual der Wahl

Als Widerstandsgröße habe ich – wie beim INA219 und INA226 – 0,1 Ohm gewählt. Je kleiner der Widerstand, desto kleiner das Signal. Je größer der Widerstand, desto größer der Eingriff in das zu messende System. Die Auswahl ist also immer ein Kompromiss.

Für die Messung sehr großer Ströme könnt ihr eigens dafür ausgelegte Shunt Widerstände erwerben (z. B. hier). Ich habe mich für einen klassischen Metallschicht-Widerstand entschieden, allerdings in einer größeren Ausführung, die bis 2 Watt belastbar ist. Normalerweise haben Widerstände eine typische Belastbarkeit von 0,25 Watt.

0,1 Ohm Shuntwiderstand für den Stromsensor
Oben: Widerstand 0,1 Ohm, 2 Watt, unten: im Vergleich ein 0,25 Watt Widerstand

Einbau des Shunts

Bei meinen ersten Versuchen zum Bau eines Stromsensors war ich zunächst enttäuscht, da ich keine reproduzierbare Messwerte ermitteln konnte. Der Grund dafür war, dass der Kontakt zwischen meinem Shunt und dem Breadboard einen signifikanten Widerstand darstellte. Ein kleines „Ruckeln“ am Shunt hat sofort die Messwerte verändert.  Normalerweise spielt der Kontaktwiderstand keine Rolle, aber bei 0,1 Ohm sieht das anders aus.

Als Lösung habe ich den Shunt fest auf einer Platine verlötet:

Verbauter Shunt: 2 Stromanschlüsse, 2 Anschlüsse für die Spannungsmessung
Verbauter Shunt: 2 Stromanschlüsse, 2 Anschlüsse für die Spannungsmessung

Den Rest habe ich mit Steckbrückenkabeln verbunden. Diese haben anscheinend niedrigere Kontaktwiderstände. Jedenfalls bekam ich danach sehr reproduzierbare Messwerte.

Stromsensor auf Basis des ADS1115

Den ADS1115 hatte ich in meinem letzten Beitrag vorgestellt. Meine Bibliothek dazu (ADS1115_WE) bekommt ihr hier auf Github oder direkt über die Bibliotheksverwaltung der Arduino IDE. Auf die Details gehe ich nicht nochmal ein, möchte aber noch einmal erwähnen, dass der ADS1115 einen internen Verstärker besitzt und über eine Auflösung von 16 Bit verfügt. Damit lassen sich auch kleine Spannungen sehr gut messen. 

Verschiedene ADS1115 Module für den Stromsensor
Verschiedene ADS1115 Module

Die Schaltung

Den ADS1115 habe ich mit den 5 Volt des Arduino UNO versorgt. Die Kommunikation erfolgt über I2C. Pullup-Widerstände für die I2C Leitungen brauchte ich nicht, das kann bei anderen Modulen aber anders sein.

Den Shunt habe ich vor den Verbraucher gesetzt (High-Side Konfiguration). Ihr könnt ihn natürlich auch dahinter setzen (Low-Side). Die Shuntspannung habe ich über die Kanäle A0 und A1 des ADS1115 erfasst. Den Spannungsabfall über dem Verbraucher (Busspannung) habe ich mit den Kanälen A2 und A3 gemessen. Mit dem Shuntstrom und der Busspannung lässt sich dann die Leistung des Verbrauchers ausrechnen.

Wenn ihr, so wie ich, eine separate Spannungsquelle für den Verbraucher verwendet, dann müsst ihr für eine gemeinsame Masse sorgen.

Achtung: die Spannung an den Eingängen A0 – A4 darf die Versorgungsspannung des ADS1115 um nicht mehr als 0,3 Volt überschreiten. In diesem Fall wären das 5,3 Volt. Wenn die Busspannung höher ist, müsst ihr noch geeignete Spannungsteiler vor die Eingänge (also hier A2 und A3) setzen! Ihr zerstört sonst den ADS1115!

Stromsensor auf Basis des ADS1115
Stromsensor auf Basis des ADS1115

Kalibrierung

Da wir nicht davon ausgehen können, dass unser Shunt einen Widerstand von exakt 0,1 Ohm hat, muss die Sensorschaltung kalibriert werden. Dafür habe ich vor den Shunt ein Multimeter für die Strommessung eingesetzt und die Shuntspannung für verschiedene Verbraucher ermittelt. Für kleine Ströme habe ich LEDs genommen, für etwas größere Ströme einen Gassensor (weil ich den gerade zur Hand hatte).  So sah das dann aus:

Breadboard Schaltung

Der Sketch zur Kalibrierung

Für die Kalibrierung ist nur die Shuntspannung von Interesse. Ich habe den kontinuierlichen Modus und die höchste Verstärkung (also die kleinste Voltage Range) gewählt.

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48

ADS1115_WE adc(I2C_ADDRESS);

void setup() {
  Wire.begin();
  Serial.begin(9600);
  if(!adc.init()){
    Serial.println("ADS1115 not connected!");
  }

  /* Set the voltage range of the ADC to adjust the gain
   * Please note that you must not apply more than VDD + 0.3V to the input pins!
   * 
   * ADS1115_RANGE_6144  ->  +/- 6144 mV
   * ADS1115_RANGE_4096  ->  +/- 4096 mV
   * ADS1115_RANGE_2048  ->  +/- 2048 mV (default)
   * ADS1115_RANGE_1024  ->  +/- 1024 mV
   * ADS1115_RANGE_0512  ->  +/- 512 mV
   * ADS1115_RANGE_0256  ->  +/- 256 mV
   */
  adc.setVoltageRange_mV(ADS1115_RANGE_0256); //comment line/change paramater to change range

  adc.setCompareChannels(ADS1115_COMP_0_1); //comment line/change paramater to change channel

  adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode

  Serial.println("Stromsensor - Shuntspannung");
  Serial.println();
}

void loop() {
  float voltage = 0.0;
  voltage = adc.getResult_mV(); // alternative: getResult_mV for Millivolt
  Serial.print("Shuntspannung [mV]: ");
  Serial.println(voltage);
  Serial.println("-------------------------------");
  delay(2000);
}

 

Das Ergebnis der Kalibrierung

Die Kalibrierung ergab eine schöne Ausgleichsgerade mit geringen Abweichungen.

Kalibrierwerte für den ADS1115 basierten Stromsensor
Messdaten für die Kalbrierung des Stromsensors

Der vollständige Sensorsketch

Mit dem Kalibrierfaktor (Verhältnis Strom / Shuntspannung = ca. 9,67) lassen sich dann unbekannte Stromstärken ermitteln. Die Leistung des Verbrauchers ergibt sich aus der Stromstärke I und der Busspannung UBus:

P_{V\!erbraucher}=I\cdot U_{Bus}

Da die Busspannung erheblich höher als die Shuntspannung ist, werden diese Messungen mit unterschiedlichen Verstärkungen durchgeführt.

Ich habe hier den „Single-Shot“ Modus (also Messung auf Anfrage) gewählt. Dieser Modus ist zum einen energetisch günstiger, zum anderen stellt er über die isBusy() Funktion sicher, dass man keinen veralteten Wert ausliest.

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48
ADS1115_WE adc(I2C_ADDRESS);

const float voltageToCurrent = 9.67;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  if(!adc.init()){
    Serial.println("ADS1115 not connected!");
  }

  /* Set the voltage range of the ADC to adjust the gain
   * Please note that you must not apply more than VDD + 0.3V to the input pins!
   * 
   * ADS1115_RANGE_6144  ->  +/- 6144 mV
   * ADS1115_RANGE_4096  ->  +/- 4096 mV
   * ADS1115_RANGE_2048  ->  +/- 2048 mV (default)
   * ADS1115_RANGE_1024  ->  +/- 1024 mV
   * ADS1115_RANGE_0512  ->  +/- 512 mV
   * ADS1115_RANGE_0256  ->  +/- 256 mV
   */
  //adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change paramater to change range

  /* Set the inputs to be compared
   *  
   *  ADS1115_COMP_0_1    ->  compares 0 with 1 (default)
   *  ADS1115_COMP_0_3    ->  compares 0 with 3
   *  ADS1115_COMP_1_3    ->  compares 1 with 3
   *  ADS1115_COMP_2_3    ->  compares 2 with 3
   *  ADS1115_COMP_0_GND  ->  compares 0 with GND
   *  ADS1115_COMP_1_GND  ->  compares 1 with GND
   *  ADS1115_COMP_2_GND  ->  compares 2 with GND
   *  ADS1115_COMP_3_GND  ->  compares 3 with GND
   */
  //adc.setCompareChannels(ADS1115_COMP_0_GND); //uncomment if you want to change the default

  Serial.println("Strom- und Leistungssensor mit ADS1115");
  Serial.println();
}

void loop() {
  float voltage = 0.0;

  adc.setCompareChannels(ADS1115_COMP_0_1);
  adc.setVoltageRange_mV(ADS1115_RANGE_0256);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_mV(); 
  Serial.print("Shuntspannung [mV]: ");
  Serial.println(voltage);

  float current_mA = voltage * voltageToCurrent;
  Serial.print("Busstrom      [mA]: ");
  Serial.println(current_mA);

  adc.setVoltageRange_mV(ADS1115_RANGE_6144);
  adc.setCompareChannels(ADS1115_COMP_2_3);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_V(); 
  Serial.print("Busspannung    [V]: ");
  Serial.println(voltage);

  float power_mW = voltage * current_mA;
  Serial.print("Leistung      [mW]: ");
  Serial.println(power_mW);

  Serial.println("-------------------------------");
  delay(2000);
}

 

Und so sieht die Ausgabe am seriellen Monitor aus:

Ausgabe von Stromsensor_ADS1115_komplett.ino
Ausgabe von Stromsensor_ADS1115_komplett.ino

Überwachung von Strömen

Der ADS1115 besitzt einen Alarm Pin, den ihr so konfigurieren könnt, dass er bei Überschreitung bestimmter Werte aktiviert wird. Wenn ihr den Alarm Pin mit einem Interrupt Pin des Arduino verbindet, könnt ihr so ganz bequem Ströme überwachen. Ihr habt damit (fast) die volle Funktionalität eines INA226 Stromsensors. Näheres zur Programmierung des Alarm Pins findet ihr in meinem Beitrag zum ADS1115.

Stromsensor mit Operationsverstärker

Was macht ein Operationsverstärker?

Operationsverstärker, schematisch
Operationsverstärker, schematisch

Operationsverstärker (Operational Amplifiers, kurz: OpAmps) sind ausgesprochen vielfältig einsetzbare Bauteile, über die sich ganze Bücher schreiben lassen. Ich will deswegen gar nicht erst versuchen, hier so etwas eine Einführung zu geben. Als absolutes Minimum aber solltet ihr wissen:

  • OpAmps dienen der Spannungsverstärkung.
  • Sie besitzen einen invertierenden („-„) Eingang, einen nicht-invertierenden Eingang („+“) und einen Ausgang (VOUT).
  • Die Spannungsversorgung ist meistens symmetrisch (V+ / V-), es gibt aber auch Anwendungen mit V+ / GND.
    • Wir beschäftigen uns hier mit Letzteren.
  • Der OpAmp erhält seine Funktion erst durch Beschaltung mit weiteren Bauteilen.
  • OpAmps können als invertierende oder nicht invertierende Verstärker, als Differenzverstärker, Integrierverstärker, Summierverstärker, u.v.m. eingesetzt werden. 

Wenn ihr Einsteiger seid und mehr wissen wollt, empfehle ich diese Stelle im Netz.

Einige Vertreter

OpAmps gibt es verschiedenen Bauformen. Meistens werden sie als ICs angeboten, die mehrere OpAmps enthalten. Für den Beitrag habe den MCP6002, LM358 und den TLV2462 ausprobiert.

Es sei vorweggenommen, dass ich mit dem TLV2462 Probleme mit der Linearität bei kleinen Spannungen hatte.

OpAmps für den Stromsensor: TLV2462, LM358, MCP6002
OpAmps für den Stromsensor: TLV2462, LM358, MCP6002

Alle genannten Vertreter besitzen 2 OpAmps und haben dieselbe Pinbelegung: 

Pinout für den MCP6002, LM358 und TLV2462
Pinout für den MCP6002, LM358 und TLV2462

Der OpAmp als Differenzverstärker

Für die Verstärkung der Shuntspannung habe ich den OpAmp als Differenzverstärker eingesetzt. Um die Differenz zwischen zwei Spannungen V1 und V2 zu verstärken, wird der OpAmp folgendermaßen beschaltet:

Verstärkerschaltung für den Stromsensor: Differenzverstärker
Verstärkerschaltung für den Stromsensor: Differenzverstärker

Wenn R1 gleich R2 ist und R3 gleich R4, dann gilt für VOUT:

V_{OUT}=\frac{R_3}{R_1}\cdot(V_2-V_1)

Warum das so ist, könnt ihr hier nachlesen. Als R1 bzw. R2 habe ich 3,9 kOhm gewählt 330 kOhm als R3 bzw. R4. Damit beträgt der Verstärkungsfaktor theoretisch 84,6. Bei einem Messbereich bis 5 Volt kann man damit Shuntspannungen von bis zu 5 V / 84,6 = 59,1 mV erfassen. Das wiederum entspricht einem maximalen Strom von 591 mA.

Für diejenigen, die sich mit OpAmps auskennen: ich hatte zunächst versucht, den OpAmp als nicht-invertierenden Verstärker, so wie hier beschrieben, einzusetzen. Damit habe ich keine stabilen Verstärkungen hinbekommen und die Verstärkungen waren wesentlich höher als berechnet – hat jemand eine Idee, woran das liegen könnte? Wie auch immer funktioniert die Differenzverstärkerschaltung sehr gut.

Kalibrierung des OpAmp basierten Stromsensors

Schaltung

Zur Kalibrierung müssen wir auch hier wieder praktisch ermitteln, wie die verstärkte Shuntspannung von der Stromstärke abhängt. Dazu braucht ihr also ein Gerät zur Spannungs- und eines zur Strommessung. Ich habe mein Multimeter zur Strommessung eingesetzt und zur Spannungsmessung den ADS1115. Natürlich hätte ich auch direkt den A/D-Wandler des Arduino zur Spannungsmessung verwenden können. Mich hat aber interessiert, ob auch bei kleinen Spannungen eine lineare Abhängigkeit vorliegt. Und dazu wollte ich die hohe Auflösung des ADS1115 nutzen. Noch einfacher wäre es, zwei Multimeter zu verwenden. Aber die hat ja nicht jeder.

Der Shunt ist diesmal hinter dem Verbraucher positioniert (Low-Side). Alle Komponenten haben dabei eine gemeinsame Masse.

Mit einer getrennten Stromquelle für den Verbraucher und vor allem mit einer getrennten Masse lässt sich auch die High-Side Konfiguration realisieren. VCC des Verbrauchers verbindet man für diesen Fall mit der Masse der restlichen Schaltung. Das Problem ist dabei jedoch die Messung der Busspannung, die dann im negativen Bereich liegt. 

Stromsensor Kalibrierung mit dem ADS1115
Stromsensor Kalibrierung mit dem ADS1115

Als Testverbraucher mit unterschiedlichen Stromstärken habe ich wieder ausgewählt, was auf meinem Tisch herumlag.

Sketch für die Kalibrierung

Der Sketch ist spezifisch für meine Art der Kalibrierung. Wenn ihr mehrere Multimeter besitzt, braucht ihr gar keinen Sketch, sondern messt direkt.

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48

ADS1115_WE adc(I2C_ADDRESS);

void setup() {
  Wire.begin();
  Serial.begin(9600);
  if(!adc.init()){
    Serial.println("ADS1115 not connected!");
  }

  /* Set the voltage range of the ADC to adjust the gain
   * Please note that you must not apply more than VDD + 0.3V to the input pins!
   * 
   * ADS1115_RANGE_6144  ->  +/- 6144 mV
   * ADS1115_RANGE_4096  ->  +/- 4096 mV
   * ADS1115_RANGE_2048  ->  +/- 2048 mV (default)
   * ADS1115_RANGE_1024  ->  +/- 1024 mV
   * ADS1115_RANGE_0512  ->  +/- 512 mV
   * ADS1115_RANGE_0256  ->  +/- 256 mV
   */
  adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change paramater to change range

  adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change paramater to change channel

  adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change paramater to change mode

  Serial.println("Stromsensor - Shuntspannung am Opamp");
  Serial.println();
}

void loop() {
  float voltage = 0.0;
  voltage = adc.getResult_mV(); 
  Serial.print("Shuntspannung [mV]: ");
  Serial.println(voltage);
  Serial.println("-------------------------------");
  delay(2000);
}

 

Ergebnis der Kalibrierung

Die ermittelten Messwerte lagen alle sehr nahe an einer Ausgleichsgeraden, zumindest gilt das für den MCP6002 (Ergebnisse unten abgebildet) und den LM358. Bei 0 Milliampere sollte die verstärkte Shuntspannung 0 Millivolt betragen. Die OpAmps haben aber eine Offsetspannung an VOUT, die man entsprechend herausrechnen muss.

Messdaten für die Kalbrierung des Stromsensors
Messdaten für die Kalbrierung des Stromsensors (ermittelt mit dem MCP6002)

Beim TLV2462 knickten die Messwerte bei kleinen Spannungen Richtung Nullpunkt weg. So als ob die Offsetspannung verschwindet. Warum das so ist, weiß ich nicht – ich hatte keine Lust weiter nachzuforschen.

Der vollständige Stromsensor

Der Rest ist einfach. Die verstärkte Shuntspannung könnt ihr nun direkt am Arduino auslesen und in den Strom umrechnen. Die Busspannung ist normalerweise so hoch, dass ihr sie nicht verstärken müsst.

Wenn ihr die Busspannung an VCC des Verbrauchers auslest, dann ist da auch noch ein kleiner Anteil Shuntspannung drin. In erster Näherung die das der Strom, multipliziert mit 0,1. Zu guter Letzt könnt ihr dann problemlos die Leistung errechnen.

Hier der Vollständigkeit halber die Schaltung:

Der OpAmp basierte Stromsensor
Der OpAmp basierte Stromsensor

Und hier noch der vollständige Sketch:

const float calibrationFactor = 8.77;
const int offsetValue = 15;
const int opampVOutPin = A0;
const int busAnalogPin = A1;

void setup(){
  Serial.begin(9600);
  Serial.println("Stromsensor mit OpAmp");
}

void loop(){
 
  float amplifiedShuntVoltage_mV = (analogRead(opampVOutPin) - offsetValue) * 5.0 / 1.024;
  Serial.print("Verstärkte Shuntspannung [mV]: ");
  Serial.println(amplifiedShuntVoltage_mV);

  float current_mA = amplifiedShuntVoltage_mV / calibrationFactor; 
  Serial.print("Strom [mA]                   : ");
  Serial.println(current_mA);
  
  // Wir ziehen die Shuntspannung ab, um die reine Busspannung zu haben
  float busVoltage_V = (analogRead(busAnalogPin) * 5.0 / 1024) - (current_mA * 0.1 / 1000);
  Serial.print("Busspannung [V]              : ");
  Serial.println(busVoltage_V);

  float power_mW = busVoltage_V * current_mA;
  Serial.print("Leistung [mW]                : ");
  Serial.println(power_mW);

  Serial.println("-------------------------------");
  delay(2000); 
}

 

Danksagung

Das schon mehrfach verwendete Bild des Strommessers für das Beitragsbild stammt aus dem Free-Photos Fundus von Pixabay. Die meisten Werkzeuge habe ich Clker-Free-Vector-Images zu verdanken. Die Bohrmschine stammt von Francis Ray auf Pixabay.

4 thoughts on “Stromsensor selber bauen

    1. Hallo Manfred, schön wieder von dir zu hören. Vielen Dank für den Link – das ist dann die fortgeschrittene Variante. Passt gut zum Beitrag! VG, Wolfgang

Schreibe einen Kommentar

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