Lies Dir doch mal den Absatz: Changing Channel or Reference Selection im Doc zu Deinem Controller durch. Dort wird einiges geschrieben zu Vorgehens- und Vorsichtsmaßnahmen beim Multiplexen der Eingänge.
Hallo,
ich möchte mit einem at90can 8 ADC Kanäle so schnell auslesen:
Der ADC-Takt ist 125 kHz. (16.000.000 Hz / 128 Prescaler)
In dem AVRGCC-Tutorial wird geraten eine Dummy-Messung durchzuführen. Gilt das nur nachdem ich den ADEN gesetzt hab oder auch beim wechseln der Kanäle?
Der Code ist teilweise aus dem AVRGCC-Tutorial
Code:char i=0; ADMUX = 0x40; // ADC0 ADCSRA |= (1<<ADSC); /* Test AD-Wandlung durchführen */ while (ADCSRA & (1<<ADSC)) { ; // Auf Abschluss der Konvertierung warten } adc_werte[0] += ADCL; adc_werte[0] += (ADCH<<8); adc_werte[0] =0; /* Test-Wert löschen */ for(i=0; i<5; i++) // 5 Wandlungen durchführen { ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion " while (ADCSRA & (1<<ADSC)) { ; // Auf Abschluss der Konvertierung warten } adc_werte[0] += ADCL; adc_werte[0] += (ADCH<<8); } adc_werte[0] /= 5; // Summe durch fünf teilen = arithm. Mittelwert i=0; ADMUX = 0x41; // ADC1 ADCSRA |= (1<<ADSC); /* Test AD-Wandlung durchführen */ while (ADCSRA & (1<<ADSC)) { ; // Auf Abschluss der Konvertierung warten } adc_werte[1] += ADCL; adc_werte[1] += (ADCH<<8); adc_werte[1] =0; /* Test-Wert löschen */ for(i=0; i<5; i++) // 5 Wandlungen durchführen { ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion " while (ADCSRA & (1<<ADSC)) { ; // Auf Abschluss der Konvertierung warten } adc_werte[1] += ADCL; adc_werte[1] += (ADCH<<8); } adc_werte[1] /= 5; // Summe durch fünf teilen = arithm. Mittelwert i=0; // usw.
Lies Dir doch mal den Absatz: Changing Channel or Reference Selection im Doc zu Deinem Controller durch. Dort wird einiges geschrieben zu Vorgehens- und Vorsichtsmaßnahmen beim Multiplexen der Eingänge.
Ciao sagt der JoeamBerg
Hallo,
danke für den Hinweis.
Laut Datenblatt sind Dummy Messungen um den ADC "warmlaufen" zu lassen überhaupt nicht nötig - zumindest steht da nichts davon!
Die erste Wandlung dauert zwar doppelt so lang wie die alle folgenden ( so lange der ADC nicht abgeschatet wird) aber ansonsten passiert da laut Datenblatt nichts mehr ungewöhnliches.
Hi, almic,
Betrifft das nicht die erste Wandlung nach dem Umschalten des ADC-Eingangs von einem Pin auf den anderen? Das wäre dann ja beim Multiplexen doch wieder häufiger. Aber ich bin mir da nicht gaaanz sicher.... Die erste Wandlung dauert zwar doppelt so lang ...
In solchen Fällen probier ich das auch schon mal auf (m)einer Flash- und Experimentierplatine aus.
Ciao sagt der JoeamBerg
Die Längere Wandlungszeit gilt nicht nach dem Kanalwechsel. Nach dem Kanalwechsel macht eine dummymessung sinn, wenn die Quelle einen hohen Widerstand hat (mehr als etwa 20 KOhm). Der AD Wandler hat sonst noch etwas Gedächnis an den vorherigen Kanal.
Man sollte etwas Wartezeit einplanen nach dem einschalten der internen Referenz oder dem umschalten der Referenz, besonders in Richtung kleinerer Spannung. Da reicht dann aber oft auch eine Dummymessung nicht aus.
Zum Programm:
Für eine Schnelle Messung sollte man den AD duchgängig laufen lassen, also nicht jedesmal als single conversion starten. Das geht auch wenn man die Kanäle umschaltet. Wenn es sein muß könnte man wohl auch auf 250 kHz AD Takt gehen, so groß viel größer werden dadurch die Fehler noch nicht. Zur Mittelwertbildung sind 4 oder 8 Werte oft günstiger, denn da geht das Teilen schneller. Dabei macht es aber duchaus Sinn die Summe von 4 Werten nur durch 2 zu Teilen und das Ergebnis dann als Wert mit 11 Bit Auflösung zu sehen. Entsprechend Macht es Sinn von 16 Werten 12 Bit Auflösung übrig zu lassen.
Auf den ADC wert kann man auch gleich als 16 bit wert zugreifen:
adc_werte[0] = ADC;
reicht zum auslesen aus, den Rest erledigt der Compiler.
Das aufsummieren sollte man wohl auch besser in einer localen Variable machen, und nicht unbedingt im array.
Du musst den Channel >1 ADC Takt vor der Conversion wählen!!!
Bei Dir sind das immerhin 128 Prozessortakte, das geht also nicht gut.
Nebenbei brauchst Du in C nicht High und Low Byte getrennt zu kopieren, "temp = ADC;" geht auch...
Gruß
Ach herrje, schauderhaft was ich alles in Nu (merische) Ma (thematik) vergessen habe. Schlimm schlimm.Zitat von Besserwessi
Ciao sagt der JoeamBerg
Hallo,
ich bleibe mal bei der idee mit der Einzelmessung, im zweifelsfall kann ich später noch im freilaufenden Modus wechseln.
Hab jetzt noch eine Warteschleife eingefügt und die Wertzuweisung geändert.
Die Frage ist jetzt:Code:char i=0; unsigned char volatile j=0; unsigned short adc_temp=0; ADMUX = 0x40; // ADC0 for(j=0; j<15; j++) { } // 10us warten (etwas mehr als ein ADC-Takt) ADCSRA |= (1<<ADSC); /* Test AD-Wandlung durchführen */ while (ADCSRA & (1<<ADSC)) { ; // Auf Abschluss der Konvertierung warten } adc_temp += ADC; adc_temp =0; /* Test-Wert löschen */ for(i=0; i<4; i++) // 4 Wandlungen durchführen { ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion " while (ADCSRA & (1<<ADSC)) { ; // Auf Abschluss der Konvertierung warten } adc_temp += ADC; } adc_temp /= 2; // Summe durch fünf teilen = arithm. Mittelwert adc_werte[0] = adc_temp; i=0;
Ist das Programm schneller wenn ich das in eine Funktion packe und die Funktion 8 mal starte oder ist es schneller wenn es einfach (copy&paste sein dank) 8mal hintereinander steht?
Hi, almic,
Leider bin ich nicht der große C-Freak. Allerdings weiß ich, dass beim Aufruf einer Funktion eine ganze Menge "Verwaltungsarbeit" vom Compiler gemacht wird: Register retten und wieder zurückschreiben. Daher hatte ich mal in einem Programm die "copy&paste"-Variante gemacht und meine Zeitmessung ergab einen klaren Vorteil. Sieht halt unprofessionell aus, aber wenns was bringt . . . .... Programm schneller ... die Funktion 8 mal starte ...
Du kannst Dir dazu selbst ein Bild dazu machen: schau Dir mal den Code nach dem Übersetzen an. Der steht in einer Datei *.lls im Unterordner "default" Deines Projektordners. Beim Lesen der *.lls macht sich übrigens eine sorgfältige Kommentierung sehr bezahlt.
Viel Erfolg.
Ciao sagt der JoeamBerg
Sorry! Hab mich vertan: Die Sache mit dem einen ADC Takt gilt nur, wenn man den Channel wechselt, nachdem SingleConversion ausgelöst wurde, bei Dir geschieht es ja vorher! Du brauchst also nicht zu warten. Ich hoffe, ich hab keine Verwirrung gestiftet...
Allerdings hilft es die Optimierung im Compiler einzuschalten. Und der würde Deine leere Warteschleife ohnehin rausschmeißen.
Aber wie schon gesagt, Funktiosaufruf kostet viel Zeit, also lieber eine Funktion schreiben.
Du kannst noch ein bisschen Zeit sparen, indem Du die nächste Konvertierung startest, bevor Du das ADC Register ließt, denn das letzte Ergebnis steht solange dort an, bis es vom nächsten überschrieben wurde.
Gruß
Lesezeichen