Hallo, ich habe bisher beim Atmega88 den A/D-Wandler mit einer Aufösung von 8-bit verwendet und habe somit Werte zwischen 0 und 255 bekommen. Wenn ich jetzt die 10-bit Auflösung benutze, müsste ich doch Werte zwischen 0 und 1024 bekommen. Schreibe ich mir den erzeugten 10-bit Wert vom AD-Wandler nun in eine Integer Variable, bekomme ich aber Werte bis 65535. Warum ist das so? Stehen die 10-bit vom A/D-Wandler dann an den höchstwerigsten Stellen der 16-bit Variablen und die anderen werden mit Nullen aufgefüllt? Wie kann ich nur die 10-bit benutzen, also Werte zwischen 0 und 1024 bekommen? Gruß Björn
>zwischen 0 und 1024 bekommen Nö, nur zwischen 0 und 1023 >Warum ist das so? Stehen die 10-bit vom A/D-Wandler dann an den >höchstwerigsten Stellen der 16-bit Variablen und die anderen werden mit >Nullen aufgefüllt? Hast du vielleicht noch ADLAR gesetzt? Sollte man dann nicht tun... >Wie kann ich nur die 10-bit benutzen, also Werte zwischen 0 und 1024 >bekommen? Gar nicht (siehe oben). Du kannst Werte zwischen 0 und 1023 bekommen, wenn du das ADLAR-Bit nicht setzt.
Es gibt ein Steuerbit mit dem Namen ADLAR (ADC Left Adjust Result). Wenn dieses Bit gesetzt ist, wird das Ergebnis der Wandlung "links" ausgerichtet (was v.a. dann Sinn macht, wenn man nur 8 Bit Auflösung braucht, man muss dann nämlich nur das High-Byte auslesen), andernfalls rechts. Wenn Du höhere Werte als 1023 bekommst, ist dieses Bit vermutlich gesetzt. Lösche es und Du wirst zufrieden sein...
>Und welches Byte muss ich dann auslesen? High- oder Low-Byte?
Grundlagen: Ein Byte kann keine 10bit breiten Informationen einhalten
(geht einfach nicht, oder hat schon jemand eine Byte-Kompression
erfunden?)
Du musst ein unsigned integer Variable (uint_16?) benutzen:
unsigned int wert;
.
.
.
.
wert = ADC;
.
.
.
> Und welches Byte muss ich dann auslesen? High- oder Low-Byte?
Beide natürlich. Aber der Oskar ist eh wieder schneller...
Bekomme jetzt aber wieder nur Werte zwischen 0 und 255. Auslesen so: AD_Wert = ADCL; AD_Wert = AD_Wert + ADCH; Oder mach ich das falsch? Im Datenblatt steht, zuerst das Low_Byte und dann das High.
>AD_Wert = AD_Wert + ADCH;
Wenn du im Datenblatt weiter unten guckst, steht da auch, wie man beide
Bytes "gleichzeitig" ausliest.
Das habe ich oben zwar schon geschrieben, scheint dich aber nicht zu
interessieren...
> Das habe ich oben zwar schon geschrieben, scheint dich aber nicht zu
>interessieren...
Doch, hab ich gesehen und auch ausprobiert: Klappt aber nicht. Im meiner
Variablen steht ein Wert von 61568.
unsigned int AD_Wert;
void ADC_wandlung() //PORTC, Bit2
{
ADMUX &= ~((1<<MUX0)|(1<<MUX2)|(1<<MUX3)); //ADC2 eingestellt
ADMUX |= (1<<MUX1);
ADCSRA = (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);
ADMUX |= (1<<REFS0);
ADCSRA |= (1<<ADSC); //Eine AD-Wandlung zur Initialisierung
while (ADCSRA & (1<<ADSC))
{
;
}
ADCSRA |= (1<<ADSC); //AD Wandlung
while (ADCSRA & (1<<ADSC))
{
;
}
ADCSRA &= ~(1<<ADSC); //AD Wandlung deaktivieren
AD_Wert; = ADC;
}
> AD_Wert; = ADC; Das ist ein Semikolon zu viel. > ADCSRA |= (1<<ADSC); //Eine AD-Wandlung zur Initialisierung > while (ADCSRA & (1<<ADSC)) > { > ; > } > > ADCSRA |= (1<<ADSC); //AD Wandlung > while (ADCSRA & (1<<ADSC)) > { > ; > } > > ADCSRA &= ~(1<<ADSC); //AD Wandlung deaktivieren Du machst 2 Messungen nacheinander, ohne das erste Ergebnis auszulesen. Warum? Und die Wandlung brauchst du nicht deaktivieren. Guck dir am besten mal das gcc-Tutorium zu dem Thema an.
> Du machst 2 Messungen nacheinander, ohne das erste Ergebnis auszulesen. > Warum? Weil laut Datenblatt ein paar µs von der Initialisierung bis zur ersten Wandlung vergehen müssen. Das GCC-Tutorial hab ich mir schon angeschaut. Egal wie ich es mache: AD_Wert = ADCL; AD_Wert += (ADCH << 8); oder so AD_Wert = ADCW; oder so AD_Wert = ADC; ich krieg immer Werte bis 6500 raus.....
Um welchen Controller handelt es sich? Kannst du dein komplettes Programm bitte posten?!
> ADCSRA &= ~(1<<ADSC); //AD Wandlung deaktivieren
Den ADC schaltet man durch löschen des ADEN-Bits aus. Das ADSC wird
automatisch nach dem Ende der Wandlung gelöscht. Du fragst es ja auch
schließlich daraufhin ab.
@Rahul-Oskar: ATMega88 (siehe gaaaaanz oben) ;-) Aber das mit dem kompletten Programm wäre echt ne feine Sache... Hab keine Lust zum Hellsehen heute...
>(siehe gaaaaanz oben) ;-)
Zwischen den beiden Threads steht soviel Zeug - da überliest man das
gerne mal...
Das wäre auch noch was gutes fürs Forum: ein kleiner Kasten am Rand, in
dem noch mal eine Art Zusammenfassung (z.B. Controller, Problem,
Entwicklungsumgebung etc) steht...
>>(siehe gaaaaanz oben) ;-) >Zwischen den beiden Threads steht soviel Zeug - da überliest man das >gerne mal... Aber totzdem "Danke"! Wieso übernimmt man eigentlich nie irgendwelche Beispiele direkt? (Bin gestern mal wieder über das UBSEL-Bit gefallen...[Nein, ich hab mir nicht das Bein am Bit, sondern den Kopf - gewollt - am Tisch danach gestossen...]) Bei mir gibt es immer eine ADC-Init-Routine und eine ADC-lese-Routine. void init_ADC(void) { ADMUX = (1<<REFS0); // REF = AVCC ADCSRA = (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2); // ADC freigeben, Prescaler = 128 (Wandelfrequenz = ...) } unsigned int read_adc(unsinged char kanal) { ADMUX |= (kanal & 0x0F); ADCSR |= (1<<ADSC); while(ADCSR & (1<<ADSC)); return ADC; } Ausm Kopf...(kann also noch Fehler enthalten; Gewähr wird nicht gegeben.)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.