mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ADC; Messwerte in Konstanten Zeitabständen?


Autor: Klotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich habe ein kleines Problem mit dem ADC, und zwar möchte ich n 
Messwerte in konstanten Zeitabständen aufnehmen.


Zunächst hatte ich den ADC im Free-Running Mode und dann im 
Timer-Interrupt immer den Wert aus ADCW ausgelesen und in ein Feld der 
Größe n geschrieben.


Dann habe ich gelesen das man das auch über den Interrupt des ADC machen 
kann was evtl. besser wäre (warum stand nicht dabei...) und wollte das 
mal ausprobieren, irgendwie komme ich dabei nicht richtig weiter. Es ist 
doch richtig das ich weiterhin mit dem Timer einen "Takt" erzeuge der 
dann den ADC   startet oder?

Ich verwende einen Mega168, zusammen mit AVR Studio, die Messwerte 
sollen in einem Feld abgespeichert werden.


Gibt es dazu eine genauere Erklärung oder bessere Lösungen? Im Forum 
habe ich einige Sachen in Assembler gefunden, da komme ich leider 
absolut nicht mit klar :(

main(void) 
{
  sei();
  
  ADMUX = 0;

  ADMUX |= (0<<REFS1) | (1<<REFS0);
  
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)| (1<<ADATE) | (1<<ADIE);

  ADCSRB = (1<<ADTS1) | (1<<ADTS0);

  ADCSRA |= (1<<ADSC);

  do
  {
  messwerte_aufnehmen();
  ausgabe();
  }
  
  while(1);
}


void messwerte_aufnehmen()
{
  index=0;
  TCCR1A = (1<<COM1A1) | (1<<COM1A0);
  cli();
  TCNT1H = 0xF0;
  TCNT1L = 0x05;
  sei(); 
  TIMSK1 = (1<<TOIE1);
  TCCR1B = (1<<CS10);
  while(index<=n-1);
  TCCR1B &=~ (0<<CS10);
}


SIGNAL (SIG_OVERFLOW1)    
{
  messwerte[index]  =ADCW;    // ergebnis übernehmen
  index++;
}

Autor: Thomas O. (kosmos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du schreibst einfach in die Entsprechende Interrupt-Routine den Start 
der Wandlung rein.

Beim Timerüberlauf oder beim Compare Match wird ja in die entsprechende 
Interrupt-Routine verzweigt und dort setzt du das ADSC-Bit um die 
Wandlung zu starten und verlässt die Interruptroutine wieder und holst 
nach einer gewissen Zeit deinen AD-Wert ab, kannst auch danach polen ob 
die Wandlung fertig ist oder holst ihn erst mittels dem 
"ADC-Fertig-Interrupt" ab dann kannst du zwischenzeitlich andere 
Aufgaben erledigen.

Autor: Werner B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die ATMega8535, Mega16 und Mega32 kennen einen "Trigger ADC on Compare 
Match" Modus.

z.B.
SFIOR |= _BV(ADTS0)|_BV(ADTS2);  /* ADC Trigger Source = Timer1 Compare B */
ADCSRA = _BV(ADPS2) | _BV(ADPS1) | // prescale faktor= 128 ADC läuft
         _BV(ADPS0) | // mit 14,7456MHz/ 128 = 115,2kHz 18,432MHz -> 144kHz
         _BV(ADEN)  | // ADC an
         _BV(ADSC)  | // Beginne mit der Konvertierung
         _BV(ADIE)  | // ADC-Interrupt an
         _BV(ADATE);  // Auto trigger on
Der Compare Match Interrupt muss enabled sein, aber in der ISR muss 
nichts (außer return) drinstehen.

Evtl. kann der Mega168 so etwas auch.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Werner B. wrote:
> Der Compare Match Interrupt muss enabled sein, aber in der ISR muss
> nichts (außer return) drinstehen.
Nö, der Interrupt muss dafür NICHT freigegeben sein. Nur das 
betreffende Flag muss dann von Hand gelöscht werden.

> Evtl. kann der Mega168 so etwas auch.
Kann er. Das ganze heißt ADC Auto Trigger und geht mit den meisten 
Timer-Overflow- und Timer-Compare-Ereignissen.

Einfach einen Timer auf die gewünschte Zeit einstellen, die ADTS-Bits im 
ADCSRB entsprechend setzen und den Rest macht die Hardware. Nur, wie 
gesagt, falls der Timer-Interrupt nicht freigegeben ist, dran denken, in 
der ADC-ISR das Timer-Overflow- bzw. Compare-Flag zu löschen. Sonst 
geht's nur einmal.

Autor: Klotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also der Teil meines Programmes sieht zur Zeit so aus:

  ADMUX = 0;
  ADMUX |= (0<<REFS1) | (1<<REFS0);
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)| (1<<ADATE) | (1<<ADIE);
  ADCSRB = (1<<ADTS1) | (1<<ADTS0);

void messwerte_aufnehmen()
{
  index=0;
  TCCR1A = (1<<COM1A1) | (1<<COM1A0);
  cli();
  TCNT1H = 0xF0;
  TCNT1L = 0x05;
  sei();
  TIMSK1 = (1<<TOIE1);
  TCCR1B = (1<<CS10);

  while(index<=n-1);

  TCCR1B &=~ (0<<CS10);
}


SIGNAL (SIG_OVERFLOW1)
{
  ADCSRA |= (1<<ADSC);
}

SIGNAL(SIG_ADC)
{
  array_real[index]=ADCW;
  index++;
}


Ich hatte mir das so vorgestellt das jedesmal wenn die Funktion 
aufgerufen wird das Feld mit den n Messwerten gefüllt wird.

Wäre nett wenn mal jemand mit'm Zaun winken könnte ;)

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klotz wrote:
> Ich hatte mir das so vorgestellt das jedesmal wenn die Funktion
> aufgerufen wird das Feld mit den n Messwerten gefüllt wird.
>
> Wäre nett wenn mal jemand mit'm Zaun winken könnte ;)
Winke Winke... War das oben nicht genug mit dem Zaun gewunken? Wenn das 
Programm ansonsten nix zu tun hat, kann man das sicher so ähnlich 
machen. ABER:
1.) Wie oben angedeutet, gibt es die Auto Trigger-Funktion, die Dir 
zumindest einen Interrupt Handler erspart.
2.) Achte darauf, dass die Variable "index" volatile deklariert ist. 
Sonst funktioniert es möglicherweise gar nicht.
3.) Verwende besser nicht das veraltete SIGNAL-Geschisse. Wenn Du noch 
nicht geupdated hast, dann hol es nach und verwende ISR für die 
Interrupt Handler.

EDIT:
Sehe grad, dass Du ja bereits den Auto Trigger aktiviert hast. Warum 
setzt Du dann das ADSC-Bit noch in der Timer-ISR? Das ist Unsinn. Lass 
die ISR ganz weg, deaktiviere den Interrupt und lösche lediglich in der 
ADC-ISR das Timer Overflow Flag mit
TIFR1 = 1 << TOV1;

Autor: Klotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Hilfe!

Manchmal fällt der Groschen bei mir leider Pfennigweise.

Hab die 3 Punkte nochmal geändert und es läuft jetzt schonmal....bis zum 
nächsten Problem (das dauert hoffentlich noch etwas) ;)

Gruß

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.