Forum: Mikrocontroller und Digitale Elektronik 10-bit vom A/D-Wandler nutzen


von Björn (Gast)


Lesenswert?

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

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>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.

von johnny.m (Gast)


Lesenswert?

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...

von Björn (Gast)


Lesenswert?

Und welches Byte muss ich dann auslesen? High- oder Low-Byte?

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

@Johnny: und wieder zu langsam! ;-)

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>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;
.
.
.

von johnny.m (Gast)


Lesenswert?

> Und welches Byte muss ich dann auslesen? High- oder Low-Byte?
Beide natürlich. Aber der Oskar ist eh wieder schneller...

von johnny.m (Gast)


Lesenswert?

Wusste ich doch...

von Björn (Gast)


Lesenswert?

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.

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>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...

von Björn (Gast)


Lesenswert?

> 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;
}

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>  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.

von Björn (Gast)


Lesenswert?

> 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.....

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

Um welchen Controller handelt es sich?
Kannst du dein komplettes Programm bitte posten?!

von johnny.m (Gast)


Lesenswert?

> 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.

von johnny.m (Gast)


Lesenswert?

@Rahul-Oskar:
ATMega88 (siehe gaaaaanz oben) ;-)

Aber das mit dem kompletten Programm wäre echt ne feine Sache... Hab 
keine Lust zum  Hellsehen heute...

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>(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...

von fieser Rahul (auch Oskar genannt) (Gast)


Lesenswert?

>>(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
Noch kein Account? Hier anmelden.