Präzise analoge Spannungsmessungen mit dem Arduino anhand einer Referenzspannung messen
Mikrocontroller wie der ATMEGA328P des Arduinos besitzen analoge Eingänge, welche zur Spannungsmessung verwendet werden können. Über die Funktion analogRead() lässt sich die Spannung an einem analogen Eingang in einen digitalen Wert zwischen 0 und 1023 abbilden. Dieser Bereich entspricht der Auflösung des ADCs. Für den Arduino UNO beträgt die Auslösung 10 Bit. ()
Ein Minimalbeispiels zum lesen der Spannung am Pin A0 sieht wie folgt aus:
void setup() { // initialisierung der seriellen Kommunikationsschnittstelle mit 9600 bits pro Sekunde Serial.begin(9600); } // Hauptschleife, welche endlos ausgeführt wird void loop() { // Lesen des Eingangs am analogen Pin A0: int sensorValue = analogRead(A0); // Umrechnung des Analogwertes (welcher von 0 bis 1023 reicht) in eine Spannung von (0V bis 5V): float voltage = sensorValue * (5.0 / 1023.0); // Ausgabe des Wertes über die serielle Schnittstelle Serial.println(voltage);
Dies lässt vermuten, dass ein Wert von 0 einem Eingang von 0,000 V und 1023 einer Eingangsspannung von genau 5,000 V entspricht. Das ist nicht ganz richtig.
Der Arduino-Mikrocontroller ist mit einem stufenweisen Analog-Digital-Wandler (ADC) ausgestattet, der die folgende Spezifikation hat:
- Auflösung: 10 bit
- Integrale Nichtlinearität: 1 LSB (Least Significant Bit) niedrigstwertiges Bit
- Absolute Messgenauigkeit: ± 2 LSB
- Konvertierungszeit: 13 – 260μs
- Eingangswiderstand: Rin = 100 MOhm
- Eingangswiderstand der Referenzspannung: Rref = 32 kOhm
Diese Spezifikationen sagen uns, dass der Arduino in der Lage ist, Spannungen mit einer Genauigkeit von ± 2 LSB zu messen.
Der maximale Fehler beträgt also 2 Bit (4 dezimal) von insgesamt 10 Bit (1024 dezimal).
Die ungünstigste Abweichung des Wandlers beträgt also 4 / 1024 oder 1 / 256 bzw. 0,39%.
Jedoch hängt die Grenze der Messgenauigkeit von der verwendeten Spannungsreferenz ab.
Der Arduino hat eine eigenen Spannungsreferenzen – aber sie ist nicht sehr genau.
Der Chip ist – je nach Typ – mit einer der folgenden Referenzspannungen ausgestattet:
DEFAULT: die Standard-Analogreferenz von 5 Volt (bei 5 V Arduino-Boards) oder 3,3 Volt (bei 3,3 V Arduino-Boards).
INTERN: eine eingebaute Referenz, mit 1,1 Volt beim ATmega168 oder ATmega328 und 2,56 Volt beim ATmega8 (beim Arduino Mega nicht verfügbar).
INTERNAL1V1: Vint1 – eine eingebaute 1,1V Referenz (nur Arduino Mega)
INTERNAL2V56: Vint2 – eine eingebaute 2,56V Referenz (nur Arduino Mega)
EXTERN: die am AREF-Pin anliegende Spannung (von 0 bis 5 V)
Die Genauigkeit dieser “Referenzspannungen” ist jedoch sehr eingeschränkt:
- DEFAULT: hängt von der Spannungsversorgung über USB ab. USB2 ist für Spannungen von 4,4 V bis 5,25 V definiert.
- Vint 1 = 1,10 V tatsächlich 1,00 bis 1,20 V
- Vint 2 = 2,56 V tatsächlich 2,40 bis 2,80 V
Die Genauigkeit der Referenz, gegen welche die Spannung gemessen wird, ist – unter Verwendung einer der obigen Referenzen – bestenfalls nur – viel schlechter als die 0,25 % des ADCs.
Bezogen auf die internen Referenzspannungen besteht die Möglichkeit diese einmalig zu Messen und diesen zur Kompensation zu nutzen.
Zur Bestimmung der realen internen Referenzspannung kann folgender Code auf dem Arduino gespielt und die Referenz dann mit einem Multimeter zwischen GND und dem AREF gemessen werden.
void setup() { analogReference(INTERNAL); } void loop() { analogRead(A0) }
Die Formel mit der eingebauten real gemessenen Referenz (Ref) lautet dann wie folgt:
Mit der internen Referenzspannung lässt sich nun sogar die Veränderung in der Versorgungsspannung mit folgendem Code bestimmen:
long readVcc() { long result; // Auslesen der 1,1V internen referenz gegenüber AVcc ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Warte, bis sich Vref stabilisiert ADCSRA |= _BV(ADSC); // Umwandlung while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = 1125300L / result; // rückrechnen von AVcc in mV return result; } void setup() { Serial.begin(9600); } void loop() { Serial.println( readVcc(), DEC ); delay(1000); }
Für genauere Messungen benötigen wir eine genauere Referenzspannung.
Die LM4040 ist eine Spannungsreferenzdiode, und wenn diese über einen Widerstand an die “5 V”-Versorgung angeschlossen ist, so dass ein Strom von >100 uA und <15mA durch die Diode fließt, liefert diese eine Spannung von 4,096 V ± 0,2%.
Der Eingangswiderstand der Referenzklemme beträgt 32kOhm
Dann ist
Wenn der minimale Diodenstrom 0,4 mA beträgt, dann ist
Die minimale Spannung von einem USB-Port beträgt 4,4 V, also
Der maximal fließende Strom beträgt damit bei 5,25V: .
Mit dieser Referenzspannung können Spannungsmessungen mit einer Genauigkeit von 0,25% durchgeführt werden. Als Alternative liefert der MCP1541 die gleiche 4,096V Referenzspannung, während der MCP1525 eine 2,50V Referenz liefert und einen Widerstand von etwa 3,3 kOhm benötigt.
Man kann auch mit analogReference(INTERN); oder analogReference(INTERNAL1V1); die Referenzspannung auf 1,1 Volt umstellen,
und anschließend an AREF mit einem Multimeter ihres Vertrauens die Spannung messen.
Diese kann dann im Programm als Konstante eingegeben werden.
Der IC misst bis zur Referenzspannung von 1,1 Volt, der Eingang darf nicht mehr als AVCC oder 5 Volt sein.
Während des Messens sollte man versuchen die anderen I/O Pins ruhig zu halten.
Ein 100nF an AREF und AVCC kann nicht schaden.
Wer den IC auf ein eigenes Board setzt kann AVCC mit einer Spule und Kondensator 100nF die Versorgungsspannung stabilisieren.
Danke für den interessanten Beitrag. Ich habe hier gerade ein WEMOS D1 Mini und frag mich ob man die Genauigkeit hier auch steigern kann? Einen ARef Pin gibt es hier ja nicht. Das einzige was ich mir vorstellen könnte ist, die Versorgungsspannung entsprechend zu stabilisieren (wobei ich hier ein ATX Netzteil verwende, dass bestimmt schon eine gute Spannungsversorgung liefert).
Grüß Tobi