Forum: Projekte & Code AVR ATMega8 einfacher ADC Test (ANSI C)


von Jan (Gast)


Lesenswert?

Hallo zusammen,

ich benutze einen ATMega8(L) und wollte mal ein einfaches Programm zum 
testen des ADCs schreiben. Ich habe ein Poti (0..5V) an den PC0 Eingang 
geklemmt und will das er mir auf PORTB (habe dort drei LEDs 
angeschlossen) den ungefähren Spannungsbereich ausgibt (grob in drei 
Bereiche unterteilt).
Ich benutze den Single Conversion Betrieb und kein Prescale. Das Problem 
ist das er immer in dem kleinsten Bereicht der Auswertung bleibt, da der 
ADC scheinbar keine Werte liefert.
Ich weiss das es zu diesem Thema bereits einige Artikel gibt, mit denen 
ich mich auch auseinander gesetzt habe, aber zu keinem Ergebnis geführt 
hat.
Deswegen poste ich nun einfach mal meinen Programmcode in der Hoffnung 
das ihr etwas seht was mir entgegangen ist. Da der Code nicht sehr lang 
ist folgt er einfach anbei. Habe versucht ihn ein wenig zu kommentieren.

 ----

#include <mega8.h>;

void main()
{
  int sample,i,value;
  DDRB=0xFF;   // PORTB als Ausgabeport
  ADMUX=0x00;  // ADC Ref auf Avcc, PC0 gewählt, normale Formatierung
  ADCSRA=0x80; // ADC eingeschaltet, kein Prescale
  while(1)
  {
    sample=0;
    for(i=0;i<256;i++)
    {
      ADCSRA.6=1;  //single conversion mode ein
      while(ADCSRA.6==1);  //warten bis konvertierung abgeschlosen
      sample+=ADCW;  //aufsummierung der samplewerte
    }
    value=sample/256;  //aritmethisches mittel der samplewerte
    if (value<300)
      PORTB=0x01;  //schaltet rote LED ein
    else if (value>=300 && value<600)
      PORTB=0x02;  //schaltet gelbe LED ein
    else
      PORTB=0x04;  //schaltet grüne LED ein
  }
}

von Christoph B. (christophbudelmann) Benutzerseite


Lesenswert?

Ohne jetzt die Initialisierungsroutinen für den AD-Wandler genau 
angeschaut zu haben:

Deine Variable "sample" ist zu klein. Als Integer-Wert kann die Werte 
bis 65536 speichern, teilst du das durch 256, kommen 256 raus. Kein 
Wunder, dass immer deine rote LED blinkt. Willst du bei Integer bleiben, 
solltest du höchstens 64 Wandlungen speichern.

von Jan (Gast)


Lesenswert?

Hab jetzt nur 32 Samplewerte genommen und es funktioniert wunderbar. 
Manchmal scheitert es echt an so kleinigkeiten. Vielen Dank für die 
schnelle Hilfe.

von Jan (Gast)


Angehängte Dateien:

Lesenswert?

So als Anhang mal das fertige Programm (inkl. Blinkender LED beim 
überschreiten des 2ten Grenzwertes). Werde die blinkende LED die Tage 
noch einmal mit einem Timer realisieren.

Jan

von ich (Gast)


Lesenswert?

Jan
Mit welcher Taktfrequenz betreibst du das Programm?

Bei einem Delay von 250ms.

<800KHz?

von jan (Gast)


Lesenswert?

Mit 8Mhz. Ich weiss das das mit der delay Funktion nocht nicht sehr 
ausgereift ist, werde aber schaun das ich das blinken per Timer 
realisiert bekomme.
Wenn ich die Taktrate im Compiler richtig einstelle (CVAvr C), dann 
sorgt die delay.h dafür dads die 250ms auch wirklich 250ms sind (wenn 
ich das richtig verstanden habe).
Der ADC sollte mit 4Mhz arbeiten (default prescalefactor ist 2).
Hab das Board leider im Labor der FH und kann erst am Dienstag 
weiterarbeiten (Klausurvorbereitung+arbeiten), dann gibts evtl ne 
bessere Version, eine Umsetzung aufs LC-Display ist auch geplant vllt. 
auch in Balkenform, mal schauen.

Jan

von Fly (Gast)


