Forum: Mikrocontroller und Digitale Elektronik ATMEGA325 - ADC einlesen ? - warum geht nicht ???!?!?!


von Neubi (Gast)


Lesenswert?

hey,

möchte gerne kanalA und kanalB am ATMEGA325 einlesen. leider bekomme
ich auf kanalA und kanalB immer das gleiche ergebnis (ergebnis der 1ten
wandlung). im debug-singlestep-betrieb bekomme ich richtige
wandlungsergebnisse. einfügen von kleinen und grossen delays hat keinen
erfolg bebracht ?!?!

-> was tun ?? - im datenblatt ist nichts vermerkt was darauf hinweist
?!?

HILFE !!!!
thx Neubi



void main(void)
{
byte x,y;

  ADCSRA = 0x86;       // init ADC (clock,...)
  x=ADReadResult(0);
  y=ADReadResult(1);
}



byte ADReadResult(byte Channel)
{
word Result=0;

  ADMUX = Channel;  // kanal wechseln
  ADCSRA |= 0x40;   // wandlung starten
  while(!(ADCSRA & 0x10));  // warten bis wandlung fertig
  ADCSRA |= 0x10;   // int-flag löschen

  Result = (ADCH << 8) + ADCL;  // ergebnis holen
  return (Result >> 2);         // auf 8bit kürzen
}

von johnny.m (Gast)


Lesenswert?

Du musst beim lesen der AD-Register unbedingt die Reihenfolge einhalten
(erst das Low Byte ADCL, dann das High-Byte ADCH). Was der Compiler aus
dem Konstrukt macht, das Du da geschrieben hast, ist undefiniert! Am
besten direkt das 16-Bit-Ergebnis aus ADC (oder ADCW) auslesen. dann
macht der Compiler das automatisch korrekt.

Gruß

Johnny

von johnny.m (Gast)


Lesenswert?

Falls es nicht einleuchtet: Sobald das Low-Byte (ADCL) gelesen wird,
sperrt der Controller das High-Byte (ADCH) gegen Schreibzugriffe durch
den ADC. Erst wenn das High-Byte gelesen wird, gibt der Controller die
beiden Register wieder frei, so dass der ADC das nächste Ergebnis
ablegen kann.

Dein Code liest aber erst das High-Byte ein, shiftet es um 8 Stellen
nach links und addiert dann das Low-Byte. In diesem Moment sperrt der
Controller das komplette Register, so dass alle folgenden
Wandlungsergebnisse nicht gespeichert werden!

Die mir bekannten Compiler (WINAVR, CodeVision) besitzen alle in der
entsprechenden Headerdatei eine Definition eines
16-Bit-Ergebnisregisters ADC oder ADCW, das direkt eingelesen werden
kann:

Result = ADC;

Wenn Du eh nur 8 Bit brauchst, dann setz das ADLAR-Bit in ADMUX
(dadurch wird das Ergebnis linksbündig in den Registern ADCH und ADCL
gespeichert) und lies immer NUR das High-Byte aus. Das reduziert den
Rechenaufwand!

Gruß

Johnny

von Rahul (Gast)


Lesenswert?

im Prinzip müsste es dann ja so funktionieren:

Result = ADCL + (ADCH<<8);

IAR: Result = ADC;

von johnny.m (Gast)


Lesenswert?

> Result = ADCL + (ADCH<<8);

Ist aber (glaub ich) im ANSI-Standard nicht definiert, in welcher
Reihenfolge der Compiler das abarbeitet.

Am besten in mehreren Schritten machen, dann ist man auf der sicheren
Seite. Und der Code wird trotzdem nicht größer.

Am allerbesten die Variante mit ADC! Dafür isse da! Und für 8 Bit siehe
oben!

Gruß

Johnny

von Neubi (Gast)


Lesenswert?

recht schönen dank - jetzt funkts

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.