Messungenauigkeit Spannungsmessungen über Analog In

Hallo Arduino Nutzer!

Ich versuche mit meinem Arduino Uno Spannungen zu messen. Zum einen ca. 12 V und zum anderen 0-4 V. Aufbau mit Spannungsteiler ist klar und funktioniert auch. Allerdings sind meine Messungen zu ungenau (bei 12 V habe ich im Mittel ca. 0,3 V Abweichung). Die Verstärkung durch den Spannungsteiler habe ich abgeglichen (Bauteiltoleranzen der Widerstände berücksichtigt). Temperatureinflüsse schließe ich aus, da Messungen bei konstanter Temperatur. Die Fehlerquelle scheint die Umrechnung von Bit in Volt zu sein.

Es muss ja mittels Schlussrechnung bzw. Geradengleichung von Bit in Volt umgerechnet werden. In sämtlichen Forumsbeiträgen wird die Referenzspannung dazu mit 5 V angegeben. Also 1023 Bit entsprechen 5 V. Somit ergibt sich die gesuchte Spannung U=Bit*5/1023 oder mit dem map-Befehl. Sind das allerdings wirklich immer 5 V? Müsste das nicht die aktuelle Boardspannung des Arduino sein? Ich habe folgende Code zur Ermittlung der Boardspannung verwendet.

long readVcc() { long result; // Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert

while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = 1126400L / result; // Back-calculate AVcc in mV

return result; }

void setup() { Serial.begin(9600); }

void loop() { Serial.println( readVcc(), DEC ); delay(1000); }

Damit wurde die Boardspannung mit 4,36 V berechnet. Mit zwei unterschiedlichen Multimetern betrug die Boardspannung allerdings 4,53 V. Verwende ich die 4,53 V in der Schlussrechnung ist das Ergebnis deutlich genauer.

Nun zu meinen Fragen:

Schlussrechnung mit 5 V oder aktueller Boardspannung?

Kann ich nach einmaligen Messen der 4,53 V ausgehen, dass diese Boardspannung bei meinem Arduino immer gleich bleibt (auch bei leicht schwankender Versorgungsspannung) und diesen Wert als Konstante in meine Schlussrechnung nehmen?

Warum kommt es bei obigem Code zu solcher Abweichung der Boardspannung?

Gibt es alternativen zur Ermittlung der exakten Boardspannung?

Bin für Tipps dankbar! LG

Tipp 1:
Verwende die interne Referenz.
Diese hat eine Exemplarstreuung von ca 10%.
Ist aber stabil.
Stabiler, als es die Versorgungsspannung je sein wird.

Tipp 2:
Wenn du dann noch eine Temperaturkompensation brauchst, viele AVR haben einen eingebauten Temperatursensor.

Damit wurde die Boardspannung mit 4,36 V berechnet. Mit zwei unterschiedlichen Multimetern betrug die Boardspannung allerdings 4,53 V.

Du hast die (bis zu) 10% gefunden!
Glückwunsch :wink:

SP90:
Allerdings sind meine Messungen zu ungenau (bei 12 V habe ich im Mittel ca. 0,3 V Abweichung).

0,3 Volt Abweichung bei 12 Volt, das sind 2,5% das ist doch gar nicht so schlecht.
Na gut, mein Multimeter ist etwas genauer (ca. 0,3%), sagen wir das ist grob gesagt 10 mal genauer, dafür kostet es aber auch deutlich mehr als 10 mal soviel wie ein ATmega328P :slight_smile:

Danke mal für die Tipps.

Ich dachte mit dem Code verwende ich die interne Referenz. Habe mich dazu ein wenig durchs Forum gelesen - man die analogreference anscheinend auch umstellen. So wirklich schlau bin ich daraus aber leider nicht geworden.

Aber ich denke meine erste Frage ist beantwortet. Auf jeden Fall die aktuelle Boardspannung verwenden. Und anstatt diese als konstant bleibend anzunehmen wäre es sicher besser diese auszulesen. Es muss doch eine Möglichkeit geben die zur Spannungsmessung verwendete Referenz exakt auszulesen. Jemand eine Idee dazu?

Danke und LG

Hallo,

standardmäßig sind als Referenz die internen 5V eingestellt für analogRead.

Wenn du mit der internen 1,1V Referenz die Boardspannung genauer messen möchtest, dann mußte die Formel entsprechend korrigieren und einen Abgleich machen. Das gilt dann nur für das eine Board bzw. diesen µC.
Das heißt du musst den Wert für result einmal selbst ermitteln.

