Forum: Mikrocontroller und Digitale Elektronik Atmega32: ADC Ergebnis mit AVCC als VREF immer 1023


von Daniel M. (dandansen)


Lesenswert?

Moin,
habe mir eine kleine Schaltung entworfen (siehe Schaltplan). Ich will 
eine Spannung, die von einem Absolut-Winkel-Sensor ausgegeben wird und 
zwischen 0 und 5 V liegt, digitalisieren. Den AREF Pin habe ich mit 
einem 100nF Kondensator gegen Ground beschaltet. An AVCC liegt eine 
(einigermaßen) geglättete 5V Spannung an (auch gemessen!).
Wenn ich durch die Reference Selection Bits die interne Spannung von 
2,5V einstelle, liegt diese auch an AREF an und die Wandlung klappt gut 
(natürlich nur bis 2,5V).
Wähle ich nun AVCC als VREF aus, liegt an AREF seltsamerweise keine 
Spannung an und der ausgegebene Wert ist somit immer 1023.

Was ich schon gecheckt habe:
- uc getauscht, da ich vermutet habe, das die Spannung intern nicht 
umgeschaltete wird -> gleiches Ergebnis

- Stromfluß durch die Schaltung liegt bei beiden Modi bei ca. 124 mA

Könnte es an dem Kondensator an AREF liegen? Kann den auf der Schaltung 
nicht messen und auslöten ist sehr fummelig.

Ach ja hier sind noch die verwendeten c-Funktionen für den ADC:

/* initialize ADC with a frequency of f_ck/128 in single conversion mode 
*/

void adc_init(void)
{
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
  // AVCC is reference voltage, external capacitor on AREF
  ADMUX = (0<<REFS1) | (1<REFS0) |(1<<MUX2) | (1<<MUX1) | (1<<MUX0);

  /* Dummy-Readout of the first value */
  ADCSRA |= (1<<ADSC);
  while (ADCSRA & (1<<ADSC)) //wait for convertion to complete
  {
    ;
  }
}

float read_channel(unsigned int no_samples)
{
  double result = 0;
  unsigned int i;
  for (i=0; i < no_samples; i++)
  {
    ADCSRA |= (1<<ADSC); //one conversion
    while (ADCSRA & (1<<ADSC)) //wait for conversion to complete
      {
        ;
      }
    result += ADC;
  }
  result /= no_samples;
  return (float) result;
}

von Daniel M. (dandansen)


Angehängte Dateien:

Lesenswert?

Hier ist der Anhang.

von fubu1000 (Gast)


Lesenswert?

hallo,
vermute du denkst das die 5V Spannung intern erzeugt wird, dem ist aber 
nicht so !!!!  deswegen misst du auch keine 5v, sondern 0V.
du musst 5v schon an AREF anlegen, genau wie an AVCC, wenn du mit 5V 
arbeiten willst.
gruss fubu

von Rahul, der Trollige (Gast)


Lesenswert?

>du musst 5v schon an AREF anlegen, genau wie an AVCC, wenn du mit 5V
>arbeiten willst.

Nein, muß man nicht.

von johnny.m (Gast)


Lesenswert?

@fubu1000:
Nein! Genau das muss (und soll) man nicht machen! Bei allen aktuellen 
AVRs mit A/D-Wandler ist AVCC als Referenz intern einstellbar! Niemals 
AREF extern mit AVCC verbinden!!

von johnny.m (Gast)


Lesenswert?

Tja, ich hätte ja getippt, dass Du versehentlich an dem Analog-Eingang 
nen Pull-Up aktiviert haben könntest. Aber da es ja anscheinend mit der 
2,5V-Referenz klappt, scheidet das ja aus... Was anderes fällt mir so 
auf die Schnelle auch nicht ein...

von Holger (Gast)


Lesenswert?

Wo wird das ADC-DatenReg High and Low gelesen ???
10 Bits breit Messen ???
bezogen auf V.Ref
X-MessBits Milivolt
ADC Messbits.

von fubu1000 (Gast)


Lesenswert?

hallo,
nochmal datenblatt angeschaut habt recht "muss" man net anschliessen 
AREF an 5V !!!!

@ johnny warum sol man das nit machen 5V an AREF bei mir klappts so 
super bei nem ATMEGA8.
gruss fubu

von Rahul, der Trollige (Gast)


Lesenswert?

>warum sol man das nit machen 5V an AREF bei mir klappts so
>super bei nem ATMEGA8.

Das ist dann eine externe Einspeisung. Da könntest du auch 4,096V 
anlegen...

von johnny.m (Gast)


Lesenswert?

> warum sol man das nit machen 5V an AREF
Weil man sich dadurch jeglicher Möglichkeiten beraubt, eine andere 
Referenz als AVCC zu benutzen und weil es, wenn man intern ein Bit 
falsch setzt und eine andere Referenz auswählt, einen Kurzschluss gibt. 
AVCC an AREF macht nur Sinn bei den alten AT90Sxxxx-AVRs, die noch 
keine internen Einstellmöglichkeiten hatten.

von Sonic (Gast)


Lesenswert?

@Daniel:
Den 'Dummy read' kannst du dir schenken.
Laut Datenblatt ist zu beachten dass, wenn vor einer Messung der MUX 
umgeschaltet wurde, eine gewisse Zeit zu warten ist. Empirisch ermittelt 
habe ich min. 40µs herausgefunden. Wenn die Betriebsart umgeschaltet 
wird musst du min. 120µs Pause bis zur Messung machen, sonst kommt nur 
Schrott 'raus!
So wie's in deinem Codeschnipsel ist vergehen da mit Sicherheit keine 
40µs!

von Ray (Gast) (Gast)


Lesenswert?

Hallo,

ich dachte, es reicht den ADC anzuhalten, z.B. den MUX umzustellen und 
dann eine neue Messung zu starten und zu warten, bis der ADC fertig ist. 
Soweit mir bekannt ist, sagt Atmel nur, dass beim Wechsel eines 
differentiellen Eingangs oder einmal nach dem Wechsel der Referenz 
125µsec Wartezeit eingehalten werden sollen. Da ich beim Umschalten der 
ADC-Eingänge (single-ended nicht differentieller Modus) auch schon 
Probleme hatte und dieses auch nur durch Warten lösen konnte. Und zwar 
langes warten: wenn ich als Teiler 128 bei 16MHz Systemtakt wähle, 
sollte ich als Umsetzzeit ca. 104µsec bekommen, aber gesehen habe ich, 
dass ich einige Messungen wegwerfen musste, bis man gesehen hat, dass 
der Kanal auch wirklich gewechselt wurde.

Mein Vorgehen:
ADCSR=0x07; // ADC anhaltzen
ADMUX=0x42; // MUX neu setzen
ADCSR=0xc7; // ADC starten
while (ADSC==1); // warten bis ADC fertig
adc_in=ADCL;  // Ergebnis lesen
adc_in+=ADCH << 8;

ADCSR = 0xc7;   //ADC neustarten
while (ADSC==1);

adc_in=ADCL;
adc_in+=ADCH << 8;

Damit müsste ich ja nach dem Kanal Wechsel zwei Umsetzungen angestossen 
haben und ein evtl. falsches (erstes) Resultat verworfen haben. Leider 
habe ich gesehen, dass ich bis zu 10 Messungen wegwerfen musste, bis ich 
ein plausibles Ergebnis hatte. Irgendwie verstehe ch es nicht - wo mach 
ich da den Fehler?

Tschüss

Ray

von Sonic (Gast)


Lesenswert?

Atmel schweigt sich darüber aus. Jedenfalls steht nix im Datenblatt 
darüber. Irgendwo (weiß leider nicht mehr wo) habe ich mal gelesen dass 
der MUX 60µs Einschwingzeit hätte. Durch Versuche stellte ich fest, dass 
er kleiner 40µs tatsächlich Mist gemessen hat. Also nach der Umschaltung 
min. 40µs warten, dann klappt's!

von Sonic (Gast)


Lesenswert?

Ich nochmal,
hier meine ADC-Funktion:

double ADC_conversion(unsigned char mux, unsigned char MW)  // Spannung 
messen (single ended)
{
ADMUX = mux;      // Multiplexer-Modus einstellen
_delay_us(40);      // Pause bis Multiplexer eingestellt ist
double Messwert = 0;
unsigned int ADC_temp;
unsigned char i = 1;

do
{
  ADCSRA |= (1<<ADSC);       // 'single conversion' einleiten
  while(!(ADCSRA & 0x10));   // auf ende der Wandlung warten, ADIF Flag 
'1'
  ADC_temp = ADCL;           // ADCL Register lesen
  ADC_temp += (ADCH << 8);   // ADCH Register lesen
  Messwert += ADC_temp;      // Ergebnisse der Messungen addieren
  i++;           // Schleifenzähler erhöhen
}
while (i <= MW);         // MW Messungen für bessere Genauigkeit
Messwert = Messwert/MW;       // Mittelwert der globalen Variable 
zuweisen

return (Messwert);
}

von Ray (Gast)


Lesenswert?

Hallo,

vielen Dank - aber ich habe glaube ich meinen Fehler jetzt gesehen - 
anscheinend muss man Sachen immer erst anderen Leuten zeigen, dass man 
in seinem eigen Code die Fehler sieht. Der Vergleich auf

while (ADSC==1);

ist natürlich absoluter Quatsch, weil ADSC ja eine Konstante (ich denke 
6) ist, damit warte ich natürlich nicht bis der ADC fertig ist, sondern 
laufe sofort weiter, daher muss ich auch immer soviele Ergebnisse 
wegschmeissen - weil der ADC noch gar nichts neues geliefert hat 
(schäm).

Danke

Ray

von Dan (Gast)


Lesenswert?

Hab den Fehler gefunden:

ADMUX = (0<<REFS1) | (1<REFS0) |(1<<MUX2) | (1<<MUX1) | (1<<MUX0);

Damit wird REFS0 natürlich nicht gesetzt. Saublöd, aber irgendwie auch 
schwer zu entdecken, da es ja keinen Compilerfehler gibt.

von Rahul, der Trollige (Gast)


Lesenswert?

>Damit wird REFS0 natürlich nicht gesetzt. Saublöd, aber irgendwie auch
>schwer zu entdecken, da es ja keinen Compilerfehler gibt.

REFS0 wird gesetzt, REFS1 aber nicht...

von Dan (Gast)


Lesenswert?

meinte ich auch.

von Dan (Gast)


Lesenswert?

nee. quatsch. REFS1 wird aufgrund des einfachen Pfeils nicht gesetzt.

von Rahul, der Trollige (Gast)


Lesenswert?

Stimmt... sollte ja 1<<REFS1 heissen.

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.