Hallo - kann mir jemand erklaeren, wie ich den Sleep-Mode zum Auslesen des ADCs richtig einstelle?! - ich hab den Beispiel-Code genommen und leider haengt sich das Device hinterher auf: uint16_t ReadChannel(uint8_t mux,uint8_t count) { uint8_t i; uint32_t result = 0; set_sleep_mode (SLEEP_MODE_ADC); ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); //Frequenzvorteiler ADMUX = mux; // Kanal waehlen ADMUX |= (0<<REFS1) | (0<<REFS0); // interne Referenzspannung nutzen ADCSRA |= (1<<ADSC); // eine ADC-Wandlung sleep_mode (); while ( ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten for(i=0;i<count;i++) { ADCSRA |= (1<<ADSC); while ( ADCSRA & (1<<ADSC) ); result += ADCW; } ADCSRA &= ~(1<<ADEN); result /= count; return result; } Ahh - btw: ATMega8
Aus dem Sleep-Modus wird der Kontroller durch einen Interrupt wieder aufgeweckt. Daher entsprechende Interrupts erlauben und auch die ISR dazu programmieren. Wenn der Sleep-Modus auf ADC eingestellt ist, dann startet der Befehl sleep_mode() die Wandlung automatisch, braucht man also nicht noch extra anzustoßen. Auf das Ende der Wandlung muß man dann auch nicht warten. Falls Du aber noch andere Interrupts verwendest, Timer z.B., dann mußt Du trotzdem auf Abschluß der Konvertierung pollen, da sonst u.U. vor Ende der Wandlung das Ergebnis ausgelesen wird.
Ist nur das Wesentliche als Auszug; kann man sicherlich auch noch eleganter lösen. volatile uint8_t MyADCSRA; ... SIGNAL (SIG_ADC) { MyADCSRA |= (1<<ADIF); } void init_ADC(void) { MyADCSRA = 0; ADCSRA = (1<<ADEN); // ADC aktivieren // Frequenzvorteiler 128: 75.0KHz bei 9.6MHz ADCSRA |= (1<<ADPS2) |(1<<ADPS1) | (1<<ADPS0); ADCSRA |= (1<<ADIE); // Interrupt zulassen set_sleep_mode(1); // ADC Noise Reduction sei(); // alle Interrupts erlauben // Dummy-Readout, um den Wandler "warmlaufen" zu lassen nicht vergessen } uint16_t ReadChannel(uint8_t mux, uint8_t referenz) { uint8_t i; uint16_t result=0; // Kanal und Referenzspannung setzen ADMUX = referenz | (mux & 31); for(i=0; i<Oversample; i++){ MyADCSRA &= ~(1<<ADIF); sleep_mode(); // auf Abschluss der Konvertierung warten (ADIF-bit) falls // anderer Interrupt den Kontroller aufgeweckt hat while(!(MyADCSRA & (1<<ADIF))) ; result += ADCW; // Wandlungsergebnis } return(result / Oversample); }
Finde ich umständlich. Warum kannst du nicht einfach ein ganz gewöhnliches Flag innerhalb der ADC-ISR setzen und dort auch gleich den ADC-Wert auslesen? Dann braucht es dich nicht zu interessieren, ob ein anderer Interrupt den Controller aufgeweckt hat, du legst dich danach einfach wieder schlafen.
Wie gesagt, es läßt sich eleganter lösen. Die Vorgehensweise habe ich bei der Migration von Pollen auf Interrupt angewendet. Daher auch die Variable "MyADCSRA", in der ich als Flag das gleiche Bit wie im Register verwende. Wenn man wieder auf Pollen wechselt, dann einfach das "My" vor der Variable löschen... Das mit dem wieder schlafen legen interessiert mich jetzt auch! Dazu habe ich aber einige Fragen: Wo genau soll er sich denn wieder schlafen legen? In den anderen ISRs? Kann dann überhaupt noch ein Interrupt den Kontroller wecken? Und außerdem startet ein sleep() doch die AD-Wandlung - oder nicht, falls gerade eine Wandlung läuft. Fragen über Fragen. Hat das jemand schon mal in der Praxis ausgetestet?
> Wo genau soll er sich denn wieder schlafen legen? Typischerweise in der main-loop. > In den anderen ISRs? Keinesfalls. Erst den RETI am Ende der ISR abarbeiten lassen, sonst bleiben die Interrupts verboten. > Kann dann überhaupt noch ein Interrupt den Kontroller wecken? Alle (zumindest im SLEEP_MODE_IDLE, das ist der default). > Und außerdem startet ein sleep() doch die AD-Wandlung - oder nicht, > falls gerade eine Wandlung läuft. Genau, falls nicht gerade eine Wandlung läuft.
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.