mikrocontroller.net

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


Autor: Joachim Krohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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();
  }
}

Autor: doc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Joachim Krohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, das war eine meiner Quellen... funktioniert dennoch nicht.

Autor: doc (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: doc (Gast)
Datum:

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

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

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
void wartekurz(void)
{
  // 10*100ms = 1s Pause
  unsigned char i = 10;
  for (i=0; i<10; i++)
    delay_ms(100);
}

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.
  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

Autor: Joachim Krohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: MeinerEiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Krohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim Krohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ADMUX |=

Ist ein riesen Unterschied zu

> ADMUX =

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joachim Krohn schrieb:

> Warum das so ist, weiß ich nicht.

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

Autor: Joachim Krohn (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Tanja (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Grml (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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.