www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATMega32 ADC0 zeigt immer max Wert.


Autor: Andreas Schneider (crsle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich möchte mittels LM35 die Temp messen und habe den LM35 am ADC0. 
Dieser liefert eine Spannung von ca. 2,31 V.

Leider zeigt das LCD immer 1023 an, egal ob das Kabel dran ist oder 
nicht. DIe Spannung steht eigentlich auf interne Ref, aber selbst wenn 
ich sie extern schalte und dort +5V dran habe passiert nix.
Das komische ist, dass es funktioniert hat, ich das ganze aber eine 
Weile hab ruhen lassen und jetzt geht nix mehr.

Hier die zwei Routinen, die ich probiert habe. Beide werden ausgewertet 
und zeigen 1023 an.

1. Routine

uint16_t ReadChannel(uint8_t mux)
{
  uint8_t i;
  uint16_t result;

  ADMUX = mux;                      // Kanal waehlen
  ADMUX |= (0<<REFS1) | (0<<REFS0); // interne Referenzspannung nutzen

  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
                               // setzen auf 8 (1) und ADC aktivieren 
(1)

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
lassen" */
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) ) {
     ;     // auf Abschluss der Konvertierung warten
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.

  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden 
Wandlungen */
  result = 0;
  for( i=0; i<4; i++ )
  {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) {
      ;   // auf Abschluss der Konvertierung warten
    }
    result += ADCW;        // Wandlungsergebnisse aufaddieren
  }
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)

  result /= 4;                     // Summe durch vier teilen = arithm. 
Mittelwert

  return result;
}


2. Routine
int MESSWERT (int kanal){

    int i=512,j=512;
    long int analogwert=0, analogwert1=0, analogwert2=0 ;

  while(j){

    while(i){
      ADCSRA=0x80;     // ADC eingeschaltet, kein Prescale
      ADMUX=kanal;        // ADC Ref auf Avcc, PC0 gewaehlt, normale 
Formatierung
      ADCSRA |=_BV(ADSC);   // single conversion mode ein
      while (ADCSRA & (1<<ADSC)) {;}  // auf Abschluss der Konvertierung 
warten
      analogwert+=ADCW;
      i--;
    }

    analogwert1 = analogwert/512;
    analogwert2 += analogwert1;
    j--;
  }

  analogwert=(analogwert2/512);

  return (analogwert);
}

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:

> nicht. DIe Spannung steht eigentlich auf interne Ref, aber selbst wenn

dann hast du ein anderes Datenblatt als ich

>   ADMUX |= (0<<REFS1) | (0<<REFS0); // interne Referenzspannung nutzen

was soll diese Zeile deiner Meinung nach machen?

Autor: Paul Baumann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe nichts von "C" aber m.E. bedeuten die Bits REFS0 und REFS1
auf Null, daß AREF verwendet wird und die interne Referenzspannung
abgeschaltet wird. (Datenblatt von 11/04)

Vielleicht hilft Dir das.
MfG Paul

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Ich verstehe nichts von "C" aber m.E. bedeuten die Bits REFS0 und REFS1
>auf Null, daß AREF verwendet wird und die interne Referenzspannung
>abgeschaltet wird. (Datenblatt von 11/04)

Ich auch nicht. Aber, da das eine ODER-Verknüpfung ist gilt das nur, 
wenn vorher schon 0 drin stand. Also sinnlos.

MfG Spess

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt auch so was wie for-Schleifen. while ist nicht alles auf der 
Welt. Und es gibt hier im Forum eine ganz tolle Funktion, mit der man 
C-Code schön formatiert darstellen kann, so dass man ihn lesen kann, 
ohne dabei Augenkrebs zu bekommen. Bitte benutze diese Funktion!

Und ja: Eine beliebige Zahl mit 0 verODERt ergibt wieder die beliebige 
Zahl, so dass man die Operation auch weglassen kann. Schau Dir mal den 
Artikel zum Thema Bitmanipulation an.

Ein Funktionsname in Großbuchstaben ist auch keine gute Idee. Gewöhne 
Dir besser gleich eindeutige Schreibweisen an: Makros in 
GROSSBUCHSTABEN, Variablen und Funktionen in kleinbuchstaben. Dann weiß 
man immer sofort, was was ist.

Autor: Andreas Schneider (crsle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ehrlich gesagt keine Ahnung was die Zeile macht, ich hab den Code aus 
einem Beispiel übernommen und hatte ja wie gesagt auch funktioniert.


den Formatier-flag kannte ich nicht aber hier nochmals formatiert.

1. Routine
uint16_t ReadChannel(uint8_t mux)
{
  uint8_t i;
  uint16_t result;

  ADMUX = mux;                      // Kanal waehlen
  ADMUX |= (0<<REFS1) | (0<<REFS0); // interne Referenzspannung nutzen

  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
                               // setzen auf 8 (1) und ADC aktivieren
(1)

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu
lassen" */
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) ) {
     ;     // auf Abschluss der Konvertierung warten
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.

  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden
Wandlungen */
  result = 0;
  for( i=0; i<4; i++ )
  {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) {
      ;   // auf Abschluss der Konvertierung warten
    }
    result += ADCW;        // Wandlungsergebnisse aufaddieren
  }
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)

  result /= 4;                     // Summe durch vier teilen = arithm.
Mittelwert

  return result;
}

