Forum: Mikrocontroller und Digitale Elektronik A/D-Wandler ATMega8 funktioniert nicht


von Joachim Krohn (Gast)


Lesenswert?

Habe mir aus diversen Quellen ein Test-Programm für einen A/D-Wandler 
zusammengestrickt. Eingang C0, Spannung von Poti, der zwischen +5V und 
Masse hängt und damit als Spannungsteiler fungiert. Das Ergebnis ist 
leider permanent 0. Wer kann mir helfen?

#define   F_CPU 3686400        // Taktferquenz des myAVR-Boards
#include  <avr\io.h>           // AVR Register und 
Konstantendefinitionen

int wartekurz()                // da delay-Funktion nicht funktioniert
{
  for (long j = 0; j < 10000; j++)
    int k=k+1;
}

int main()
{
  int i,sample,value;          // Variablen Definition

  DDRC   = 0b00111110;         // 0 Eingang, 1-5 Ausgang, 6+7 reserviert
  PORTC  = 0x00;               // Ausgänge auf 0

  ADMUX |=  (1<<REFS0);        // AVCC als Referenz
  ADMUX &= ~(1<<REFS1);        // AVCC als Referenz
  ADMUX |=  (1<<MUX0);         // C0 als Eingang wählen
  ADCSRA|=  (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0); //AD-Wandler an, 
Frequenzvorteiler auf 32

  // Endlosschleife zur kontinuierlichen Auswertung der Eingangsspannung 
(am ADC)

  while(1)
  {
    ADCSRA |=(1<<ADSC);       // Einschwing-Wandlung
    while(ADCSRA&(1<<ADSC))   // warten bis Konvertierung abgeschlosen
    sample=ADCW;              // Auslesen ADCW

                              // Nun geht es los
    sample=0;
    value=0;

    for(i=0;i<10;i++)         // Schleife zum Sammeln von 10 Meßwerten
    {
      ADCSRA |=(1<<ADSC);     // eine Wandlung
      while(ADCSRA&(1<<ADSC)) // warten bis Konvertierung abgeschlosen
        sample+=ADCW;         // aufsummierung der Sample-Werte
    }
    value=sample/10;          // Aritmethisches Mittel der Sample-Werte

                              // Auswertung der Meßdaten

    if (value==0)             // falls 0 ->
      PORTC=0b00001000;       // schalte rote LED (C3) ein
    if (value>0 && value<1024)// falls zwischen 0 und 1024 ->
      PORTC=0b00010000;       // schalte gelbe LED (C4) ein
    if (value>=1024)          // falls 1024 ->
      PORTC=0b00100000;       // schaltet grüne LED (C5) ein

    wartekurz();
    PORTC=0x00;               // schaltet LED aus
    wartekurz();
  }
}

von doc (Gast)


Lesenswert?


von Joachim Krohn (Gast)


Lesenswert?

Danke, das war eine meiner Quellen... funktioniert dennoch nicht.

von doc (Gast)


Lesenswert?

Bei dir scheint so einiges nicht zu funktioneren..

>// da delay-Funktion nicht funktioniert

Nö, die funktioniert garantiert.
Im  Gegensatz zu Deiner, die vermutlich komplett wegoptimiert wird.

Ebenso funktioniert die Routine im Tutorial.

Ist "Sample" uint16_t ?

von doc (Gast)


Lesenswert?

...das die grüne LED angeht, erwartest du aber nicht wirklich, oder ?

while(ADCSRA&(1<<ADSC))<- wo ist das semikolon ?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Danke, das war eine meiner Quellen... funktioniert dennoch nicht.

Benutz' doch zuerst den geprüften Quellcode. Dann kämpfst du "nur noch" 
mit der Hardware. Wenn du Software und Hardware selbst machst, hast du 
einen Zweifrontenkrieg.

Ansonsten:

  int i,sample,value;          // Variablen Definition
        ^^^^^^

ADC gibt kein int (vorzeichenbehaftet) zurück sondern unsigned Werte 
(nicht vorzeichenbehaftet). Beim Aufsummieren von 10 Werten hast du noch 
keinen Überlauf. Bei mehr als 32 Werte aufpassen. Dito Typ von value.

    while(ADCSRA&(1<<ADSC))   // warten bis Konvertierung abgeschlosen
                           ^
