Atmega32: ADC Ergebnis mit AVCC als VREF immer 1023

OP #483535
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;
}
Gast #483550
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
Gast #483564
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...
Gast #483600
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.
Gast #483837
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!
Gast #485035
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
Gast #485036
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!
Gast #485041
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);
}
Gast #485210
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
Gast #486180
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.

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