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. (2^{10}=1024)

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

http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf

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 \frac{(5,25 - 5,0)}{5,0} * 100 = 5 \% – 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:

ADC-Spannung = (\frac{ADCval}{1024})*Ref

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 I_{ref} = \frac{4.096 V} {32 kOhm} = 0,128 mA
Wenn der minimale Diodenstrom 0,4 mA beträgt, dann ist I_t = 0,4mA + 0,128mA = 0,528mA
Die minimale Spannung von einem USB-Port beträgt 4,4 V, also R = \frac{(4,40V - 4,096V)}  {0,528A} \approx 560 Ohm
Der maximal fließende Strom beträgt damit bei 5,25V: \frac{(5,25V-4,096V)}{560 Ohm} \approx 2,1 mA.

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.