Forum: Mikrocontroller und Digitale Elektronik ADC bei ATmega 328p liefert falsche Werte?!


von Mike Litoris (Gast)


Lesenswert?

Hi!

ich probiere gerade den Status eines Schalters am ADC7 Pin des 328P mit 
dem ADC abzufragen.

Ich benutze folgenden Code:
1
//Startet und konfiguriert den ADC.
2
int ADCKonfiguration(void)
3
{
4
  //ADC Multiplexer auf ADC7 pin einstellen
5
  sbi(ADMUX, MUX2);
6
  sbi(ADMUX, MUX1);
7
  sbi(ADMUX, MUX0);
8
  
9
  //ADLAR im ADMUX Register auf 1 setzen. Dadurch wird das 10bittige Ergebnis linksbündig in den Registern ADCH und ADCL gespeichert.
10
  sbi(ADMUX, ADLAR);
11
  
12
  //ADC einschalten
13
  sbi(ADCSRA, ADEN);
14
  //Eine Messung durchführen
15
  sbi(ADCSRA, ADSC);
16
}
17
18
19
//Ließt den ADC7 Pin aus und gibt die 8 hochwertigsten Bits zurück.
20
int ADC7Read(void)
21
{
22
  //ADC Conversion starten:
23
  sbi(ADCSRA, ADSC);
24
  
25
  return ADCH;
26
}

Leider gibt mit die Funktion ADC7Read immer 255 zurück. Auch wenn ich 
den Pin mit einer Drahtbrücke direkt auf Masse ziehe. Einen Defekt in 
der Schaltung kann ich also fast ausschließen.

Stimmt die Initialisierung des ADCs soweit? Hab ich evtl. einen falschen 
Modus verwendet oder ein Register vergessen?

Ist mein "erstes Mal" mit dem ADC ;-)

Grüße und Danke!

von Jasch (Gast)


Lesenswert?

Warum?

Ein Schalter ist ein/aus, 1/0, true/false - binär halt.

Kannst Du trivial ohne ADC einlesen.

Was möglicherweise das Problem mit dem ADC ist: der braucht ein bisschen 
Zeit, Du kannst nicht sofort das Ergebnis lesen nachdem Du eben erst 
einen Umsetzungs-Zyklus gestartet hast. Siehe Beschreibung des ADC im 
Manual. Ob Deine Initialisierung für den ADC vollständig/korrekt ist - 
keine Ahnung, habe ich nicht gecheckt, aber wieder, siehe Manual.

von public (Gast)


Lesenswert?

Hey Mike,

ich geh mal davon aus du willst unabhängig von der Sinnhaftigkeit 
trotzdem den ADC verwenden. Schau dir doch mal hier auf der Seite das 
AVR-Tutorial zum Thema ADC an, so ein µC hat praktischerweise FLAGs die 
dir sagen ob/wann der ADC mit samplen/wandeln fertig ist.

Einen einzelnen Wert messen ist ja immer so eine Sache, da werden aus 
einem 8-Bit ADC gerne mal 7 oder 6 oder weniger? Besser ein array voll 
mit werten sammeln und dann mal schauen was drin steht, da lernst du 
eine ganze menge.

bis dahin beste grüße
public

von Frank (Gast)


Lesenswert?

Es muss gewartet werden bis die ADC Wandlung abgeschlossen ist!
Schau dir mal die Codebeispiele zum ADC an.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mike Litoris schrieb:
> //ADC Multiplexer auf ADC7 pin einstellen
>   sbi(ADMUX, MUX2);
>   sbi(ADMUX, MUX1);
>   sbi(ADMUX, MUX0);
>
>   //ADLAR im ADMUX Register auf 1 setzen. Dadurch wird das 10bittige
> Ergebnis linksbündig in den Registern ADCH und ADCL gespeichert.
>   sbi(ADMUX, ADLAR);

Wie bist du denn auf diese Idee gekommen? Das geht alles viel einfacher 
und in einer Zeile, ohne irgendwelche Verrenkungen:
1
ADMUX = (1 << ADLAR)|(7 << MUX0); 
2
// oder 
3
ADMUX = (1 << ADLAR)|(1 << MUX2)|(1 << MUX1)|(1 << MUX0);
Selbst in Assembler würde man nicht auf die Idee kommen, das alles mit 
sbi zu lösen:
1
  ldi r16, (1 << ADLAR)|(7 << MUX0)
2
  out ADMUX,r16

: Bearbeitet durch User
von Mike Litoris (Gast)


Lesenswert?

Jasch schrieb:
> Ein Schalter ist ein/aus, 1/0, true/false - binär halt.
>
> Kannst Du trivial ohne ADC einlesen.

Ja, soweit bin ich mit meinen Kentnissen schon...

Geht aber in dem Falle nicht anders, da sonst keine Pins frei sind.

Frank schrieb:
> Es muss gewartet werden bis die ADC Wandlung abgeschlossen ist!
> Schau dir mal die Codebeispiele zum ADC an.

ok, danke für den Tipp. Ich erninnere mich, dass dazu im Datenblatt was 
stand. Hab dem aber für meine Zwecke keine bedeutung zugemessen, da das 
ja nicht zeitkritisch ist...

Grüße!

von Thomas E. (thomase)


Lesenswert?

