mikrocontroller.net

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


Autor: Ilja (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Mario Schrenk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ilja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Haste mal nen Beispiel-Code fuer mich?

Ciao
         Ilja

Autor: Mario Schrenk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);
}

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Mario Schrenk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.