Das heißt, du baust dir einen Spannungsteiler womit du um die 1,1V genau justieren kannst.
Dann liest du mit der internen 1,1V Referenz und analogRead aus.
Jetzt stellst du solange sachte am Spannungsteiler rum, bis du geradeso von unten kommend 1023 angezeigt bekommst.
Das wird etwas zappeln. Dann misst du die Spannung die nun anliegt.
Dann rechnest du die Bsp. 1,07V * 1023*1000 = 1094610
das wäre dein spezieller result Wert.

Doc_Arduino:
... genau justieren ...

Wenn es um ganz genaues Einstellen geht, würde ich einen Spindeltrimmer/-poti nehmen. Ich habe hier ein Dutzend mit 2 MOhm.

Vier davon kann ich abgeben. Gerne im Tausch für irgendein anderes Teil.

Gruß

Gregor

Hallo,

Spindeltrimmer geht auch. Ich dachte eher daran, dass man sich den Spannungsteiler mit je einem Festwiderstand "oben", "unten" und in der Mitte ein Poti aufbaut, dann regelt man mit dem Poti in einem winzigen Spannungsbereich. Nur die Größenverhältnisse aller Widerständen müssen zueinander passen.
Bsp. Spannungsteiler
+5V ---- 15k ---- 1k Poti ---- 3k9 ---- Masse
dann kannste am Potiabgriff zwischen 0,97 ... 1,23V regeln

Irgendwas aus der Bastelkiste wird schon zusammen passen. :slight_smile:

So ich habe mich jetz nochmal in das Thema eingelesen. Die intere Referenz hat wie hier schon erwähnt 10% Toleranz, soll aber sehr stabil sein. Also hat man eine konstante Abweichung die man korrigieren kann. Und das geht wie hier zuletzt beschrieben - vielen Dank.

Aber vorweg kurz zu meinem Verständnis. Oft wird die Referenz auf analogreference internal gesetzt. Damit dürften aber am analog in auch nicht mehr als 1,1 V anliegen, wenn ich recht verstehe. In meinem Fall bleibt die analogreferece auf default, was die aktuelle Boardspannung wäre. Und die versuche ich jetzt mit dem anfangs geposteten sketch über die interne 1,1 V Referenz zu berechnen. Richtig soweit?

Die Abweichung liegt jetz in der Variable result, die ich fälschlich mit 1126400L übernommen habe. Wie das L in dieZiffer kommt is mir unklar, aber egal. Die Prozedur wie von Doc_Arduino beschrieben is mir prinzipiell klar, bis auf "Dann liest du mit der internen 1,1V Referenz und analogRead aus." Muss ich hier vorm analogread den Befehl analogReferene(INTERNAL) schreiben?

Ich kann ja davon ausgehen das meine 4,36 V konstant falsch sind. Kann ich nicht diese Werte für die Korrektur verwenden? Und zwar mit einer Schlussrechnung: Vcc_Arduino 4,36 V bei angenommener 1,1 V Referenz, Vcc_Multimeter 4,53 V bei welcher tatsächlichen Referenz.

Ref_tats = Ref_1,1/VccArduinoVcc_Multimeter
1,1429 = 1,1/4,36
4,53

und damit in die Formel von Doc_arduino:

result = 1,1429/1023*100 = 1169176

Kann das so auch funktionieren, oder hab ich einen Denkfehler? Dann würde ich mir die Arbeit mit dem Spannungsteiler ersparen.

Und Danke nochmal für die echt hilfreichen Tipps!!!

Ich kann ja davon ausgehen das meine 4,36 V konstant falsch sind.

Ja?
Eher nicht!

Die interne Referenz ist stabil.
Also nutzt man eben die!
Wenn es nur irgendwie geht.....

Den konkreten Wert kann man ja einmalig mit einem Multimeter messen.
Danach im Flash, oder noch besser im EEPROM ablegen.
Da wo auch die anderen individuellen Werte stehen sollten.

OK, habs mal eben ausprobiert. Also die Mathematik funktioniert. Man bekommt so ein genaues Messergebnis.

Allerdings hat combie recht. Diesmal waren es 4,47 statt 4,36 V. Also werd ich die Tatsächliche interne Referenzspannug ermitteln. Habe mir dazu folgenden kleinen sketch geschrieben:

void setup()
{
 Serial.begin(9600);
 analogReference(INTERNAL);
}

void loop()
{
   Serial.println(analogRead(A5));
}

Spannung justieren bis 1023 angezeigt wird und diese Spannung ist dann die Referenzspannung am Board.

Könnte ich die eigentlich auch direkt am IOREF-Pin messen?

Was ist der EEPROM und wie leg ich dort was ab?

Das ganze mach ich aber erst nächstes Jahr :slight_smile: Also wünsch ich euch mal ein gutes Neues!!

SP90:
Was ist der EEPROM und wie leg ich dort was ab?

Das EEPROM ist ein Speicher, der seinen Inhalt auch behält, wenn der Arduino nicht mit Energie versorgt wird (im Gegensatz zum RAM, das dann gelöscht wird). Vor einiger Zeit habe ich hierzu das hier ins Netz gestellt.

HTH

Gregor

Könnte ich die eigentlich auch direkt am IOREF-Pin messen?

Der Name des Pins legt es nahe.
Das Datenblatt deines Prozessors legt es nahe.

Ein kleiner Tipp:
Es benötigt mindestens einen analogRead() damit die Referenz aktiviert wird.

Hallo,

gesundes Neues alle zusammen. :slight_smile:

Ja, du musst erst die 1,1V Referenz aktivieren. Standardmäßig ist die 5V Referenz aktiv.

"L" ist ein Literal für den Datentyp "long" damit die Rechnung funktioniert. Standardmäßig wird in int gerechnet.
Fällt mir auch heute noch manchmal auf die Füße, beim debuggen fällt es dann auf. :wink:

Was mir noch einfällt, ich hatte dann später immer noch eine Meßabweichung und zwar ob ich das Board per USB und/oder zusätzlich versorgt hatte. Frage mich bitte nicht warum es dabei zu Unterschieden kam. Masseproblem, was auch immer ... , kannste mal probieren und berichten.

Halllo Leute,

ich habs jetz mal ausprobiert und bin wie beschrieben vorgegangen. Demnach hab ich bei der internen Referenzspannung 1023 Bit am Analogeingang wenn 1,08 V anliegen. Damit hab ich die Konstante neu berechnet und Messungen gemacht. Die waren allerdings mehr daneben als zuvor. Keine Ahnung warum???

Ich hab dann diese Konstante empirisch ermittelt, und zwar so dass die durch den obigen Code berechnete Boardspannung dem mit Multimeter gemessenen Wert entsprach. Dann passte auch die 12 V Messung exakt. Ich werd das jetzt mal weiterhin so im Auge behalten, ob die Messungen weiterhin stimmen.

Oder hättet ihr noch einen anderen Vorschlag?

LG

Hallo,

hmm, ich weiß nicht mehr ganz genau wie ich das ermittelt hatte, scheinbar darf man nicht mit dem ermittelten Wert direkt weiter rechnen sondern mit der weiteren Differenz, zusätzlich. Aber wenn es jetzt paßt ist alles i.O. Hauptsache die Messung stimmt im gesamten Bereich von 0V bis 12V. Nicht das die Steilheit der Messung noch daneben liegt. Dann müßte man die Formel nochmal neu herleiten wegen der Korrektur.

Hallo!

Habe heute wieder Testmessungen gemacht und leider scheint die Korrektur nicht zu funktionieren. Boardspannung lag 0,1 V daneben, gemessene Spannung um 0,2 V. Musste die Konstante erneut anpassen, um genaue Werte zu erhalten. Aber das kann nicht die Lösung sein, diese ständig ändern zu müssen.

Hat jemand eine Idee? Bin schön langsam ziemlich ratlos :frowning:

LG

Hat jemand eine Idee?

Nööö...

Du zeigst ja nicht, was du falsch machst.
Dann kann man/ich dir auch nicht sagen was du falsch machst.

Dass du was falsch machst, steht zu befürchten....
Aber selbst da kann ich dir keine Garantie drauf geben.

Tja....
Chancenlos.

Hallo,

okay, die Korrektur mit der Formel funktioniert doch etwas anders wie ich in Erinnerung hatte. Sorry.
Hier der Link mit der Beschreibung ohne Erinnerungslücken, habe lange gesucht ...
http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

Und wenn das wieder nicht klappt, tja dann das machen was fehlt und was combie meint, den kompletten Code zeigen.

Hallo,

