ATMega32 ADC0 zeigt immer max Wert.

OP #1204918
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);
}
Gast #1204980
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
Gast #1204990
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
#1205008
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.
OP #1205049
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
1
uint16_t ReadChannel(uint8_t mux)
2
{
3
  uint8_t i;
4
  uint16_t result;
5

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

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

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

25
  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden
26
Wandlungen */
27
  result = 0;
28
  for( i=0; i<4; i++ )
29
  {
30
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
31
    while ( ADCSRA & (1<<ADSC) ) {
32
      ;   // auf Abschluss der Konvertierung warten
33
    }
34
    result += ADCW;        // Wandlungsergebnisse aufaddieren
35
  }
36
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)
37

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

41
  return result;
42
}

2. Routine
1
int MESSWERT (int kanal){
2

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

6
  while(j){
7

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

19
    analogwert1 = analogwert/512;
20
    analogwert2 += analogwert1;
21
    j--;
22
  }
23

24
  analogwert=(analogwert2/512);
25

26
  return (analogwert);
27
}
#1205062
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...
OP #1205152
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.
OP #1205268
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.
#1205366
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
1
ADMUX |= (0<<REFS1) | (0<<REFS0);

im Tutorial
1
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
#1205452
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...;-)
OP #1205484
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.
1
ADMUX = (0<<REFS1) | (1<<REFS0); // interne Ref auf VCC
#1205489
Lesenswert?

Andreas Schneider wrote:
1
> 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

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