Rechnen

Hallo Zusammen,

da ich noch neu mit der Programmierung hier bin, krieg ich gerade graue Haare:

Serial.println((790 * (1.05) * 0.00488) );
Als Ergebnis bekomme ich 4.05

Serial.println((790 * (105 / 100) * 0.00488) );
Als Ergebnis bekomme ich 3.86

Serial.println((790 * 105 * 0.00488) );
Als Ergebnis bekomme ich 84.98

Ich verstehe das nicht.

Was ich im Prinzip eigentlich nur machen will:

  1. Eine Spannung am Analogport messen (Basis 5V = 1023(?))
  2. Messungenauigkeit (bedingt durch Spannungsteiler) kompensieren [1.05]
  3. Wert auf 'echte' Spannung umrechen [0.00488]

Den Wert aus 2 würde ich gerne im EEprom speichern. Da ich Platz sparen will, reicht mir hier ja ein int oder long völlig aus!
Wie kann ich das denn hin bekommen?

Gruß und Danke
Carsten

Du rechnest mit Fleißkommazahlen bzw mit Integer. Die Fließkommazahlen haben eine Genauigkeit von nur 6 -7 Stellen. Am genauesten ist es Du rechnest mit Ganzzahlen (int oder long) und entfernst erst am Ende der Rechnung die nicht gebrauchten Kommastellen.

Serial.println((790 * (1.05) * 0.00488) );
Als Ergebnis bekomme ich 4.05

ist das genauste Ergebnis (genaugesagt 4,04796)

Serial.println((790 * (105 / 100) * 0.00488) );
Als Ergebnis bekomme ich 3.86

105/100 integer ( ohne Kommastellen ergibt 1 und nicht 1,05) darum der Fehler

Serial.println((790 * 105 * 0.00488) );
Als Ergebnis bekomme ich 84.98

Das kann ich nicht nachvollziehen. Müßte etwas um 404,796 herauskommen.

Des weiteren ist die Versorgungsspannung keineswegs 5,000V sondern igendwas zwischen 5,1V und 4,6V Das bedingt eine weitere Ungenauigkeit bei Sensoren die einen absoluten Ausgangswert geben. Bei relativen Ausgangswerten (zB von einem Spannungsteiler eines veränderbaren Widerstandes mit einem Fixwiderstand.
Grüße Uwe

Hallo,

die Versorgungsspannung habe ich mal als 5 definiert. Die bekomme ich aus einem Regler und sie ist in meinem Fall exakt 5.00V

Trotz allem bekomme ich die Rechnung nicht hin!

Könntest Du mir mal die Rechnung so umbauen, dass was richtig raus kommt. Und mir dann auch sagen warum?
Ich habe es mit vielem probiert. Nur Murks :frowning:

Gruß
Carsten

Die AnalogenInputs messen die 5V in 1024 Schritten. Von 0 bis 1023.

value = analogRead(analogInput); 
vout = (value * 5.0) / 1024; // Der Wert den wir messen 
vin = vout / (R2/(R1+R2)); // Spannungsteiler-Umrechnung

So mache ich das immer, die Werte stimmen auch mit einer Abweichung von maximal +/- ~ 0.05V mit meinem GoOn! 8) Multimeter überein.
Zusätzlich hab ich den Eingang dann noch mit einer Z-Diode abgesichert, falls mal mehr als 5V dran schwappen.

Nur keine Ahnung ob dir das jetzt hilft oder voll vorbei ist.

Hallo,

nee ist genau richtig.
Die Formel sind für mich als gelernter Elektroniker nicht das Problem.
Mein Problem ist die Arithmetik im Arduino gewesen. Die habe ich jetzt aber im Griff.
Auch werde ich nicht mehr auf 5 Volt Basis arbeiten, sondern meinen Messwert
Maximal 4,2V (LiPo maximal Spannung pro Zelle) per Spannungsteiler auf 1,1V teilen.
So kann ich dann die interne Referenz nutzen, was etwas genauer ist.
Allerdings muss ich dann wieder mit ganzen krummen Werte kompensieren, da es die Widerstände so wie sie gebraucht würden in der E96 Reihe gar nicht gibt.

Aber jetzt warte ich erstmal auf die Widerstände und dann geht es weiter...

Gruß
Carsten

cGiesen:
Serial.println((790 * 105 * 0.00488) );
Als Ergebnis bekomme ich 84.98

Nur der Vollständigkeit halber:

die drei Rechenoperationen werden nacheinander gerechnet.

zuerst 790 * 105 = 82950
der Wertebereich von unsigned int geht aber nur bis 65536. Es gibt also einen Überlauf und der Wert, der nachher in der Zelle steht ist:
8950 - 65536 = 17414

