Genaues Messen mit dem ADC und "Fixed-Point Arithmetik" sind immer
wieder ein Thema. Häufig werden hier die Grundlagen nicht verstanden und
man sieht die abenteuerlichsten "Floating point" Berechnungen. Trotz des
erhöhten Aufwands werden dennoch keine perfekten Ergebnisse
zurückgeliefert weil Offset und Gain Error falsch ermittelt werden. Das
folgende Beispiel wurde für das AVR NET IO Board, bestückt mit einem
ATMEGA 644p, geschrieben.
Bei Verwendung des ADC müssen folgende Fehlerquellen in Betracht gezogen
werden.
- Gain Error, Verstärkungsfehler des ADC / Eingangsverstärker.
- Offset Fehler des ADC, Idealerweise 0.
- INL / DNL Error, nichtlineare Verstärker, AD Wandler Fehler.
- VREF Fehler, Range 2,4 - 2,9 Volt.
In der AppNote AVR 120 werden alle diese Fehler in der Theorie
besprochen. Der hier vorliegende C Code setzt, im wesentlichen, diese
AppNote um. In der AppNote AVR 121 wird zu dem das Prinzip des
Oversampling beschrieben. Auch dieses Verfahren ist im Code enthalten.
Es werden 512 Messwerte gemittelt und auf 12 BIT skaliert. Bei einer
4-Stelligen Anzeige beträgt die Auflösung 1 mVolt. Die letzte Ziffer ist
somit frei von "Sprüngen".
Alle Berechnungen erfolgen mittels "Fixed-point Arithmetik". Die Ausgabe
des Meßwert erfolgt über die USART.
Die Referenzierung wird über 2 Stützpunktmessungen realisiert. Hierbei
wird der "rohe AD Wert" zugrunde gelegt.
1 | return (AvgSum >> 7); // ADC raw Value
|
Alle linearen Fehler sind somit kompensiert. Die Korrektur der
nichtlinearen Fehler wird hierbei, wie auch in der AppNote, nicht
berücksichtigt.
Die tatsächliche Größe der internen Referenzspannung muß nicht bekannt
sein da die Referenzierung über die Stützpunkte erfolgt. Man muß
lediglich 2 Testmessungen ausführen und den tatsächlichen AD Wert in das
adc.h file eintragen.
1 | #define AdcRawH 3206 // Stützpunkt 2.00 Volt
|
2 | #define AdcRawL 605 // Stützpunkt 0.40 Volt
|
Da alle Zahlen zur Basis 2 erweitert wurden kann die Berechnung des ADC
Wertes mit simplen shift Operationen ausgeführt werden.
1 | return ((((AvgSum >> 7) * Factor) + Offset) >> 16);
|
Der Code benötigt gerade einmal 600 Byte und ist ein schönes Beispiel
für die Effizienz von Fixed-point Arithmetik.
Viel Spaß,
Bernd