Lesenswert?

Der ADC wir niemals mit 4 MHz arbeiten. Ich sag mal 20ksps sind schon 
viel, die Auflösung nimmt ab. Details siehe Datenblatt.

von ich (Gast)


Lesenswert?

Bei 8MHz hast du ein max. delay von 32,7675ms da blinkt nichts sichtbar.
Delay also 8mal hintereinander aufrufen. Uff.

von ich (Gast)


Lesenswert?

Max. delay(ms) = 262.14/Taktfrequenz

von jan (Gast)


Lesenswert?

Also ich kann nur sagen das die LED definitiv blinkt. Ja hmm das mit der 
Samplerate war wohl etwas hochgegriffen. Grad mal nachgeschaut 15 kSPS @ 
max. Auflösung.
Und wie gesagt die LED blinkt schon ca. mit 2Hz.

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich bin "blutiger" Anfänger und beschäftige mich seit ein paar Wochen 
mit dem Thema Microcontroller. Einige simple Programme wie "Taster ein - 
LED ein" oder "blinkende LEDs" waren nach etwas Einarbeitung kein 
Problem mehr.

Jetzt wollte ich mich das Thema ADC angehen, habe mich durch den 
entsprechenden Abschnitt im C-Tutorial gearbeitet und bin auf dieses 
simple Beispiel gestoßen, welches ich zu Anfang gerne realisieren würde.

Damit stoße ich allerdings auf Probleme. Ich hoffe jemand hier kann 
eventuell mit einem kleinen Tipp weiterhelfen.

Ich musste den Code etwas anpassen, da mein genutzter Compiler Error an 
bestimmten Positionen meldete. Den Code, den ich jetzt nutze, hänge ich 
zum Anschluss hier an.

Ich bin mir über die elektrische Beschaltung inzwischen etwas unsicher 
geworden. An PC0 (Pin 23) habe ich den Mittelabgriff eines Potis gelegt. 
Die beiden äußeren Abgriffe liegen jeweils auf GND bzw. auf +5V, so dass 
ich am Eingang PC0 stufenlos Spannungen zwischen 0 und 5 V einstellen 
kann. Am Port D habe ich die entsprechenden Pins mit LEDs versehen, die 
gegen gemeinsame 5V geschaltet sind. Ist das so korrekt?

Wenn ich nun mein Programm auf den Atmega8 übertrage, habe ich leider 
keinen Erfolg und eine Verstellung des Eingangspegels hat keinerlei 
Auswirkung auf die LEDs.

Was mache ich falsch? Vielen Dan im Voraus!

Peter

von Robert K. (molch) Benutzerseite


Lesenswert?

Hi,

setz in deinem ADCSR Register mal einen Prescaler von 64 für den ADC. 
Wenn dein ATmega wirklich auf 8 MHz läuft dann würde dein ADC bei deinem 
Code ebenfalls mit 8MHz getaktet. Im Datenblatt wird empfohlen die 
Frequenz des ADC für 10Bit Auflösung maximal 125kHz zu wählen. Muss 
nicht die Fehlerursache sein, aber so bist du auf der sicheren Seite was 
die Arbeitsweise des ADC angeht.
1
ADCSR=(1<<ADEN); // ADC eingeschaltet, kein Prescale

Deine Beschaltung mit dem Poti hört sich korrekt an. Bei Verwendung der 
interenen Referenzspannung sollte zumindest noch ein 100nF Kondensator 
zwischen VREF und GND.

Wenn die LEDs keine Reaktion zeigen, bist du dir sicher das du sie an 
den richtigen Pins des ATmega angeschlossen hast? Nen Schaltplan für uns 
wäre auch von Vorteil.

Deine erste LED an PD7 wird auch nicht mehr ausgehen, die bleibt immer 
an.

Melde dich ob es was gebracht hat.

MfG Robert

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Robert,

vielen Dank für die schnelle Reaktion. Ich habe die Zeile nach Deiner 
Empfehlung angepasst. Den Code habe ich wieder in den Anhang angehängt.

Der Kondensator zwischen VREF und GND ist vorhanden.

LEDs habe ich an den Pins 6,11,12,13,14