Mike Litoris schrieb:
> //Ließt den ADC7 Pin aus und gibt die 8 hochwertigsten Bits zurück.
> int ADC7Read(void)
> {
>   //ADC Conversion starten:
>   sbi(ADCSRA, ADSC);
>
>   return ADCH;
> }

Wenn die Wandlung gestartet wird, muss du auch warten, bis sie fertig 
ist. Den Wert kannst du nicht sofort auslesen.

mfg.

von public (Gast)


Lesenswert?

Ey sach mal dein Name "mike litoris" ist ja wohl nen bissl frech wa?

von Ingo L. (corrtexx)


Lesenswert?

public schrieb:
> Ey sach mal dein Name "mike litoris" ist ja wohl nen bissl frech wa?
Und du bist so katholisch das es selbst dem Papst peinlich wäre ;)


SCNR

von Mike Litoris (Gast)


Lesenswert?

Matthias Sch. schrieb:
> Wie bist du denn auf diese Idee gekommen? Das geht alles viel einfacher
> und in einer Zeile, ohne irgendwelche Verrenkungen:ADMUX = (1 <<
> ADLAR)|(7 << MUX0);
> // oder
> ADMUX = (1 << ADLAR)|(1 << MUX2)|(1 << MUX1)|(1 << MUX0);

Ja das sieht natürlich besser aus. Gehen sollte es aber auch auf meinen 
Weg, oder?

Thomas Eckmann schrieb:
> Wenn die Wandlung gestartet wird, muss du auch warten, bis sie fertig
> ist. Den Wert kannst du nicht sofort auslesen.

Wurde ja schon öfter angemerkt, hab ich ergänzt:
1
//Startet und konfiguriert den ADC.
2
int ADCKonfiguration(void)
3
{
4
  //ADC Multiplexer auf ADC7 pin einstellen
5
  sbi(ADMUX, MUX2);
6
  sbi(ADMUX, MUX1);
7
  sbi(ADMUX, MUX0);
8
  
9
  //ADLAR im ADMUX Register auf 1 setzen. Dadurch wird das 10bittige Ergebnis linksbündig in den Registern ADCH und ADCL gespeichert.
10
  sbi(ADMUX, ADLAR);
11
  
12
  //ADC einschalten
13
  sbi(ADCSRA, ADEN);
14
  //Eine Messung durchführen
15
  sbi(ADCSRA, ADSC);
16
}
17
18
19
//Ließt den ADC7 Pin aus und gibt die 8 hochwertigsten Bits zurück.
20
int ADC7Read(void)
21
{
22
  //ADC Conversion starten:
23
  sbi(ADCSRA, ADSC);
24
  
25
  //Warten bis ADWandlung fertig.
26
  while (ADCSRA & (1<<ADSC))  
27
  
28
  //Eingelesenen Wert zurückgeben.
29
  return ADCH;
30
}

Welche Werte in welches Register kommen, stimmt "eigentlich" mit dem 
Datenblatt überein. Kann da evtl. mal jemand drüberschauen?

Grüße!

public schrieb:
> Ey sach mal dein Name "mike litoris" ist ja wohl nen bissl frech wa?
Ey sach mal hast du damit ein Problem? Kannst gerne vorbeikommen!

von Uwe (de0508)


Lesenswert?

Hallo Mike Litoris schrieb:
> //Warten bis ADWandlung fertig.
>   while (ADCSRA & (1<<ADSC))
Hier ist noch ein Fehler, es fehlt der While-Block
Entweder als { } oder als ;

In Init der ADC-Funtion schreibst Du:
1
 //Eine Messung durchführen
2
  sbi(ADCSRA, ADSC);
Aber diese Anweisung ist keine Messung, sondern nur das starten einer 
ADC-Messung.
Man muss auch das Ende abwarten und denn ADC-Messwert auslesen.

: Bearbeitet durch User
von Hugh Jass (Gast)


Lesenswert?

Mike Litoris schrieb:

>> Ey sach mal dein Name "mike litoris" ist ja wohl nen bissl frech wa?
> Ey sach mal hast du damit ein Problem? Kannst gerne vorbeikommen!

"Kannst gerne kommen!" hätte es heißen müssen. Manchmal könnte man an 
dieser Welt und ihren Insassen verzweifeln.

von Mike Litoris (Gast)


Lesenswert?

Hallo Uwe, danke für deine Antwort!

Du hast natürlich Recht, dass da die Klammer fehlt. Ist mir direkt nach 
dem Absenden aufgefallen.

Wegen dem Starten der Messung in der InitFunktion:

Ich starte dort schonmal eine Messung, weil die erste Messung immer 
mehrere Takte braucht. Ausgelesen wird das Ergebnis dieser Messung nie.

Im Programm Frage ich den Taster mit der ADC7Read Funktion ab, dort wird 
auch das ADCH Register zurückgegeben.

Grüße!

von Thomas E. (thomase)


Lesenswert?

Mike Litoris schrieb:
> //ADC einschalten
>   sbi(ADCSRA, ADEN);
>   //Eine Messung durchführen
>   sbi(ADCSRA, ADSC);

Auch hier musst du warten:
1
while(ADCSRA & (1 << ADSC));

und das Register auslesen oder zumindest so tun als ob:
1
(void)ADCH;

mfg.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Der ADC Prescaler muss auch noch eingestellt werden. (ADPS Bits)

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.