Sleep-Mode aktivieren beim ADC auslesen

Gast #285463
Lesenswert?
• ▲
▼
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
Gast #285464
Lesenswert?
• ▲
▼
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.
Gast #285466
Lesenswert?
• ▲
▼
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);
}
Gast #285468
Lesenswert?
• ▲
▼
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?
Moderator Persönliche Seite #285469
Lesenswert?
• ▲
▼
> 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.

Antwort schreiben

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.

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.