ACS712 Stromsensor

Über den Beitrag

Wenn ihr die Begriffe „Stromsensor“ und „Arduino“ in Google sucht, werdet ihr vor allem auf den ACS712 treffen. Nachdem ich über die Stromsensormodule INA219, INA226 und den Eigenbau Stromsensor  berichtet habe, möchte ich mich jetzt diesem wahrscheinlich populärsten Stromsensor widmen.

Bei Stromstärken von unterhalb einem Ampere stößt der ACS712 in Kombination mit dem A/D-Wandler des Arduino UNO an seine Grenzen. Auf diesen Punkt gehe ich besonders ein und zeige wie ihr bessere Ergebnisse erhalten könnt. Zum Schluss erkläre ich dann noch, wie ihr den ACS712 als Leistungssensor einsetzen könnt.

Eigenschaften des ACS712 (Moduls)

Das Messprinzip des ACS712

ACS712 Modul

Der ACS712 bzw. das ACS712 Modul misst Ströme auf Basis des Hall-Effekts. In einem früheren Beitrag hatte ich schon einmal über Hall-Sensoren berichtet. Diese werden benutzt um Magnetfelder zu detektieren, bzw. um mithilfe von Magneten kontaktlose Schalter zu realisieren. Im ACS712 hingegen erzeugt der zu messende Strom ein Magnetfeld, das in eine Spannung umgewandelt wird, die ihr dann am Pin „Out“ abgreifen könnt.

Durch sein Messprinzip beeinflusst der ACS712 den zu messenden Strom noch weniger als die shuntbasierten Module aus meinen vorherigen Beiträgen. Der ohmsche Widerstand beträgt lediglich 1,2 Milliohm. Allerdings ist dafür die Empfindlichkeit nicht besonders hoch, außerdem verbraucht der ACS712 erheblich mehr Strom.

Je nach Beschaltung liefert der ACS712 IC eine Spannung zwischen 66 und 185 Millivolt pro Ampere. Auf dem Modul ist die Beschaltung vorgegeben. Alle Module, die ich ausprobiert oder in Online-Shops gesehen habe, haben die maximale Empfindlichkeit von 185 Millivolt pro Ampere implementiert. Mit dem blanken ACS712 IC seid ihr diesbezüglich freier. Ein weiterer Vorteil des blanken ICs ist, dass ihr die Filterfunktion (Pin 6 des ICs, siehe Datenblatt) kontrollieren könnt.

Technische Daten (Modul)

Hier die wichtigsten technischen Daten:

  • Spannungsversorgung an VCC/GND: 4.5 – 5.5 V.
  • Stromverbrauch des ACS712 ICs: ca. 10 mA.
    • Bedingt durch seine LED ist der Stromverbrauch des Moduls etwas höher: ca. 12 mA.
  • Empfindlichkeit des Moduls: 185 mV / A.
  • Linearitätsabweichung: 1.5 % (lt. Datenblatt).
  • 5 Ein-/Ausgänge:
    • VCC/GND Spannungsversorgung.
    • OUT: Signalspannung.
    • IN+ (oben rechts) / IN- (oben links): Ein- bzw. Ausgang für den zu messenden Strom.
  • Spannung an OUT bei 0 Ampere: VCC/2.

Die Signalspannung VOUT beträgt damit bei einer Versorgungsspannung VCC in Abhängigkeit vom zu messenden Strom I: 

V_{OUT}\,[\text{mV}]=185\,[\text{mV/A}]\cdot I\,[\text{A}]+\frac{VCC\,[\text{mV}]}{2}

Aufgelöst nach I:

I\, [\text{A}]=\frac{V_{OUT}-\frac{VCC}{2}}{185}

Der ACS712 „Quick and Dirty“

Wenn ihr den ACS712 mit dem Arduino auslesen wollt, dann könnt ihr ihn wie folgt anschließen:

Der ACS712 am Arduino UNO
Der ACS712 am Arduino UNO

Das ist die High-Side Konfiguration, d.h. der ACS712 sitzt an der V+ Seite des zu messenden Verbrauchers. Ihr könnt den ACS712 aber auch hinter dem Verbraucher auf die GND Seite setzen (Low-Side).

Dann habe ich mich zunächst um den Nullpunkt gekümmert, sprich die Spannung an OUT (im Fritzing Schema oben als Vo bezeichnet) bei null Ampere Stromfluss. Theoretisch sind das 2,5 Volt, d.h. ein analogRead(A0) sollte 1023/2 = 511 oder 512 liefern. Praktisch werdet ihr wahrscheinlich etwas weniger messen. Selbst unter der geringen „Last“ des ACS712 geht die durch den Arduino bereitgestellte Spannung schon um ein paar Millivolt herunter. Damit ist auch der Nullwert an OUT etwas geringer. Ich habe 510 ermittelt, allerdings um bis zu +/-3 Einheiten schwankend.

