ATiny85 Betriebsspannung messen fehlerhaft. Warum?

Hier ist eins von beiden überflüssig.
entweder das delay(5) oder der dummy read

So weit habe ich nicht gedacht, die Mimik so weit zu vereinfachen.
Meine genutzte Variante ist:

constexpr uint16_t VCC = 4997;   // Measured in milliVolts!
constexpr uint32_t REFxRESOLUTION {1100 * 1024UL};
constexpr uint32_t VCCxREF {VCC * 1100UL};
constexpr float INTERIM_RESULT {VCCxREF / REFxRESOLUTION};

uint16_t readInternalRef11() {
  ADCSRA |= _BV(ADSC);                 // Start conversion
  while ((ADCSRA & _BV(ADSC))) { ; }   // measure
  return static_cast<uint16_t>(INTERIM_RESULT * ADCW);
}

void setup() {
  soSerial.begin(9600);   
  initADC0();
}

void loop() {
  static char buffer[5];
  itoa(readInternalRef11(), buffer, DEC);
  soSerial.print(buffer);
  soSerial.print("\n");
  delay(2000);
}
#endif

Kommt dasselbe raus :-). Hab es ja quasi schon da stehen, dass die 1,1 rausgekürzt werden kann, aber nicht gesehen.

Die 1.1 ist der Sollwert der Referenz. In dieser Rechnung wird der tatsächliche Wert der 1.1V-Referenz Referenz ermittelt. Die 1023 oder 1024 ist ein altes Streitthema.

Gruß Tommy

Oh ja ... danke für den Hinweis.

Ja!
Aber der Sollwert hat doch da nichts zu suchen!

Du kannst an der Stelle, ohne jeden Unterschied auch Pi einsetzen, oder 4711.0, als "Sollwert".
Bitte: Probiere es aus!

Die 1.1 ist da einfach eine Müllzahl.
Flüssiger als Wasser, überflüssig.
Sie erhöht nur die Anzahl Rechenoperationen unnötig.
Und erhöht damit nur die notorische Ungenauigkeit bei Float Rechenoperationen.

Jedenfalls ist die 1,1 in meinem Fall nicht die Ursache für mein Problem mit dem ATTiny85. Vielleicht hat ja noch jemand eine Idee, aber ich denke auch, dass ich das so machen werde wie @Doc_Arduino und das Thema erst einmal unter "nice try" ablege. Mit den "moderneren" Tinys scheint es ja zu funktionieren.

Habe es jetzt nach dem Denkanstoß abgeändert:

constexpr uint16_t VCC = 4997;   // Measured in milliVolts!
constexpr float VCCxRESOLUTION {VCC/1024.0};

uint16_t readInternalRef11() {
  ADCSRA |= _BV(ADSC);                 // Start conversion
  while ((ADCSRA & _BV(ADSC))) { ; }   // measure
  return static_cast<uint16_t>(VCCxRESOLUTION * ADCW);
}

void setup() {
  soSerial.begin(9600);   
  initADC0();
}

void loop() {
  static char buffer[5];
  itoa(readInternalRef11(), buffer, DEC);
  soSerial.print(buffer);
  soSerial.print("\n");
  delay(2000);
}

Ja!
Ins besondere, wenn man es mit Menschen zu tun hat, die mit den im Datenblatt angenagelten Fakten nicht klar kommen.
Die beharren auf 1023. Die sind auch mit Logik und guten Worten nicht zu überzeugen.

Was aber offensichtlich ist:
VCC/1023.0 und VCC/1024.0 liefen unterschiedliche Ergebnisse
Die Differenz der beiden geht in die Folgerechnungen ein.

Beispiel, der ADC liefert 355.
Dann geht die Differenz mit dem Faktor 355 in die Rechnung ein.

Will man sich wirklich eine um den Faktor 355 verstärkte Fehlpeilung einfangen?

Wo Du Recht hast, hast Du Recht :wink: Die 1.1 in beiden Zeilen kürzt sich raus.

Gruß Tommy

Hier würde ich dir raten, den Messvorgang mit der niedrigsten für die Schaltung üblichen Spannung durchzuführen.
Also z.B. für den Betrieb an einem Lipo Akku mit 3,6V

Hallo,

nach der Abschweifung kommen wir wieder zum eigentlichen Problem.
Den doppelt 1.1 Faktor Vref hat Kai nie verwendet.
Auch rechnet Kai seit Anfang an mit 1024 statt 1023.
Dennoch stimmen die Messwerte nicht bei unterschiedlichen Versorgungsspannungen.
Wir stehen weiterhin am Anfang der Frage warum die Messwerte wegdriften.

Falsch!
Er berechnete seine Referenz mit dem Code hinter dem Link, und da steht eben die 1.1V drin.

Auch wohl falsch!
Er berechnete seine Referenz mit dem Code hinter dem Link, und da steht eben die 1023 drin.

Vielleicht übersehen, dass in dem hier geforderten Messbereich durchaus (geschätzte) 10% Fehlpeilung drinsitzen können. Darum auch mein Vorschlag, die Referenz bei einer realistischen Akkuspannung zu bestimmen und nicht bei 5V.

Dazu kommt noch, dass das Rechenwerk Vcc belastet, also Innenwiderstände zuschlagen.
Drum gibts ja auch einen Sleep Mode extra zu dem Behufe.

