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 }
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...)
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...
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
@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); } }
Habe mal noch outp (0x00, DDRC); outp (0x00, PINC); eingefügt, das Ergebnis bleibt aber immer noch 0. Alex
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.
@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 } } }
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.
Danke nochmal für die zusätzliche Hilfe, ich teste es morgen mal aus. Eventuelle Erfolgserlebnisse poste ich natürlich sofort ins Forum.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.