Da der Arduino eine Referenzspannung von 5 Volt hat und sein A/D-Wandler eine Auflösung von 10 Bit, gilt für die Spannung am Pin A0:

V_{\text{A0}}[\text{V}]=analogRead(\text{A0})\cdot\frac{5}{1023}

Eingesetzt in die Gleichung für die Stromstärke weiter oben ergibt sich folgender einfacher Sketch:

const int ACS712_Pin = A0;
const int zeroCurrentValue = 510;

void setup() {
  Serial.begin(9600);
  Serial.println("ACS712 - Basissketch");
}

void loop() {
  int rawValue= analogRead(ACS712_Pin);
  float current = (rawValue - zeroCurrentValue)*5.0/1.023/0.185;
  Serial.print("Strom [mA]: ");
  Serial.println(current);
  delay(2000);        
}

 

Damit erhielt ich bei null Ampere typischerweise Ergebnisse wie das folgende:

Ausgabe von ACS712_Quick_And_Dirty.ino

Das Ausmaß des Rauschens wäre selbst für Messungen im Ampere Bereich nicht gerade befriedigend. Die schwankenden Ergebnisse sind allerdings nicht nur dem ACS712 anzulasten. Was hier vor allem schwankt, ist der A/D-Wandler des Arduino UNO.  Nehmt einmal eine stabilisierte Stromquelle oder schlicht eine unbelastete Batterie und messt die Spannung über analogRead(). Ihr werdet feststellen, dass die ausgelesenen Werte um +/-2 bis 3 Einheiten schwanken. Eine Einheit entspricht 5000/1023 = ~4,888 Millivolt und das entspricht immerhin 4,888/0,185 = 26,42 Milliampere.

Verbesserung 1: Mittelwertbildung

Es liegt auf der Hand, dass man bei rauschenden Messergebnissen viele Werte misst und dann mittelt. Dazu habe ich zunächst den Nullwert genauer ermittelt (510.8). Dann habe ich den Sketch so verändert, dass  jeweils 50 Messergebnisse gemittelt werden:

const int ACS712_Pin = A0;
const float zeroCurrentValue = 510.8;  
void setup() {
  Serial.begin(9600);
  Serial.println("ACS712 - Stromsensor, Basissketch verbessert");
}

void loop() {
  long rawValue = 0;
  for(int i=0; i<50; i++){
    rawValue += analogRead(ACS712_Pin);
  }
  float rawVoltage = rawValue/50.0;
  float current = (rawVoltage - zeroCurrentValue)*5.0/1.023/0.185;
  Serial.print("Strom [mA]: ");
  Serial.println(current);
  delay(2000);        
}

 

Das Ergebnis sieht schon viel besser aus. Schwankungen lagen im Bereich von +/-10 Milliampere:

ACS712 - Ausgabe von ACS712_verbessert_duch_Mittelwerte.ino bei null Ampere
Ausgabe von ACS712_verbessert_duch_Mittelwerte.ino bei null Ampere

Bei Stromfluss bleibt die Schwankung bei ca. +/- 10 Milliampere, d.h. bei steigenden Strömen kommt sie prozentual weniger zum Tragen. Hier die Ergebnisse für einen Strom, den mir mein Multimeter und mein Labornetzteil als konstant 305 Milliampere angezeigt haben:

ACS712 - Ausgabe von ACS712_verbessert_duch_Mittelwerte.ino bei 305 mA
Ausgabe von ACS712_verbessert_duch_Mittelwerte.ino bei 305 mA

Und hier die Ergebnisse für tatsächliche 536 Milliampere:

ACS 712 - Ausgabe von ACS712_verbessert_duch_Mittelwerte.ino bei 536 mA
Ausgabe von ACS712_verbessert_duch_Mittelwerte.ino bei 536 mA

Tendenziell lagen die so ermittelten Messwerte im Durchschnitt etwas höher als der tatsächliche Strom. Der Faktor von 185 mV/A müsste entsprechend ein wenig nach oben korrigiert werden. Wegen der Schwankungen hatte ich aber keine Lust mehr, da eine Wissenschaft draus zu machen.

Verbesserung 2: Ein besserer A/D-Wandler

Im nächsten Schritt habe ich anstelle des Arduino A/D-Wandlers einen ADS1115 eingesetzt. Den ADS1115 und meine zugehörige Bibliothek habe ich hier beschrieben. Deshalb gehe ich in diesem Beitrag nicht noch einmal auf alle Details ein.

