10-bit vom A/D-Wandler nutzen

Gast #469281
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
Gast #469287
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.
Gast #469289
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...
Gast #469294
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;
.
.
.
Gast #469314
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;
}
Gast #469322
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.
Gast #469334
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.....
Gast #469358
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.)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren