Archiv verlassen und diese Seite im Standarddesign anzeigen : Messungenauigkeit bei AD-Wandler
Hallo
ich habe ein kleines Problem mit dem AD- Wandler meines Atmega32. Ich verwende die interne Referenzspannung dem Atmega (2,56V). Nun habe ich an den PortA.0 mein Netzgerät bzw. auch Batterien angehängt. Masse des Netzgerätes bzw. Masse des Akkus hab ich auch mit Masse meines Experimentierboards verbunden. Mein Problem ist nun, dass bei etwas höheren Spannungen die Messungenauigkeit sehr hoch ist. Ich hänge beispielsweise 1,4V an, und bekomme 1150 angezeigt (entspricht 1,150V, das Komma fehlt noch). Das wäre eine Abweichung von ca. 0,3V. Ich finde, dass das etwas viel ist, zumal ich die interne Referenzspannung von 2,56V benutze, die doch relativ genau ist, oder? Bei Spannungen bis so ca. 0,4V sind die Werte noch akzeptabel bzw. genau. An was könnte das liegen?
Ich benutze einen Teilungsfaktor von 128 und messe die Spannung 64mal und teile sie dann wieder durch 64. Um die Spannung zu bekommen, multipliziere ich den gelesenen Wert mit 2,56 und teile mit 1024. Danach übergebe ich den Wert dieser Funktion:
void lcd_putsint(uint16_t zahl)
{
char puffer[6];
itoa(zahl, puffer, 10);
lcd_puts(puffer);
}
Der int Wert wird in ein char Array geschrieben und auf dem Display ausgegeben. Um ständig einen Wert zu bekommen habe ich das ganze in eine while(1) Schleife gesteckt:
int main(void)
{
lcd_init(LCD_DISP_ON);
uint16_t result;
while(1)
{
result = readADC(0)*2,56/1024;
lcd_putsint(result);
sleep(1000);
lcd_clrscr(); //löscht das Display
}
return 0;
}
Was könnte daran falsch sein?
Gruß micro5
was ich noch vergessen habe:
von dieser Seite habe ich den Großteil meines Programmcodes (hab nur kleine Änderungen gemacht):
https://www.roboternetz.de/wissen/index.php/ADC_%28Avr%29#C.2FC.2B.2B
Ich betreibe den Atmega auch mit einer Taktfrequenz von 7,372000 MHz.
Gruß micro5
Wie sieht denn die Hardware aus? Ist AVcc von Vcc mit Spule und Kondensator entkoppelt? Liegt VRef per 100nF auf Masse (ist m.W. auch bei internem VRef notwendig)?
linux_80
01.01.2007, 18:24
Hallo,
der grösste Wert vom AD-Wandler ist 1023, deshalb sollte da mit 1023 gerechnet werden, 1023*2,56/1023 = 2,56 !
Weis aber nicht ob es das schon war.
Wie ist die externe Beschaltung des ADC, bzw. von AREF AVCC usw., oder welches Board verwendest Du,
dann kann man evtl. sagen ob da auch noch etwas schwankt.
Hallo
also AVcc scheint von Vcc mit Spule und Kondensator entkoppelt zu sein. Zwischen Vcc und AVcc liegt ein Spule mit Induktivität von 100uH und zwischen AVcc und Masse ein 100nF Kondensator. Es liegt auch ein Kondensator zwischen VRef und Masse (100nF). Ich habe folgendes Experimentierboard:
http://www.kreatives-chaos.com/artikel/atmega1632-testboard-v2
Dort kann man auch einen Schaltplan und und Bestückungsplan herunterladen.
Die 1024 habe ich in dem Programmcode geändert in eine 1023. Dies leider keine große Auswirkung gebracht, die Werte sind weiterhin noch relativ ungenau bei höheren Spannungen.
Der Jumper 4 ist natürlich nicht gesteckt.
Gruß micro5
Die Schaltung sieht gut aus. Eine der wenigen mit sauberer AVcc Entkopplung, die man im Netz findet.
Laut Datenblatt des ATMega32 liegt die interne Refernezspannung zwischen 2.3 und 2.7 V (ist wahrscheinlich temperaturabhängig).
Nimm doch mal eine Testkurve auf, bei der Du die Eingangsspannung mit einem Multimeter misst. Zumindest sollte die linear sein.
Wichtig ist auch, dass die ADC Spamplefrequenz nicht zu hoch ist (s. Datenblatt). Für 10bit Genauigkeit darf sie 200kHz nicht überschreiten. Ansonsten werden die Messungen ungenau und fangen an zu schwanken.
Hallo
also ich habe dann mal eine Testkurve gemacht. Ich hoffe, dass ich das richtig verstanden habe. Also ich habe am Netzgerät eine Spannung eingestellt und sie parallel mit dem Mikrocontroller messen lassen und mit dem Multimeter gemessen. Dabei kam dann folgendes heraus:
Ich nehme an mit der ADC Spamplefrequenz meinst du das hier:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Controllertyp_setzen
Bei mir wäre
TFmin= 36,86 und
Tfmax= 147,44
Bei mir ist aktuell 64 eingestellt (die 128, die ich am Anfang erwähnt habe, habe ich geändet).
Man kann deutlich erkennen, dass bei höheren Spannungen die Kurven immer weiter auseinander triften.
Ich habe auch anstatt die 2,56V als interne Referenzspannung mal 2,3 eingestellt, leider hat auch das nicht allzuviel Änderung mit sich gebracht.
Hallo
hier wäre auch noch ein Diagramm mit den Differenzen.
jschilli
03.01.2007, 11:19
result = readADC(0)*2,56/1024;
Was könnte daran falsch sein?
Hallo Micro5,
ich glaube, Du hast hier ein klassisches C-Problem. Dein Compiler rechnet in unsigned int mit 16 bit. 2,56 ist in uint16 nunmal 2 und nicht 2,56. Daraus ergibt sich ein Rechenfehler von 28%. D.h. Dein Ergebnis liegt grundsätzlich 28% niedriger als das erwartetet Ergebnis. Das wären dann bei 1,4V etwa 0,392V Fehler und ergibt eine Spannung von 1,008 V.
Es gibt drei Möglichkeiten:
1. verwende Float zum berechnen, was allerdings ein Speicheroverkill ist, oder
2. Berechne im integer Wertebereich
result = readADC(0) / 4;
3. berechen im 32 bit Wertebereich
result = (unsigned int) ((unsigned long)readADC(0) * 256/102400);
Grüsse,
Schimmi
jschilli
03.01.2007, 15:41
2. Berechne im integer Wertebereich
result = readADC(0) / 4;
Sorry, aber ich muss mich korrigieren:
result = readADC(0)/400;
sollte es korrekt heissen... Denn 2,56/1024 = 1/400.
Grüsse,
Schimmi
SprinterSB
03.01.2007, 15:45
https://www.roboternetz.de/wissen/index.php/Fallstricke_bei_der_C-Programmierung#Ein_.2C_anstatt_._in_Konstante
Hallo
@jschilli
Ich glaube, du hattest Recht mit deiner Vermutung, dass dies ein klassisches C-Problem sei. Trotzdem funzte es nicht einwandfrei. Problem:
Wenn ich diese Zeile schreibe:
result = readADC(0)/400;
Dann bekomme ich auf dem Display immer nur eine 0, 1 oder 2 angezeigt. Diese steht für 0V, 1V und 2V, allerdings nicht die Nachkommastellen. Außer dieser Zeile habe ich nichts geändert.
result = (unsigned int) ((unsigned long)readADC(0) * 256/102400);
Bei dieser Zeile genau das selbe.
Bei beiden Versionen kommt der Sprung von 0 auf 1 bzw. 2 im richtigen Moment. Also es scheint nicht mehr so große Abweichungen zu geben.
Durch Zufall bin ich dann auf diese Seite gestoßen (ich suchte Funktion die float in char konvertiert, wusste nicht ob itoa() dies auch kann):
https://www.roboternetz.de/phpBB2/printview.php?t=20211&start=0
Mit dieser Zeile funzt das ganze jetzt mit der internen Referenzspannung einwandfrei:
result = (readADC(0)*320313/2)/65536;
Normalerweise hätte ich anstatt der 320313/2 diesen Wert nehmen müssen 164000,1564 (ich gehe davon aus, dass die interne Referenzspannung 2,56V beträgt). Jedoch sind meine Werte dann ungenauer. Deshalb nehme ich jetzt 320313/2. Dies Differenz zwischen meinem Multimeter und dem Mikrocontroller liegt bei 2-4 mV. Dies ist ein akzeptabler Wert, denke ich. Würde ich die 164000 nehmen, ist die Differenz zwischen 5-25mV.
Ich bedanke mich bei allen die mir geholfen haben
Gruß micro5
enterprise30
19.12.2007, 21:42
Tschuldigung - Deine Frage ist zwar schon etwas älter, aber ich hatte so ein ähnliches Problem (beim Mega8)
Hast Du schonmal ins Datenblatt auf Seite 55/324/347 geschaut?
Guck Dir mal die Toleranzen der internen Bandgap und Referenz an!
(VINT Internal Voltage Reference)
Die ist mit 2,3V bis 2,7V angegeben und alles andere als genau!
Bastel Dir eine externe Referenz und schalt die interne ab und dann geht dat
...
Ich hab mal am AREF Pin die interne Referenzspannung gemessen. Statt der erwarteten 2,56 V waren das 2,77V. War schon eine Überraschung - Messung war bei Raumtemperatur. Die Angabe von 2 Stellen nach dem Komma suggeriert einem schon eine höhere Genauigkeit. Nachdem ich es ausgemessen hatte und den Meßwert für VREF für die internen Berechungen verwendet habe, war die Genauigkeit o.k.
enterprise30
30.12.2007, 23:24
Und das ist nicht alles:
Bei jedem Prozessor ist das eine andere bzw. von gleichem Typ ist keine Ref. wie die andere.
Wenn auch sonst die Atmel klasse sind, DAS hat mich schon entäuscht.
...
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.