Da fehlt was.

      while(ADCSRA&(1<<ADSC)) // warten bis Konvertierung abgeschlosen
                             ^
Da auch.

int wartekurz()                // da delay-Funktion nicht funktioniert
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Diesem Kommentar solltest du nachgehen. Checke die Version deines 
Compilers und der dazugehörigen avr-libc. Möglicherweise benutzt du die 
Funktion "delay" auch falsch. Gehen müsste
1
void wartekurz(void)
2
{
3
  // 10*100ms = 1s Pause
4
  unsigned char i = 10;
5
  for (i=0; i<10; i++)
6
    delay_ms(100);
7
}

wenn mit Optimierung übersetzt wird (-Os z.B.).

Den folgenden Teil habe ich nicht überprüft. Ich vertraue darauf, dass 
du das korrekt aus dem AVR-GCC-Tutorial übernommen hast.
1
  ADMUX |=  (1<<REFS0);        // AVCC als Referenz
2
  ADMUX &= ~(1<<REFS1);        // AVCC als Referenz
3
  ADMUX |=  (1<<MUX0);         // C0 als Eingang wählen
4
  ADCSRA|=  (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0); //AD-Wandler an,
5
Frequenzvorteiler auf 32

von Joachim Krohn (Gast)


Lesenswert?

Hätte vielleicht dazusagen sollen, daß ich gerade erst angefangen habe 
...

-Hatte das Semikolon übersehen.
-Da ich nur 10 Werte zur Mittelwertbildung einsetze, müßte int reichen.
-Die Verzögerungsfunktion ist nicht kritisch, sondern die A/D-Wandlung.
-Das Musterprogramm verwendet die internen 2,56 Volt als Referenz, ich
 möchte 0-5V messen (kann es hier zu Beschädigungen kommen?)

Semikolon eingefügt => mein Programm funktioniert leider dennoch nicht
(das Musterprogramm allerdings auch nicht)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Joachim Krohn schrieb:

> Hätte vielleicht dazusagen sollen, daß ich gerade erst angefangen habe
> ...
>
> -Hatte das Semikolon übersehen.

Die Stelle ist zweimal vorhanden; du musst 2x ein ; einfügen.

> -Da ich nur 10 Werte zur Mittelwertbildung einsetze, müßte int reichen.

Stimmt habe ich auch überprüft.

> -Die Verzögerungsfunktion ist nicht kritisch, sondern die A/D-Wandlung.

Wenn deine Funktion verzögert, Wenn sie das nicht macht, siehst du u.U. 
kein Ergebnis an den LEDs, weil die passende nur ein paar Microsekunden 
aufblitzt.

> -Das Musterprogramm verwendet die internen 2,56 Volt als Referenz, ich
>  möchte 0-5V messen (kann es hier zu Beschädigungen kommen?)

Nein, allerdings bekommst du bei zu messenden Spannungen >= 2,56V den 
oberen Grenzwert des ADC (0x3FF).

> Semikolon eingefügt => mein Programm funktioniert leider dennoch nicht
> (das Musterprogramm allerdings auch nicht)

Vielleicht hängt es doch an der Schaltung.

von Gast (Gast)


Lesenswert?

Hallo,

> sample=ADCW;              // Auslesen ADCW

> sample=0;

Was soll das?? Wieso weist Du der Variablen "sample" erst den Wert vom 
ADC zu und setzt sie eine Zeile später auf Null? Kein Wunder, dass da 
nur Null heraus kommt ... :-(

Gruss

von MeinerEiner (Gast)


Lesenswert?

> Was soll das?? Wieso weist Du der Variablen "sample" erst den Wert vom
> ADC zu und setzt sie eine Zeile später auf Null? Kein Wunder, dass da
> nur Null heraus kommt ... :-(

Ist doch egal. Nochmal ne Zeile drunter gehts mit der Messung von 10 
Werten und Mittelwertbildung weiter.

von Joachim Krohn (Gast)


Lesenswert?

Oh Wunder, oh Wunder, mit der Schaltung aus dem Musterprogramm habe ich 
doch hinbekommen. Morgen versuche ich rauszubekommen, warum es in meinem 
Programm nicht geklappt hat. Danke für den Support.

von Joachim Krohn (Gast)


Lesenswert?

Habe nun rausbekommen, woran es hing:
Ich habe zur Wahl des Eingangs verwendet:

       ADMUX |=  (1<<MUX0); -> funktioniert nicht

Musterprogramm:

  ADMUX = 0; -> funktioniert

Warum das so ist, weiß ich nicht.

von STK500-Besitzer (Gast)


Lesenswert?

> ADMUX |=

Ist ein riesen Unterschied zu

> ADMUX =

von Justus S. (jussa)


Lesenswert?

Joachim Krohn schrieb:

> Warum das so ist, weiß ich nicht.

Weil du das Datenblatt nicht gelesen hast...du hast auf ADC1 gestellt...

von Joachim Krohn (Gast)


Lesenswert?

Auch auf die Gefahr hin, mich gänzlich zu blamieren:

Um C0 als zu A/D-wandelnden Eingang zu setzen, muß doch im Register 
ADMUX das Bit0 (MUX0) auf 1 gesetzt werden. Warum funktioniert das nicht 
über ADMUX |=  (1<<MUX0)? Und der Befehl ADMUX = 0 setzt doch alle Bits 
auf 0, incl. REFS0 und REFS1.

Danke für Eure Geduld!

von spess53 (Gast)


Lesenswert?

Hi

>Um C0 als zu A/D-wandelnden Eingang zu setzen, muß doch im Register
>ADMUX das Bit0 (MUX0) auf 1 gesetzt werden.

Nein. Datenblatt:

MUX3..0    Single Ended Input
0000            ADC0

MfG Spess

von Tanja (Gast)


Lesenswert?

Hallo Joachim Krohn!

Ich weiß der Thread ist schon sehr alt, aber ich hab mich mit dem selben 
Thema beschäftigt und erstmal ein Lob von mir, dein Programm ist super, 
habs bei mir ausprobiert und meinen Bedürfnissen angepasst.

Ich hab gesehn, dass du Probleme mit der delay-Funktion hattest und du 
dir daher eine "Warteschleife" geschrieben hast. Ich hatte bis eben auch 
das selbe Problem mit dem Delay, aber die Lösung ist einfach, wenn man 
sie denn endlich gefunden hat.

Das ist jetzt sozusagen für dich und für die zukünftigen User die 
Probleme mit dem Delay haben.

Bei mir lag es daran, dass ich mit dem myAVR Workpad Plus (Demo) arbeite 
und der mir immer diese Fehlermeldung ausgabe:

warning: #warning "Compiler optimizations disabled; functions from won't 
work as designed"

Da es bei Workpad keine Einstellung dafür gibt, muss man eine kleine 
Zeile ganz oben im Code schreiben:

//CompilerOption:  -Os

Somit bekommt man beim copelieren diese Meldung:

Hinweis: Es werden die im Quelltext angegebenen Compiler-Optionen 
verwendet: -Os

Somit kann man dann auch #include <util/delay.h> einbinde und 
_delay_ms() funktioniert! =)

Hoffe das war jetzt hilfreich....

Liebe Grüße
Tanja

von Grml (Gast)


Lesenswert?

Tanja schrieb:
> Hallo Joachim Krohn!
>
> Ich weiß der Thread ist schon sehr alt

Leichenfledderei nennt man das auch.

> aber ich hab mich mit dem selben
> Thema beschäftigt und erstmal ein Lob von mir, dein Programm ist super,

LOL, ich hoffe das ist ironisch gemeint. Dieser Murks.

> Bei mir lag es daran, dass ich mit dem myAVR Workpad Plus (Demo) arbeite
> und der mir immer diese Fehlermeldung ausgabe:
>
> warning: #warning "Compiler optimizations disabled; functions from won't
> work as designed"

Und diese Fehlermeldung war dir über so lange Zeit nicht eindeutig 
genug? Was muss der Compiler denn noch machen, vor dir Tanzen?

> Da es bei Workpad keine Einstellung dafür gibt, muss man eine kleine
> Zeile ganz oben im Code schreiben:
>
> //CompilerOption:  -Os
Was ein Pfusch Programm. Nehmt doch mal was gescheites.

Alter Schwede, ich frage mich ja, ob der Sinn der Optimierung überhaupt 
verstanden wurde. Man setzt diese ja nicht wegen der delay Funktionen 
auf Os, sondern weil jede andere Einstellung für einen kleinen 
Controller eigentlich keinen Sinn macht, ausser man weiß wirklich was 
man tut. D.h. ja du hast die ganze über mit O0 optimiert.

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.