www.mikrocontroller.net

Forum: Compiler & IDEs ADC beim Atmega8


Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum steht in der Variable 'i' immer eine Null. Ich habe testweise
2,5V an den Eingang gelegt.
AREF liegt auf 5V.

#include<avr/io.h>

int main (void) {

  char i = 0;

  outp ((1<<MUX0), ADMUX);
  //Aktivierung des Pins PC1 (ADC1), an ihm soll die zu messende
Spannung liegen

  outp ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1), ADCSRA);
  //Aktivierung des ADC, festlegen eines Prescalers von 64 -->
4Mhz/64=62,5kHz

  outp ((1<<ADSC), ADCSRA);
  //Starten einer einzelnen Konvertierung

  for (i=0; i<100; i++) {
    i++;
  }
  //warte ein bischen

  x = ADCL + ADCH*256;
  //ADCH muss binär um 4 Stellen nach links geschoben werden
  //es muss immer zuerst ADCL ausgelesen werden
}

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Statt char i steht natürlich unsigned int x in meinem Programm.

Alex

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstens wird die Warteschleife wahrscheinlich wegoptimiert, zweitens
ist 100 ohnehin eine gewagte Annahme.  Du solltest stattdessen auf das
entsprechende Bit im Statusregister pollen.

Übrigens:

x = ADC;

geht auch. ;-)

(Der Kommentar zu ADCH ist ohnehin flasch, wenn schon, muß es um 8 bit
geschoben werden, aber eigentlich nicht wirklich geschoben...)

Autor: Datenblatt-Hinweiser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie hoch/niedrig wird denn der ADC getaktet?

Hier stehts genau drinnen:
http://www.mikrocontroller.net/datasheet.php?atmega8

Auf dieser Seite befindet sich bereits ein Code der für 4MHz läuft,
auch nicht angeschaut...

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besten Dank für die Tips, eigentlich habe ich das Programm fast nur mit
Hilfe des Datenblatts zum Atmega8 erstellt, das C-Programm muss ich
wohl übersehen haben ;-)

Alex

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Datenblatt-Hinweiser
Also in meinem datasheet ist kein C-Code Beispiel, zumindest sehe ich
keins in der ADC-Sektion.
Mein Code liefert allerdings trotz geringer Modifikationen immer noch
nicht das richtige Ergebnis ;-(

#include<avr/io.h>
#include<lcd.h>
#include<stdlib.h>

int main (void) {

  int x = 0;
  char buffer [5];
  lcd_init(LCD_DISP_ON);

  outp ((1<<MUX0), ADMUX);
  //Aktivierung des Pins PC1 (ADC1), an ihm soll die zu messende
Spannung liegen

  outp ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADFR), ADCSRA);
  //Aktivierung des ADC, festlegen eines Prescalers von 64 -->
4Mhz/64=62,5kHz
  //Starten einer einzelnen Konvertierung

  for (;;) {

    outp ((1<<ADSC), ADCSRA);

    while (ADCSRA & (1<<ADSC)) {}
    //warte, bis ADSC gelöscht wird --> Ende der Konvertierung

    x = ADC;
    //ADCH muss binär um 4 Stellen nach links geschoben werden
    //es muss immer zuerst ADCL ausgelesen werden

    //lcd_clrscr ();
    itoa(x, buffer, 10);
    lcd_puts(buffer);
    delay (10000);
  }
}

Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe mal noch
outp (0x00, DDRC);
outp (0x00, PINC);
eingefügt, das Ergebnis bleibt aber immer noch 0.

Alex

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nu ja, im Gegensatz zum ehrenwerten Datenblatthinweiser kannst Du Dir
ja zumindest einen Vornamen leisten...

Klar, was sollen Deine zusätzlichen Ausgaben auch bringen?  DDRC ist
auf 0 vorbelegt nach Reset (alles Eingang), und das PIN-Register zu
beschreiben, ist alles andere als sinnvoll...

Btw., inp() hast Du ja schon weggeworfen, vergiß auch outp() (oder
outb()), schreib einfach:

ADCSRA = ...;

Wenn Du bei AVR-GCC bleiben willst, kannst Du außerdem _BV() zur
Vereinfachung nehmen:

ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADFR);

Hmm, Du hast Dich für den free-running mode entschieden.  Anyway:

* Bit 6

   ADSC: ADC Start Conversion In Single Conversion mode, write this
   bit to one to start each conversion. In Free Running mode, write
   this bit to one to start the first conversion.

Den Kommentar dafür hast Du noch drin, aber das zugehörige

ADCSRA |= _BV(ADSC);

fehlt.  Erst danach kannst Du auf das Ergebnis warten.  Aber
eigentlich brauchst Du ja wohl den free-running mode gar nicht,
sondern kannst auch gleich jede Konvertierung einzeln starten.
Free-running ist sinnvoller zusammen mit einer Interruptroutine, die
dann eine globale Variable setzt.

Autor: Alexander Starke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Joerg
Vielen Dank für die konstruktiven Tipps, allerdings geht das Proggi
noch immer nicht. Was bewirkt eigentlich:
ADCSRA |= _BV(ADSC);
Wird dadurch das Bit in ADSC gelöscht?
Habe jetzt auch mal den Analog-Pin gewechselt, man weiss ja nie ;-)
Es liegen nachweislich 2,6V an, aber die Ausgabe bleibt bei 0.
Langsam bekomme ich Selbstzweifel, soviel kann man dabei doch
eigentlich garnicht verkehrt machen...

#include<avr/io.h>

int main (void) {

  int x = 0;
  ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADSC);
  //Aktivierung des ADC,  Prescalers von 32 --> 4Mhz/32=125kHz
  //Starten einer einzelnen Konvertierung
  //Start einer Wandlung

  for (;;) {
    ADMUX = _BV(MUX0) | _BV(MUX2);
    //Aktivierung des Pins PC5 (ADC5)
    ADCSRA = _BV(ADSC);
    //Start einer Konvertierung
    while (ADCSRA & (1<<ADSC)) {}
    //warte, bis ADSC gelöscht wird
    x = ADC;
    if (x==0) {
      DDRB = 0xFF;
      PORTB = 0x00;  //--> Dioden am Port leuchten
    }
  }
}

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, mit Nachnamen. :-)  Danke!  (Sorry, ich finde das einfach
persönlicher so...)

> Was bewirkt eigentlich:
> ADCSRA |= _BV(ADSC);

Nun, klassisches C, bitweise Operatoren.  Ausgeschrieben wäre es

ADCSRA = ADCSRA | (1 << ADSC);

> Wird dadurch das Bit in ADSC gelöscht?

Nein, gesetzt.  Genau das sagt ja das Datenblatt auch: Bit setzen, um
die Konvertierung zu starten.

> soviel kann man dabei doch eigentlich garnicht verkehrt machen...

Na doch, man kann's immer noch verkehrt hinschreiben. ;-)

    ADCSRA = _BV(ADSC);

    //Start einer Konvertierung


Sollte wohl |= heißen.

Außerdem:

  ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADSC);


Dort setzt Du bereits ADSC.  Das ist so nicht sinnvoll, da Du den
ADMUX ja erst danach umschaltest, d. h. Du schiebst erst eine
Konvertierung an und schaltest danach den MUX um... effektiv wird die
Umschaltung dann verzögert bis zur nächsten Konvertierung.

Ich bin mir gerade auch nicht ganz sicher, ob man zwischen der Auswahl
des MUX und dem Start der Konvertierung eventuell ,,einen Moment''
Zeit vergehen lassen muß, z. B. einen NOP:

asm volatile("nop");

Bei normaler Pin-IO ist es jedenfalls so, daß die Ausgabe erst mit
leichter Verzögerung wirksam wird.

Autor: Alexander Starke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke nochmal für die zusätzliche Hilfe, ich teste es morgen mal aus.
Eventuelle Erfolgserlebnisse poste ich natürlich sofort ins Forum.

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.