Forum: Mikrocontroller und Digitale Elektronik Atmega 88 ADC im free running mode. timimings?


von Matthias H. (maethes26)


Lesenswert?

Hallo zusammen,

ich beschäftige mich gerade intensiv mit dem ADC im free running mode 
und habe dazu ein paar Fragen.
Einige Sachen im Datenblatt sind mir unklar.

Meine Funktion sieht wie folgt aus:


uint16_t ADC_Read_free_running_mode( uint8_t channel )
{
  static uint8_t channel_vorheriger, result;

  if (channel_vorheriger!=channel)
//wenn ein neuer Kanal gewählt wurde, dann Kanal einstellen und 
Testmessung
  {                  //Wandlung mit der Änderung des Kanals 
synchronisieren

loop_until_bit_is_set(ADCSRA, ADIF);

//channel change during a conversion will not go in effect

ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
// Kanal waehlen, ohne andere Bits zu beeinflußen

  _delay_us(250);                // 250us Warten, damit die Elektronik 
sich darauf einstellen kann,  verlangsamt das Programm unnötig!!!!!! 
kann man  das ändern?
  result=ADCW;                  //eine Messung machen die verworfen wird
  }

  channel_vorheriger=channel;
  return ADCW;                    // ADC auslesen und zurückgeben


Mit loop_until_bit_is_set(ADCSRA, ADIF) will ich die Kanaleinstellung 
synchronisieren und warten bis die Wandlung abgeschlossen ist, damit 
auch tatsächlich der Kanal eingestellt ist, den ich erwarte.

Laut Datenblatt wird ADIF gelöscht  (auf Null oder 1 gesetzt??? auf 1 
oder?), wenn der dazugehörige interruptvector ausgeführt wird. Im free 
running mode wird kein vector ausgeführt und somit auch kein bit 
gelöscht, oder?
Ich müßte es dann manuell nach jedem lesevorgang auf 1 setzen, um es zu 
löschen??? Im Datenblatt steht, das es gelöscht wird, indem man eine 1 
schreibt!!
Dann auch wieder im Datenblatt: After the conversion is complete  ADIF 
is high.
Muss ich ADIF also danach wieder im free running mode manuell auf Null 
setzen?
ADCSRA&= ~(1<<ADIF); //löschen



würde meine Funktion dann so aussehen müssen??

loop_until_bit_is_set(ADCSRA, ADIF);

 ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
 ADCSRA&= ~(1<<ADIF); //löschen
 _delay_us(220);
  result=ADCW;


Was sagt ihr zu diesem _delay_us(220)????? Immer nach einer 
Kanaländerung muss gewartet werden, damit sich die Elektronik darauf 
einstellt.

Hält dies mein Programm nicht unnötig auf und man könnte die Funktion im 
free running mode nicht anders, ohne delay, schreiben??

Wie würdet ihr das denn besser machen?



Wozu benötigt man das DIDR0? Digital Input Disable Register 0

man kann damit, laut Datenblatt, den input buffer des betreffenden ADC 
PIN deaktivieren.
Wenn man den digitalen Input nicht benötigt, dann kann man etwas 
einstellen, aber wozu und weshalb?
Könntet ihr mir das bitte erklären?


Es wäre nett, wenn ihr mir zu meienr Probelmatik noch ein paar Tipps 
geben könntet.

Herzlichsten Dank,

Matthias.

von Uwe (de0508)


Lesenswert?

Hallo Matthias,

du hast doch schon einen Thread zu diesen Themen offen.

Beitrag "Analogmessung mehrerer Kanäle hinterteinander, überall gl. Werte?"

im letzten Beitrag des Alten Threads hatte ich versucht das 
syncronisierte Ändern des Kanals zu beschreiben.

1. Syncronisieren, dann wie du gelesen hast ADIF löschen.
1
ADCSRA = (1<<ADIF); //löschen

Oder einfacher die ISR-ADC-Routine hinschreiben:
1
ISR(ADC_vect)    // ADC Conversion Complete
2
{
3
// evtl. weiterer code 
4
// Flag.
5
}

Dann geht das Löschen von ADIF automatisch.

Aber syncrones Ändern wird nicht mehr über ADIF signalisiert, evlt. ein 
Flag verwenden.

2. ADC stoppen ADEN=0 und Auto Trigger off ADATE=0
3. ADC-Kanal ändern,
4. ADC Starten ADEN=1 und eine Wandlung starten ADSC=1
5. auf das Ende der ersten Wandlung warten:
1
loop_until_bit_is_not_set(ADCSRA, ADSC);
5. ADC-Werte lesen und verwerfen:
1
(void)ADCW;
6. Free Running mode setzen
1
ADCSRB = (0<<ADTS2) ^ (0<<ADTS1) ^ (0<<ADTS0);
7. Starte erste Wandlung ADSC=1, ADC Auto Trigger Enable ADATE=1
1
ADCSRA |= (1<<ADSC) ^ (1<<ADATE);

Aber warum soll der ADC im Freerunning Mode laufen, wenn Du die 
Messwerte nicht verwendest ?

Vielleicht einfach nur eine ADC-Wandlung mit ISR-ADC um ein Flag zu 
setzen dass die Wandlung fertig ist. Danach in der Main das Flag 
abfragen und eine neue ADC-Wandlung starten.

Also sind das zwei unabhängige Prozesse ADC-Wandlung (ISR) und ADC-Wert 
auslesen (main-prozess). Damit ist keine delay mehr nötig !

von Matthias H. (maethes26)


Lesenswert?

Hallo Uwe,

vielen Dank, das Du mir weiter helfen willst. Ich habe Deine 
ausführliche Routine gestern auch intensiv bearbeitet und bin schon, 
Dank Deiner Hilfe, ein gutes Stück weiter gekommen.

Einige Funktionen davon kenne ich aber noch nicht, deswegen wollte ich 
nochmal nachfragen.
Hättest Du denn vielleicht auch Zeit mir das am Telefon zu erklären? 
Gern gebe ich Dir für die Zeit auch Geld (20€ für 30min, damit ich das 
Thema ADC bald mal durch habe :-) ). Ansonsten halt hier im Forum auch 
gern.