Der ADS1115 ist ein A/D-Wandler mit einer Auflösung von 16 Bit, er hat 4 Kanäle (A0 – A3) und einen internen Verstärker. Darüber hinaus bietet er die Möglichkeit, Spannungsdifferenzen zwischen den Kanälen zu messen. Das könnt ihr euch zunutze machen, indem ihr mit einem Spannungsteiler eine Referenzspannung von 2,5 Volt erzeugt und dann die Spannungsdifferenz zwischen Referenz (Kanal A1) und OUT Signal des ACS712 (Kanal A0) messt:

Der ACS712 mit ADS1115 am Arduino
Der ACS712 mit ADS1115 am Arduino

Bei null Ampere Stromfluss startet ihr auf diese Weise mit einer Spannungsdifferenz von ungefähr null Volt. Bei kleinen Strömen erhaltet ihr geringe Spannungen, die ihr mit dem ADS1115 verstärken könnt. 

ACHTUNG: ich komme später dazu, warum ich V+ des Verbrauchers an A2 angeschlossen habe. Wartet noch damit, vor allem wenn eure Stromquelle für den Verbraucher über 5 Volt erzeugt! 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 Versorgungsspannung für den Verbraucher höher ist, müsst ihr noch geeignete Spannungsteiler vor die Eingänge (also hier A2) setzen! Ihr zerstört sonst den ADS1115!

Überprüfung der Messwertschwankungen