2. Routine
int MESSWERT (int kanal){

    int i=512,j=512;
    long int analogwert=0, analogwert1=0, analogwert2=0 ;

  while(j){

    while(i){
      ADCSRA=0x80;     // ADC eingeschaltet, kein Prescale
      ADMUX=kanal;        // ADC Ref auf Avcc, PC0 gewaehlt, normale
Formatierung
      ADCSRA |=_BV(ADSC);   // single conversion mode ein
      while (ADCSRA & (1<<ADSC)) {;}  // auf Abschluss der Konvertierung
warten
      analogwert+=ADCW;
      i--;
    }

    analogwert1 = analogwert/512;
    analogwert2 += analogwert1;
    j--;
  }

  analogwert=(analogwert2/512);

  return (analogwert);
}

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:
> Ehrlich gesagt keine Ahnung was die Zeile macht, ich hab den Code aus
> einem Beispiel übernommen und hatte ja wie gesagt auch funktioniert.
Glückssache... Und auch toll: Einfach Code irgendwo her kopieren, ohne 
ihn auch nur ansatzweise zu verstehen...

> den Formatier-flag kannte ich nicht aber hier nochmals formatiert.
und mit den selben "Fehlern" drin...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:
>   return (analogwert);
BTW: return ist keine Funktion. Die Klammern gehören da nicht hin 
(auch wenn es nicht direkt falsch ist...)

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Abgesehen davon gehe ich davon aus, dass der eigentliche Fehler in dem 
Teil des Programms liegt, den Du nicht zeigst. Es fehlt z.B. die 
Port-Initialisierung, und mein Gefühl sagt mir, dass da vielleicht ein 
Pull-Up aktiviert sein könnte...

Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das hat bei mir funktioniert mit der gleiche Routine, aber in der 
Routine steckt ein Fehler.
Du addierst 5 X den Meßwert und dann result  /= 4 da muß /= 5 stehen.

Gruß
Jochen

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jochen wrote:
> Du addierst 5 X den Meßwert und dann result  /= 4 da muß /= 5 stehen.
Wo addiert er fünfmal den Messwert? Da steht
>  for( i=0; i<4; i++ )
Die Schleife wird viermal durchlaufen.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übrigens: In dem zweiten "Beispiel" werden 512*512 = ca. 262000 
Wandlungen pro Durchlauf durchgeführt. Das dauert bei 15 kSPS schon mehr 
als 17 Sekunden, bis das erste Ergebnis da ist...

Autor: Andreas Schneider (crsle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johannes M. ; Wow du schreibst soviel aber sagst so wenig zur Sache. 
Ich habe eigentlich nicht nach einer Lehrstunde in C-Syntax gefragt, 
sondern eine Lösung des Problems erhofft. Trotzdem vielen Dank, deine 
Tipps sind echt hilfreich.

Das erste Beispiel ist übrigens das GCC Tutorial, deshalb gehe ich davon 
aus, dass es genau so sein muss. Ich werde den Fehler mal im Rest 
suchen.

Autor: Andreas Schneider (crsle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okay das Problem lag tatsächlich woanders. Offensichtlich hatte ich den 
falschen Port geschaltet. grmpf :-) Nun geht die erste Variante 
zumindest soweit, dass sie bei 0V auch fast 0 und bei +5 V 1023 anzeigt. 
Der interne Ref ist ja auf 2,xx gestellt, so dass auch bei anschluß des 
LM35 1023 angezeigt wird, da dieser ca. 2,9 V bringt. Klingt irgendwie 
logisch :-) Werde also morgen mal versuchen den internen auf VCC zu 
stellen.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:


> Das erste Beispiel ist übrigens das GCC Tutorial, deshalb gehe ich davon
> aus, dass es genau so sein muss.

nein ist es nicht...

bei dir
ADMUX |= (0<<REFS1) | (0<<REFS0);

im Tutorial
ADMUX |= (1<<REFS1) | (1<<REFS0);

Deine Variante funktioniert wenn nur zufällig, weil REFS1 und REFS0 
beide als default Null sind, aber deine Code würde sie nicht wieder auf 
0 stellen, wenn sie vorher mal auf 1 gestanden hätten

Autor: Andreas Schneider (crsle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja stimmt, leider kann man hier nix editieren. Ich benutze die Variante 
mit 1

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:
> Ja stimmt, leider kann man hier nix editieren.
Doch, kann man. Aber nicht bis in alle Ewigkeit. Ne Viertelstunde nach 
Absenden geht es glaub ich...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:
> @Johannes M. ; Wow du schreibst soviel aber sagst so wenig zur Sache.
> Ich habe eigentlich nicht nach einer Lehrstunde in C-Syntax gefragt,
> sondern eine Lösung des Problems erhofft.
Naj, wenn schon, dann richtig. Wenn ich mir den Code schon anschaue, 
dann kriegste auch alles, was mir auffällt, um die Ohren gehauen...;-)

Autor: Andreas Schneider (crsle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Naj, wenn schon, dann richtig. Wenn ich mir den Code schon anschaue,
> dann kriegste auch alles, was mir auffällt, um die Ohren gehauen...;-)

Okay hast ja recht :-)

Funktioniert nun übrigens endlich. Problem war die Kombination aus 
Port-Fehler und Ref-Spannung falsch gesetzt. Nachdem diese auf VCC ist, 
gehts so wie es sollte.
ADMUX = (0<<REFS1) | (1<<REFS0); // interne Ref auf VCC

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schneider wrote:
> ADMUX = (0<<REFS1) | (1<<REFS0); // interne Ref auf VCC
OK, das geht zwar, und es gibt auch Leute, die sagen, dass sie das so 
übersichtlicher finden, wenn alle Bits da stehen, aber: Die Operation 
"(0<<REFS1)" macht rein gar nichts, und sinnlose Operationen sollte man 
besser ganz weglassen. Eine Null kann man schieben, so lange man will, 
es bleibt eine Null. Und 0 | IRGENDWAS ist einfach nur IRGENDWAS...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.