und nun wird weitergerechnet:
17414 * 0,00488 = 84,98.

Voila. Der Arduino rechnet richtig!

Wobei die Reihenfolge in der solche gleichwertigen Operationen gerechnet werden nicht zwangsläufig in der Reihenfolge passieren, in der sie geschrieben werden. Mit einem anderen Compiler kann evtl ein anderes Ergebnis rauskommen.
Da hilft eben nur, die Variablen richtig zu deklarieren!

Sche***e,
jetzt fällt's mir wieder wie Schuppen aus den Haaren, da war doch was :frowning:

DANKE

guntherb:
Da hilft eben nur, die Variablen richtig zu deklarieren!

oder Konstanten zuerst zusammenzurechnen und das Ergebnis in die Formel einsetzen. Es hat nämlich keinen Sinn daß Arduino immer wiederkehrende Rechenoperationen durchführt. Das ist nur Speicher und Rechenzeitverlust.
Grüße Uwe

Müsste die Formel für die Spannungsteiler-Berechnung nicht so sein:

value = analogRead(analogInput);
vout = (value * 5.0) / 1024; // Der Wert den wir messen
vin = vout * (R2/(R1+R2)); // Spannungsteiler-Umrechnung

Ich komme bei der Formel vin = vout / (R2/(R1+R2)) auf falsche Werte

Jürgen

Juergen_S:
Ich komme bei der Formel vin = vout / (R2/(R1+R2)) auf falsche Werte

Das Verhältnis ist VR1R2:VR2 = (R1+R2): R2
(Vin an R1+R2 und Vout an R2.)
Grüße Uwe

Ich hab das in meinen Sketch so gelöst

const float referenceVolts = 3.3;
const float R1 = 1000;
const float R2 = 1000;
const float resistorFactor = 1023.0 * (R2/(R1 + R2));

und hier im Loop

void loop()
{
  int val = analogRead(batteryPin);
  float volts = (val / resistorFactor) * referenceVolts ;
  Serial.println(volts);

Selbst im Arduino Kochbuch im Kapitel 5.11 wird die Formel meiner Meinung verkehrt angebeben.

Wenn ich einen Spannungsteiler von 2 x 1000 Ohm nehme, habe ich mit der Formel wie im Buch beschrieben einen resistorFactor von 2046 statt 511!

Vieleicht hab ich auch einen Denkfehler, aber der Sketch zeigt mir die richtige Spannung an.

Jürgen

So ganz verstehe ich es nicht.
Du hast doch genau die Formel aus dem Arduino-Kochbuch umgesetzt!

Dein "volts" entspricht Vin; Also:
Vin = (val / resistorFactor) * referenceVolts

jetzt setzen wir noch deine Formel für "resistFactor" mit ein:
Vin = (val / (1023 * R2/(R1 + R2))) * referenceVolts

jetzt ziehen wir die Normierung auf den AD-Wert noch raus:
Die Formel
Vout = val * Uref /1023 lösen wir nach val auf:
val = Vout * 1023 / Uref

und setzen sie ein:
Vin = (Vout * (R2/(R1 + R2)))

das ist genau das gleich!

Juergen_S:
value = analogRead(analogInput);
vout = (value * 5.0) / 1024; // Der Wert den wir messen
vin = vout * (R2/(R1+R2)); // Spannungsteiler-Umrechnung

Du hast die Formel perfekt umgesetzt.

Gunther

Eigentlich werden die Widerstände doch gar nicht benötigt. Ich der Formel meine ich!
Es reicht doch zu wissen, was ich anlege und welches Zahl ich bekomme.

Da die Widerstände ehe nie so genau sind, muss man sowieso einen Kalibrierfaktor vorsehen.
Der kann dann auch gleich die Spannungskorrektur beinhalten.
Also einfach readanalog(pin) * Faktor und fertig!

Gruß
Carsten

Die Widerstände brauchst du, wenn du Spannungen messen willst, die größer sind als die Referenzspannung des AD.

So ist es, ich messe die Spannung des Lithium-Akku der ja 4,2 Volt Spannung abgibt und mein Arduino Pro Mini hat 3,3 Volt.

Gruß
Jürgen

guntherb:
Die Widerstände brauchst du, wenn du Spannungen messen willst, die größer sind als die Referenzspannung des AD.

Ich habe doch ausdrücklich geschrieben:
"In der Formel werden sie nicht benötigt!"

Soll heißen, ich kann alle diese Faktoren in den Korrektur Faktor integrieren!

Das man die Widerstände auf der Elektronischen Seite braucht, versteht sich von selbst.
Allerdings würde ich auch gleich auf 1,1V gehen und die interne Referenz nehmen. Das ist genauer.

Gruß
Carsten