Für einen ersten Eindruck habe ich mir die Schwankungen bei null Ampere Stromfluss angeschaut. Dazu habe ich den folgenden Sketch verwendet:

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48
const float zeroCurrentVoltage_mV = 0.0;

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

  /* 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_1); 

  Serial.println("ACS712 - Nullstrommessung mit ADS1115");
  Serial.println();
}

void loop() {
  float voltage = 0.0;
  
  for(int i=0; i<10; i++){
    adc.startSingleMeasurement();
    while(adc.isBusy()){}
    voltage += adc.getResult_mV();
  }
  
  voltage /= 10;
  voltage -= zeroCurrentVoltage_mV;
  float current = voltage/0.185;
  Serial.print("ADC712-Spannung [mV]: ");
  Serial.print(voltage);
  Serial.print("  /  Strom [mA]: ");
  Serial.println(current);
  delay(2000);
}

 

Ein paar Anmerkungen zu dem Sketch:

  • zeroCurrentVoltage_mV ist die Spannung zwischen OUT und der Referenzspannung bei null Ampere Strom. Ich habe den Wert erst einmal auf Null gesetzt, den Sketch laufen lassen, den tatsächlichen Wert ermittelt und ihn dann entsprechend eingesetzt (2.0 mV bei mir).
  • setVoltageRange(ADS1115_RANGE_0256) setzt den Spannungsmessbereich auf +/- 256 mV. Das entspricht der höchstmöglichen Verstärkung des ADS1115.
  • setCompareChannels(ADS1115_COMP_0_1) legt fest, dass die Spannungsdifferenz zwischen den Kanälen 0 und 1 gemessen wird.
  • getResult_mV() liefert das Ergebnis der Wandlung direkt in Millivolt.
  • Mit einer Mittelwertbildung aus zehn Messungen konnte ich eine für mich akzeptable Stabilität der Werte erreichen.

Hier das Ergebnis:

Ausgabe von ACS712_am_ADS1115_Basis.ino bei null Ampere
Ausgabe von ACS712_am_ADS1115_Basis.ino bei null Ampere

Das sieht doch schon nicht so schlecht aus, oder? Wenn man annimmt, dass die Steigung tatsächlich bei 185 mV/A liegt, ist der Sketch oben auch schon fertig einsetzbar.

Verbesserung 3: „Kalibrierung“ der Schaltung

Im nächsten Schritt habe ich mir angeschaut, wie die Abhängigkeit von Strom zu Spannung tatsächlich aussieht. Dazu habe ich verschiedene Verbraucher eingesetzt, den Strom mit meinem Multimeter gemessen und die Spannung mit dem Sketch ACS712_am_ADS1115_Basis.ino ermittelt. Dabei kam Folgendes heraus:

ACS712 - Tabelle 1: Strom vs. Spannung
Tabelle 1: Strom vs. Spannung

Hier grafisch dargestellt mit einer Ausgleichsgerade:

ACS712 - Ausgleichgerade für die Messwerte Strom vs. Spannung
Ausgleichgerade für die Messwerte Strom vs. Spannung

Die Messwerte lagen recht gut auf einer Ausgleichsgerade. Ich habe dann die Spannungswerte aus Tabelle 1 in die Gleichung für die Ausgleichsgerade eingesetzt. Die Ergebnisse findet ihr in der rechten Spalte der Tabelle 1. Sie geben einen Eindruck wie genau die Messung ist. Für eine akkurate Statistik bräuchte man noch mehr Werte, aber es lässt sich abschätzen, dass die Abweichung bei Stromstärken oberhalb von 1 Ampere auf unter 1 Prozent sinkt. 

Die Steigung der Ausgleichsgeraden beträgt 5,2788 mA/mV. Das entspricht 189,4 mV/A, was ein bisschen höher ist als die angegebenen 185 mV/A, aber nicht meilenweit entfernt.  

Verbesserung 4: Leistungssensor-Funktion

Falls ihr den beschriebenen Weg nachvollzieht, könntet ihr jetzt den letzten Sketch verbessern, indem ihr die Gleichung für die Ausgleichsgerade einsetzt. Aber vielleicht wollt ihr dem Projekt auch noch eine Funktion spendieren, mit der ihr die Leistung des Verbrauchers ermittelt. Hier kommt nun die Spannungsmessung an V+ des Verbrauchers (Busspannung) zum Tragen. An dieser Stelle möchte / muss ich nochmal darauf hinweisen, dass die Spannung an den Eingängen des ADS1115 die Betriebsspannung des ADS1115 um nicht mehr als 0,3 Volt übersteigen darf. Falls V+ größer ist, dann setzt Spannungsteiler ein.

Mithilfe der Spannung an V+ und dem Strom (Busstrom) könnt ihr die Leistung errechnen:

P_{V\!erbraucher}=U_{V_{+}}\,\cdot I_{Bus}

Und hier der komplette Sketch dazu:

#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_1024); //uncomment line / change parameter 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_1); // uncomment line / change parameter to change channels

  Serial.println("ACS712 - Strom- und Leistungssensorsketch");
  Serial.println();
}

void loop() {
  float voltage = 0.0;

  adc.setCompareChannels(ADS1115_COMP_0_1); // Channel 0 vs. 1
  adc.setVoltageRange_mV(ADS1115_RANGE_0512); // Limit: 512 mV
  
  for(int i=0; i<10; i++){
    adc.startSingleMeasurement();
    while(adc.isBusy()){}
    voltage += adc.getResult_mV();
  }
  voltage /= 10;
 
  Serial.print("V Out          [mV]: ");
  Serial.println(voltage);

  float current_mA = voltage * 5.28 + 10; // experimentell ermittelt
  Serial.print("Busstrom      [mA]: ");
  Serial.println(current_mA);
  
  adc.setVoltageRange_mV(ADS1115_RANGE_6144); // Limit: 6144 mV
  adc.setCompareChannels(ADS1115_COMP_2_GND); // Channel 2 vs. GND
  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);
}

 

Zwischen den Messungen der ACS712 Spannung und V+ schalte ich im obigen Sketch den Bereich um. Ich habe für die ACS712 Spannung den Bereich bis 512 mV gewählt. Eingesetzt in die Gleichung für die Ausgleichsgerade ergibt sich daraus ein maximaler Strom von ca. 2,7 Ampere. Wenn Ihr mehr braucht, dann erhöht den Bereich entsprechend.

Und so sieht dann die Ausgabe aus:

ACS712: Ausgabe von ACS712_Strom_und_Leistungssensor.ino
Ausgabe von ACS712_Strom_und_Leistungssensor.ino

Danksagung

Wie meistens, habe ich mich für Teile meines Beitragsbildes wieder bei Pixabay bedient:

4 thoughts on “ACS712 Stromsensor

  1. Hallo Wolle
    Wieder ein fundierter toller Bericht in der Kiste! Du brauchst langsam eine Suchfunktion..
    Darf man Wünsche reingeben? Die Strom- und Spannungsmesserei ist ja langsam gründlichst durchgenommen…
    Ja? Die „Time of Flight“ Lidar Sensoren von beispielsweise STE (V53L1X) wären mein Vorschlag. Spektakuläre Technik & die dazu erhältlichen Libs könnten auch ein gewissenhaftes Reviewing brauchen wie es Du drauf hast!
    Thx für Deinen Blog

    1. Oh vielen Dank, das ist sehr nett. Ich habe zwei gute und eine schlechte Nachricht. Erst die schlechte: ich wollte das Thema Stromsensoren noch vervollständigen, es kommt also noch was ….ich weiß das ist vielleicht auf Dauer etwas langweilig….
      Dann die erste gute Nachricht: ja, gerne darf man sich was wünschen, ich sehr froh Anregungen zu bekommen. Und jetzt die noch bessere: einen Beitrag über die Time of Flight Sensoren habe ich schon geschrieben:
      https://wolles-elektronikkiste.de/vl53l0x-und-vl53l1x-tof-abstandssensoren

  2. Haha…mein Gott, ich war blind….und..na ja, man wird nicht jünger….den hab ich ja bei Dir schon durchgelesen damals…

Schreibe einen Kommentar

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