Ich verwende ein Board von Olimex, welches sonst nicht verändert ist. 
Dort habe ich nur die LEDs und das Poti entsprechend angeschaltet.
Schlatplan: http://www.olimex.com/dev/images/avr-p28-sch.gif

Das Symptom ist leider unverändert.

Danke und Gruß

Peter

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Entschuldigung, ich muss berichtigen. LEDs habe ich reduziert auf Pins 
11,12,13 des Atmega8. Den Code habe ich angepasst. Siehe Anhang.

von Robert K. (molch) Benutzerseite


Lesenswert?

Hi,
hab wohl beim ersten mal was übersehen, sorry.

Diese Zeile
1
ADCSRA=0b01000000;  //single conversion mode ein
überschreibt alles was du in dieser Zeile bewirken willst.
1
ADCSR=(1<<ADEN)|(0<<ADPS0)|(1<<ADPS1)|(1<<ADPS2); // ADC eingeschaltet, 64 Bit Prescale

Mach aus dem Registerzugriff in der for-Schleife statt dem = ein |= 
sonst setzt du das ADEN und den Vorteiler zurück.

Desweiteren setzt du zweimal PD7 in deiner if-Verzweigung (wolltest 
sicherlich einmal PD6 schreiben) und die LEDs werden damit auch nicht 
mehr ausgehen. PORTD |= (0<<PD5); schaltet die LED nicht aus. Da muss 
eine UND-Verknüpfung ran in der Art PORTD &= ~(1<<PD5). Mehr dazu:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Zugriff_auf_IO-Ports

Und für den Fall das an PD2 wie in deinem Schaltplan der Taster hängt 
solltest du nich den kompletten Port D als Ausgang definieren.
DDRD=0xFF;   // PORTD als Ausgabeport => ungünstig
Da kanns zum Kurzschluss kommen wenn du mal PD2 auf High setzt und den 
Taster drückst.

Grüße

von Peter (Gast)


Lesenswert?

Ich habe die Zeile dahingehend geändert:
1
ADCSRA|=0b01000000;  //single conversion mode ein

Der Atmega8 steht nach dem Übertragen immer noch im immerselben Zustand:

PD5=high
PD6=high
PD7=low

Verzweifelte Grüße

von Peter (Gast)


Lesenswert?

Wäre das denkbar für das korrekte Ansprechen der Ausgänge?
1
if (value<300)
2
      PORTD &= ~( (0<<PD5)|(0<<PD6)|(1<<PD7) );
3
    else if (value>=300 && value<600)
4
      PORTD &= ~( (0<<PD5)|(1<<PD6)|(1<<PD7) );
5
    else
6
      PORTD &= ~( (1<<PD5)|(1<<PD6)|(1<<PD7) );

von Robert K. (molch) Benutzerseite


Lesenswert?

Nein, das geht so nicht mit den Ausgängen, dann schaltest du gar nix an. 
Kannst du ja auch im AVRStudio simulieren (sofern vorhanden).

Am einfachsten merken:
PORTD |= (1<<PD7) setzt den Pin auf HIGH
PORTD &= ~(1<<PD7) setzt den Pin auf LOW

Ein (0<<PD7) bringt nicht wirklich was.

So sollte es mit Ein und Aus aussehen:
1
if (value<300)
2
  PORTD |= (1<<PD7);   // PD7 HIGH
3
  PORTD &= ~( (1<<PD6) | (1<<PD5) );   // PD5 und PD6 LOW
4
else if (value>=300 && value<600)
5
  PORTD |= (1<<PD7) | (1<<PD6);   // PD7 und PD6 HIGH
6
  PORTD &= ~(1<<PD5);   // PD5 LOW
7
else
8
  PORTD |= (1<<PD7) | (1<<PD6) | (1<<PD5);   // PD7..PD5 HIGH

Leider finde ich keine weiteren Fehler warum es nicht funktioniert.

von P. S. (Gast)


Lesenswert?

Hast du erstmal versucht, einfach nur die LEDs blinken zu lassen? Ein 
Bild von deinem Testaufbau waere auch nicht schlecht.

Ich verstehe nicht, warum sich Anfaenger immer auf Boards ohne Display 
stuerzen um dann im Blindflug rumzueiern... mit 'nem LCD koennte man 
einfach mal den rohen ADC-Wert ausgeben.

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.