ADC beim Atmega8

Gast #75862
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
}
Gast
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...)
Gast
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
Gast
@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);
  }
}
Gast
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.
Gast
@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
    }
  }
}
Gast
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.
Gast
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

Eine eigene Frage? Dieser Thread ist über 22 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.