ja, ich habe schon ein Thread zum Thema offen, war wohl doch nicht so 
gut ein neues auf zumachen. Dachte das wird es noch mehr gelesen, aber 
das ist wohl Unsinn.


Ich werde mir Deine Codebeispiele die Tage weiter durcharbeiten oder 
jederzeit mit Dir am Telefon. Jetzt würde ich dann erst mal andere 
wichtige Fächer für die Schule bearbeiten.

Woher kommt die ISR (ADC_vect) Routine???
ist das ein automatischer Timeraufruf, so wie Du den Timer in Deinem 
Beispeil initialisiert hast?

IM gesamten PDF finde ich kein Stichwort zu ADC_vect
oder ist das eine von Dir selbst erstellte Funktion? Ich hatte noch 
keine Zeit mir diese Funktion genau anzuschauen.


Oder einfacher die ISR-ADC-Routine hinschreiben:

ISR(ADC_vect)    // ADC Conversion Complete
{
// evtl. weiterer code
// Flag.
}


Wozu soll der free running modus denn sonst gut sein, als ihn nicht nach 
jedem Kanalwechsel so aufwendig und zeitaufwendig neu initialisieren zu 
müssen?
Im single modus dauert die erste Messung ungefähr 25 clock cycles, 
initialisierung usw.

Diese Zeit wollte ich mir im free running modus sparen. Das geht wohl 
aber anscheinend nur, wenn ich bei einem Kanal bleibe, oder?


Herzlichsten Dank für Deine Unterstützung Uwe,

viele Grüße,

Matthias.

von Vuvuzelatus (Gast)


Lesenswert?

>Wozu benötigt man das DIDR0? Digital Input Disable Register 0

>man kann damit, laut Datenblatt, den input buffer des betreffenden ADC
>PIN deaktivieren.

Wenn der Pegel eines Analogsignals sich zufällig in der Nähe der 
digitalen Umschaltpunkte befindet, kann das ein ständiges, häufiges 
Kippen der Digitalstufe bewirken.  Um den damit verbundenen unnötigen 
Stromverbrauch zu vermeiden, kann man für ausschließlich analoge 
Eingänge den Input Buffer über das DIDR abschalten.

von Matthias H. (maethes26)


Lesenswert?

Vielen Dank für Deine Antwort.



Vuvuzelatus schrieb:
>>Wozu benötigt man das DIDR0? Digital Input Disable Register 0
>
>>man kann damit, laut Datenblatt, den input buffer des betreffenden ADC
>>PIN deaktivieren.
>
> Wenn der Pegel eines Analogsignals sich zufällig in der Nähe der
> digitalen Umschaltpunkte befindet, kann das ein ständiges, häufiges
> Kippen der Digitalstufe bewirken.  Um den damit verbundenen unnötigen
> Stromverbrauch zu vermeiden, kann man für ausschließlich analoge
> Eingänge den Input Buffer über das DIDR abschalten.

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.