Hallo leute,
Kann mir jemand beim ADC auslesen helfen?
Ich habe folgendes problem:
Ich habe die funktion aus dem tutorial übernommen.
AREF auf 5 V
wenn ich jetzt einen wert auslese bekomme ich nicht den richtigen z.b.
bei 2V, sollte er sein (bei 10 bit auflösung) ca.409 ich bekomme aber
einen 353 beim 2 durchlauf 180 beim 3. 368 usw.
er bleibt nie stabil und stimmt ja auch nicht ganz.
Ich habe keine kondensatoren oder wiederstände in meiner schaltung zum
stabilisieren, kann das, das problem sein?
bedanke mich im vorraus.
sag doch bitte um welchen Przessortyp / Familie es sich handelt!
Dann kann man dir weiterhelfen.
Wenn der Wert ungefähr stimmt kannst du auch einen Mittelwert bilden!
Sprich 10 mal Messen jeweils Addieren und danach durch 10 Teilen. Schon
hast du dein Wert gemittelt...
Ein Bit entspricht
Referenzspannung / (2^Auflösung -1)
Somit:
2V bei 10Bit 409.6
Mittelwertbilden kannst du ganz einfach!
Mehrmals messen, Addieren und durch die Anzahl Messungen dividieren.
Falls dir das was bringt.
Hi,
ich kann jetzt nur von einem PIC sprechen:
Hatte da mal das gleiche Problem.
Wenn Du die A/D-Wandlung zu schnell aufeinander machst, bzw. bei
asynchronem Modus das Ergebnis ausliest, bevor die A/D-Wandlung beendet
ist --> dann treten evtl. solche Probleme auf.
Weiter Möglichkeiten:
- Falsche Referenzspannung (zu hoch oder zu niedrig --> kenne wie gesagt
den ATMEGA nicht...)
- Brumm auf dem zu messenden Signal --> miss mal mit nem Oszi
- Brumm auf der Versorgungsspannung --> miss mal mit nem Oszi
- Brumm auf der Referenzspannung --> und nochmal mit Oszi messen ;-)
(Wobei ich bei einem Fehler von 180Digits einen Brumm fast ausschließen
würde)
Falls KEIN Brumm auf den Leitungen ist, dann würde ich von einer
Mittelung großen Abstand nehmen. Denn eine Schwankun von 180 Digits ist
wirklich zu VIEL!!! +-1 Digits solltest Du erreichen...
Als schnellen Test würde ich folgenden pseudocode vorschlagen:
1. A/D-Wandlung machen
2. Ergebnis ausgeben
3. Warte 1000ms
4. zurück zu 1.
Beste Grüße,
Andreas
@ Andreas N.
Hast du recht.
der Test funktioniert eigentlich so wie er sein sollte.
gucke ich mir einfach mal die brumm spannungen an.
aber mal ne andere frage zwieschen durch.
Kann man in c double nicht % 10 rechnen???
ist für die ausgabe der zahlen.
Oder wie kann ich die Zahlen mit komma ausgeben?
Hi,
natürlich kann man den Modulo-Operator NICHT auf eine Gleitkommazahl
anwenden! Der ist nur für ganze Zahlen...
Verstehe aber auch nicht, wo Du % 10 brauchen könntest...?
Poste mal Deinen Code, dann kann Dir vielleicht geholfen werden ;-)
Oder suchst Du sowas:
printf("Meine Gleitkommazahl: %.2f\r\n", _meine_zahl);
Ausgabe für _meine_zahl = 123.4567:
Meine Gleitkommazahl: 123.46
Gruß,
Andreas
> Oder suchst Du sowas:> printf("Meine Gleitkommazahl: %.2f\r\n", _meine_zahl);>> Ausgabe für _meine_zahl = 123.4567:> Meine Gleitkommazahl: 123.46
Genau das brauch ich nur das ich jetzt
sprintf(string,"%.2f",zahl);
das mache in anschliessend sthet im string '?' (63) sonnst nix.
aber im debuger kann ich sehen das ich tatsächlich eine double variable
übergebe wie z.b. 3.04496 usw.
Sorry,
aber das kann ich nicht glauben.
Poste doch mal den ganzen Codeabschnitt inklusive Variablendeklaration.
Es sieht so aus, als ob Du einen falschen Variablentyp übergibst.
Ist "zahl" vielleicht ein Zeiger? Dann müßtest Du "*zahl" schreiben...
Kann Dir aber erst morgen Antworten - muss jetzt weg.
Gruß,
Andreas
Hier wird sie aufgerufen
double Analog_Werte;
//Analog Digital Converter Starten um die aktuellen werte einzulesen.
Analog_Werte = ReadChannel(0);
//U=Vref*adwert/1023
Analog_Werte = (5*Analog_Werte)/1023;
uart_putd_PC(Analog_Werte );
also das ist die funktion:
// ausgabe eines String mit einer double Variable wird für den ADC
verwendet
char uart_putd_PC( double value )
{
char *string;
sprintf(string,"TEST %.2f",value);
uart_puts_PC( string );
return(0);
}
als ergebniss kommt dann
"TEST ?"
> Um eine Zahl mit Komma auszugeben gibts eine schöne C-Funktion, div, mit> dem Typ dd, der Wert und Rest ausgibt:>
1
>div_tdd;
2
>
3
>dd=div(wert,10);
4
>sprintf(buffer,"%2d,%01d",dd.quot,dd.rem);
5
>
>> Grüße> Hans-Josef
wie funktioniert diese Funktion?
Ich habe das jetzt einfach mal so übernommen:-)
und mit folgendem ergebniss:
div_t dd;
char *string;
dd = div(value,10);
sprintf(string,"%2d,%01d",dd.quot,dd.rem);
//sprintf(string,"TEST %.2f",value);
uart_puts_PC( string );
value ist ein double.
jetzt mekert der Compiler dass ich 2 integer an div übergeben soll.
und als ergebniss kommt auch nix.
Hans-Josef könntest du es mir vieleicht näher erklären?
Hey,
die Funktion div arbeitet mit int's und nicht mit double.
Brauchst Du denn double?
Ich hatte Dir die Funktion gezeigt, da man damit im Prg nicht mit
double, sondern mit int's arbeiten kann. Schneller und kürzer.
Normalerweise brauchst Du es ja nur als Anzeige und da arbeitet dann die
Funktion wie beschrieben.
Wenn Du also einen AD-Wert (0..1024 entspricht 0..5V) mit einer
Nachkommastelle ausgeben möchtest, dann z.B. so:
1
div_tdd;
2
inttemp;
3
4
temp=AD_Wert*50;// 5V*10 für Nachkommstelle
5
temp>>=10;// auf richtigen Wert bringen teilen durch 1024
6
7
dd=div(temp,10);
8
sprintf(buffer,"%1d,%01d",dd.quot,dd.rem);
So bekommst Du dann die Spannung als X.X ausgegeben
Grüße
Hans-Josef
Der Grosse wrote:
> char uart_putd_PC( double value )> {> char *string;>> sprintf(string,"TEST %.2f",value);> uart_puts_PC( string );>> return(0);> }>> als ergebniss kommt dann>> "TEST ?"
Das kann ja nicht gehen, denn "string" wird ja nicht initialisiert und
zeigt dann irgendwohin...
Also besser z.B.:
Also ich weiss nicht was ich da tuhe. >> Nicht gut...
also
ich bekomme ein wert vom adc. sagen wir mal 512
damit habe ich eine spannung von 2.5V
so dann rechne ich das mal 50 ergibt 25600 ne
dann teile ich durch 1024 ergibt 25
damit bekomme ich dann den wert 2.5 angezeigt.
richtig?
soweit zur theorie.
wieso funktioniert es dann nicht in der Praxis???
hier der code:
SR (TIMER1_OVF_vect)
{
div_t dd;
int temp;
int AD_Wert;
SREG &= ~(1<<WDIF); //Globale interrupts sperren
//Analog Digital Converter Starten um die aktuellen werte einzulesen.
AD_Wert = ReadChannel(0);
temp = AD_Wert*50;
temp = (temp)/1023;// auf richtigen Wert bringen teilen durch1024
dd = div(temp,10);
sprintf(buffer,"\n%1d,%01d\n",dd.quot,dd.rem);
uart_puts_PC(buffer);
TCNT1H = 0x00;
TCNT1L = 0x00;
SREG |= (1<<WDIF); //Globale interrupts erlauben
}
Hi,
folgender Code von Dir kann nicht funktionieren:
1
charuart_putd_PC(doublevalue)
2
{
3
char*string;// das ist nur ein ZEIGER - es wird dafür KEIN Speicher reserviert...!!! Und jede Ausgabe ist Zufall. Jede Zuweisung kann zum Systemabsturz führen!
4
5
sprintf(string,"TEST %.2f",value);
6
uart_puts_PC(string);
7
8
return(0);
9
}
es muss heißen:
1
charuart_putd_PC(doublevalue)
2
{
3
charstring{50];// Korrektes ARRAY of char
4
5
sprintf(string,"TEST %.2f",value);
6
uart_puts_PC(string);
7
8
return(0);
9
}
Und schon wird es funktionieren... ;-)
Gruß,
Andreas
ALSO Leute ich bedanke mich hezlich...
es funktioniert.
Ich hätte euch die schltung geben sollen dann wüsstet ihr sofort was los
ist.
ich habe für die messung eine externe spannung verwendet. ABER keine
massen verbunden oder sonnst was.
Jetzt habe ich alles von der Spannungsversorgung des MC genommen und es
ist alles stabil und läuft!!! super hää..
hier jetzt der funktionierende code der vom adc einliest und auf eine
stelle genau ausgibt.
1
//Initialisierung:
2
3
//Analog digital converter aktivieren
4
5
ADMUX=(0);// Kanal waehlen
6
ADMUX&=~(1<<REFS1)|(1<<REFS0);// externe Referenzspannung nutzen, interne aus
temp=(temp)/1023;// auf richtigen Wert bringen teilen durch 1024
Und warum teilst Du hier durch 1023 und nicht durch 1024 (wie es
korrekt im Kommentar steht)? Zumal Du dem Programm damit keinen Gefallen
tust. Eine Division durch 1023 ist signifikant aufwändiger als eine
durch 1024 (abgesehen davon, dass 1024 in diesem Fall der einzig
richtige Divisor ist)!
Der Grosse wrote:
> weil ich es im kommentar leider vergessen habe zu ändern...> Die auflösung ist ja 1023 und nich 1024 ;-)
Nein! Die Referenzspannung wird in 1024 gleiche Teile unterteilt,
nicht in 1023! Ausgegeben werden kann zwar nur 1023, das ändert aber
nichts daran, dass der Gesamtbereich 1024 Intervalle hat. Ein ADC
"verliert" prinzipbedingt ein LSB und gibt für Werte, die größer als
VREF-1LSB sind, den Maximalwert aus. Schau Dir mal die Funktionsweise
eines solchen ADC an und vertraue auch mal den Formeln im Datenblatt.
Ja gut ist richtig. ändert im endeffeckt nichts am ergebniss. Es
verfälscht den wert an der 3 stelle nach´m komma, aber so genau muss es
jetzt auch nicht sein.
Der Grosse wrote:
> Ja gut ist richtig. ändert im endeffeckt nichts am ergebniss.
Es macht aber das Programm schneller (und u.U. auch kürzer), siehe oben!
Ob das in Deinem Fall eine Rolle spielt, musst Du selbst wissen.
Abgesehen davon heißt es "Effekt" ohne "c" und "Ergebnis" mit einem
"s"...
@ Lothar Miller
aha diese lösung sieht sehr elegant aus.
schaue ich mir mal eben an..
2 min später...
Es ist zwar eine gutte lösung es dauert aber wesentlich länger bis man
die richtige spannung berechnet hat. Wenn sie sich also schnell ändert
merkt man es halt nicht sofort.
Kann ich den nicht einfach 1 einzige messung machen ohne 4 messungen
durchzuführen, oder wird das ergebnis falsch?
Danke...
@Johannes M.
>Abgesehen davon heißt es "Effekt" ohne "c" und "Ergebnis" mit einem>"s"...
na, wer will den da schlau wirken... :-)
> Wenn sie sich also schnell ändert merkt man es halt nicht sofort.
Sowas nennt man Tiefpass ;-)
> Kann ich den nicht einfach 1 einzige messung machen...
Das ist der übliche Weg, du bist nur gleich am Anfang dieses Freds auf
falsche Pfade gelockt worden im
Beitrag "Re: ADC auslesen geht nicht richtig!".
Frei nach dem Motto: rechne dir einen schönen Wert her...
> Ein ADC "verliert" prinzipbedingt ein LSB und gibt für Werte,> die größer als VREF-1LSB sind, den Maximalwert aus.
Ist das nicht etwas extrem,
allen ADCs einfach so eine Schlamperei zu unterstellen ;-)
Für alle, die jetzt erschrocken nach dem verlorenen Bit suchen:
es ist die Null.
Ein 10-Bit Wandler kann 1024 Spannungs-Bereiche auflösen:
0 = 0 bis <1*Vref/1024
1 = 1*Vref/1024 bis <2*Vref/1024
2 = 2*Vref/1024 bis <3*Vref/1024
3 = 3*Vref/1024 bis <4*Vref/1024
4 = 4*Vref/1024 bis <5*Vref/1024
:
:
1021 = 1021*Vref/1024 bis <1022*Vref/1024
1022 = 1022*Vref/1024 bis <1023*Vref/1024
1023 = 1023*Vref/1024 bis <Vref
Wenn irgendwo im Zusammenhang mit AD-Wandlern eine Zahl
mit 2^n-1 (n=8....24) also 255, 511, 1023, 2047... auftaucht,
ist dort idR. irgendwas faul.
Lothar Miller wrote:
> Für alle, die jetzt erschrocken nach dem verlorenen Bit suchen:> es ist die Null.
Naja, eigentlich eher die Tatsache, dass ein ausgegebener Wert eben
nicht einen konkreten Spannungswert bezeichnet, sondern ein Intervall
zwischen zwei Spannungswerten. Und da ein "größer als Vref" nunmal nicht
auswertbar ist, kann man eben am oberen Ende nur sagen "Der
Spannungswert am Eingang ist größer als Vref - 1 LSB".
> Ein 10-Bit Wandler kann 1024 Spannungs-Bereiche auflösen:
Genau.
> [...]> 1023 = 1023*Vref/1024 bis <Vref
Naja, das letzte "<" würde ich weglassen. Auch Spannungen, die größer
als Vref sind, ergeben 1023 als Ausgangswert. Man kann eben keine
konkrete Aussage über dieses letzte Intervall treffen, außer dass die
Spannung größer als Vref - 1 LSB ist. Es gibt dort keine obere Grenze
mehr.
> Es gibt dort keine obere Grenze mehr.
Gilt (abhängig vom Wandler) üblicherweise auch für die untere Grenze bei
unipolaren Wandlern. Ein Wert kleiner 0 wird als 0 ausgegeben.
Formal richtig wäre dann die erste Zeile mit
0 = bis <1*Vref/1024
Lothar Miller wrote:
> Gilt (abhängig vom Wandler) üblicherweise auch für die untere Grenze bei> unipolaren Wandlern. Ein Wert kleiner 0 wird als 0 ausgegeben.>> Formal richtig wäre dann die erste Zeile mit> 0 = bis <1*Vref/1024
Rüchtüch. Die erste Zeile war mir grad nicht so aufgefallen.