habe mir den Link mal angeschaut. Ist das nicht genau das gleiche was ich schon vorgeschlagen hatte und leider auch nicht funktioniert hat?

Und zwar mit einer Schlussrechnung: Vcc_Arduino 4,36 V bei angenommener 1,1 V Referenz, Vcc_Multimeter 4,53 V bei welcher tatsächlichen Referenz.

Ref_tats = Ref_1,1/VccArduinoVcc_Multimeter
1,1429 = 1,1/4,36
4,53

und damit in die Formel von Doc_arduino:

result = 1,142910231000 = 1169176

Zur Erinnerung: Mit dem Spannungsteiler hatte ich die interne Referenz mit 1,08 V bestimmt.

Aktuelle Messwerte: Boardspannung mit Sketch 4,68 V und mit Multimeter 4,55 V. Damit ergäbe sich die Konstante result zu 1094042. Wenn ich das im Code ändere komme ich auf eine Boardspannung von 4,38 V und nicht 4,55 V :confused:

OK, mehr Infos sind ja kein Problem. Ziel ist eine Batteriespannungsüberwachung von KFZ Blei Akkus. Arduino wird von Raspberry Pi 2 B über USB mit Spannung versorgt. Raspi wird über DC/DC-Wandler KIS3R33S mit Spannung versorgt. Spannungsquelle ist die KFZ-Batterie selbst. Gemessen wird über Spannungsteiler. Vor AnalogIn ist in Serie ein 47 kOhm Schutzwiderstand. Zwischen AnalogIn und Masse ist ein 100 nF Kondensator. Folgend der komplette Code

// Ermittlung der Batteriespannung


//exakte Boardspannung Arduino
//---------------------------------------------------------------------------------------------------------------------------

long readVcc()

{
long result; // Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert

while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1170645L / result; // zum Abgleich Konstante "result" (7-stellige Zahl vor L) anpassen
//                             result = ermittelte interne Referenzspannung in V * 1023 * 1000 ???
return result;
}

//---------------------------------------------------------------------------------------------------------------------------


void setup()
{
 Serial.begin(9600);
}


void loop()
{
  float RB1=21700; //erster Spannungsteilerwiderstand in Ohm
  float RB2=6790; //zweiter Spannungsteilerwiderstand in Ohm
  float maxanalogread=1023; //Maximale Bit am Analog Pin
  float UBmessdigi=analogRead(A0); //Digitaler Messwert am Analog Pin
  
  float Vcc=readVcc(); //Arduino Boardspannung in mV
  float UBmess=Vcc/maxanalogread*UBmessdigi; //gemessener Spannungsabfall am Analog Pin (über RB2) in mV (lineare Interpolation)
  float gainB=(RB1+RB2)/RB2; //Verstärkung am Spannungsteiler (4.20) 
  float UB=UBmess*gainB/1000; // Batteriespannug in Volt (vor Spannungsteiler)
   
  Serial.print("Batteriespannung: ");Serial.print(UB);Serial.println(" V");
 
  Serial.print("Boardspannung: ");Serial.print(Vcc/1000);Serial.println(" V");

   
  delay(1000);
 
  
}

Vielen Dank schon mal!

Schön, jetzt hast du mal gezeigt, was du da baust.

Da steckt sehr viel rechnen drin.
Meines Erachtens nach zu viel.
Der Berechnungsfehler kann sich bei Float recht fix aufmultiplizieren.
Und das wollen wir doch nicht!
Oder?

Ich möchte das jetzt nicht vollständig analysieren, und den Fehler suchen, weil ich dir einen einfacheren Weg vorschlagen möchte: Die Zweipunkt-Kalibrierung

Verwende die interne Referenz.
Der konkrete Wert dieser Referenz ist irrelevant.
Muss weder gemessen, noch berechnet werden.
Die Versorgungsspannung des Arduinos ist irrelevant.

Wähle 2 Punkte, möglichst weit entfernt von einander.

Vorschlag:
Punkt 1:
Digital Wert 0 entspricht 0V

Punkt 2:
Den Spannungsteiler so bemessen, das beim obersten gewünschten Messwert die 1023 fast erreicht wird.
Die konkreten Widerstandswerte sind recht unwichtig, sie gehen nur indirekt in die Berechnung ein.
Digital Wert 102X entspricht z.B. 15V (muss mit Multimeter ausgemessen werden.)

Aus beiden Punkten dann die Steigung berechnen.
Und damit solltest du gewonnen haben.