Nein @Combi. Ich habe zwar in meinem Eröffnungsposting auf den Artikel verwiesen, aber in dem Sinne, das dieser der Ausgangspunkt meiner Versuche war. Verwendet habe ich von Anfang an den Code , den ich in #22 gepostet habe. In #7 habe ich auch geschrieben, dass ich die Werte letztendlich "experimentell" ermittelt habe. Weder die 1023 noch die 1,1 haben da eine Rolle gespielt.

Außerdem habe ich geschrieben, dass Ausgangspunkt meiner Messreihe 3V waren. Mit dem bei dieser Spannung ermittelten Referenzwert hatte ich am Ende > 500mV Fehler (Bei 5V) beim ATTiny85. Selbst bei 3,5V waren es schon 55mV Differenz zum gemessenen Wert.

Ein Phänomen, welches bei einem ATtiny1604 (bei gleichen Rechenoperationen) nicht auftritt.

Danke für den Hinweis in #29. Das werde ich mir merken.

Nunja, ich dachte, das wäre ein veränderter Code....
Und die 1.1 stehen da in Posting #22 doch schon noch drin.
Auch die 4,99V stehen da drin.

Aber ich kann auch nicht alles verstehen.....
Sorry.

Nun, die standen drin.. ja. Ich hatte das im Rahmen eines anderen Threads, wo jemand mit einem Attiny die Spannung messen wollte, vor ein paar Tagen schon umgebaut. Allerdings habe ich das "Kürzen" nicht gemacht, obwohl es mir bei dem Ausdruck constexpr float INTERIM_RESULT {VCCxREF / REFxRESOLUTION}; hätte auffallen müssen, dass REF (1,1) weggekürzt werden kann.

Konnte ja auch beim Eröffnen des Threads nicht ahnen, dass die 1,1 so eine Rolle spielen würde :wink:

Tut mir leid, wenn das von meiner Seite aus verwirrend war. Dennoch hatte ich Dank Deiner Hilfe mal wieder einen Erkenntnisgewinn.

Hallo,

jetzt wird es wirklich verrückt. Weil ich ging von #1 aus mit dem auch die ersten Messwerte ermittelt wurden. In #1 gibt es kein doppeltes 1.1 und auch kein 1023. Soweit ist das korrekt gewesen.

Ich habe mich auch nochmal mit beschäftigt. Die Bandgap driftet einfach "zu stark" je nach Ub. Du kannst einmal die Bandgap an AREF messen und mit Ub eine Kennlinie aufnehmen. Du müßtest die gleiche Krümmung bekommen wie in #1 ermittelt. Die Bandgap bewegt sich innerhalb ihrer Toleranzgrenze, soweit okay laut Datenblatt, ist jedoch abhängig von Ub, also verändert sich innerhalb ihrer Toleranz mit Ub mit. Weil man aber Ub mittels Bandgap messen will, verändert sich der Messwert zwangsweise und weicht damit ab. Der Messwert stimmt also nur für den abgeglichenen AREF Wert bei angelegter Versorgungsspannung x genau. Alles andere liegt mehr oder weniger daneben.

Ich muss gestehen, ich weiß nicht wie das gehen soll.
Bei der Konstruktion ist REFS0 bis REFS2 = 0. Das bedeutet: "VCC used as Voltage Reference, disconnected from PB0 (AREF)"
Schalte ich die interne Referenzspannung auf 1,1V und ändere nichts an den MUX Einstellungen, habe ich Ub an dem AREF Pin.

Ich auch nicht.
Die 2,56V kann man auf PB0 legen, aber nicht die 1.1V

Die Grafik 22-36 zeigt ja, dass sich Vbg mit zunehmender Spannung nach unten bewegt. Das ist ja tendenziell genau das, was ich festgestellt habe. Allerdings in stärkerem Ausmaß. Nach dem Datenblatt dürfte die Vbg nicht unter 1V fallen.

Hallo,

das Datenblatt vom ATtiny85 liest sich wie das meines ATmega2560. Sollte möglich sein.

Je nach Zeile

ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
ADMUX = _BV(REFS1) |              _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

messe ich an AREF die 1,1 oder 2,56V VREF bei meinem ATmega2560.

Wenn ich mir das für den ATtiny85 anschaue sollte das ähnlich funktionieren, denke ich.

ADMUX =              _BV(REFS1) | _BV(REFS0) | _BV(MUX3) | _BV(MUX2);
ADMUX = _BV(REFS2) | _BV(REFS1) | _BV(REFS0) | _BV(MUX3) | _BV(MUX2);

In Tabelle 17-4 steht sogar 1.1/2.56V, was beim ATmega2560 nicht steht und trotzdem funktioniert.
Danach nicht vergessen eine Wandlung zu machen, sonst wird das nicht übernommen.

Probier mal aus, bin gespannt.

Heute aber nicht mehr :slight_smile:

Wenn ich mir diese Zeile anschaue:

ADMUX =              _BV(REFS1) | _BV(REFS0) | _BV(MUX3) | _BV(MUX2);

Nach meinem Datenblatt Tabelle 17.3 ist REFS1 und REFS0 gesetzt = Reserved!?

Folgendes habe ich ausprobiert:

ADMUX =              _BV(REFS1)  | _BV(MUX3) | _BV(MUX2);

Bringt aber, wie gesagt, nur Ub an PB0.