Forum: Compiler & IDEs Sleep-Mode aktivieren beim ADC auslesen


von Ilja (Gast)


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

von Mario Schrenk (Gast)


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.

von Ilja (Gast)


Lesenswert?

Haste mal nen Beispiel-Code fuer mich?

Ciao
         Ilja

von Mario Schrenk (Gast)


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);
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Mario Schrenk (Gast)


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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

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
Noch kein Account? Hier anmelden.