Hallo.
Ich habe folgendes Problem und hoffe ihr könnt mir helfen.
Ich habe eine ADC-ISR, die bei erfolgter ADC-Wandlung auslöst. In der
ISR speichere ich nur den ADC Wert in ein Array.
Nun möchte ich alle x Messungen den ADC Kanal für die nächste Messung
umschalten, zu Beispiel bei jeder achten Messung:
Ch_1 Ch_1 Ch_1 Ch_1 Ch_1 Ch_1 Ch_1 Ch_2 Ch_1 Ch_1 Ch_1 Ch_1 Ch_1 Ch_1
Ch_1 Ch_2 Ch_1 Ch_1 usw.
Mein Ansatz war, den Kanal für die nächste Messung zu Beginn der ISR
umzuschalten. Allerdings läuft der ADC an dieser Stelle schon wieder mit
der nächsten Wandlung. Dadurch würde mein Kanalwechsel erst in der
übernächsten ISR wirksam. Die Verwaltung dieses "in der übernächsten
ISR muss ich den Wert woandershin speichern" ist verwirrend und unschön.
Wie kann man das einfacher machen? Irgendwie stehe ich gerade voll auf
dem Schlauch.
Du könntest z.B. den Freerunning-Mode aufgeben, und statt dessen in der
ISR die nächste Wandlung "von Hand" starten. Dann kannst du natürlich
noch vor dem Start bei Bedarf den Kanal wechseln.
Consox schrieb:> übernächsten ISR wirksam. Die Verwaltung dieses "in der übernächsten> ISR muss ich den Wert woandershin speichern" ist verwirrend und unschön.
Das kommt drauf an, wie du das realisiert hast.
Mit 3 globalen Variablen
1
uint8_tNrSamples;// Anzahl der Samples für den momentanen Kanal
2
uint8_tSampleChannel;// Auf welchem Kanal wird gesampelt
3
uint8_tDiscardADCResult;// Beim nächsten ISR Aufruf: Ist das ADC Ergebnis was wert
4
// oder solle es verworfen werden?
sollte sich das eigentlich ganz gut in den Griff kriegen lassen.
In der ISR
1
if(!DiscardADCResult){
2
->ErgebnisgiltundwirdfürdenSampleChannelabgelegt
3
NrSamples++;
4
}
5
else
6
DiscardADCResult=false;// dieses Ergebnis wurde verworfen, aber
7
// das nächste gilt wieder
8
9
if(NrSamples==Maximum){// Zeit für Kanalwechsel
10
SampleChannel++;
11
NrSamples=0;
12
ADMUXumstellen;
13
DiscardADCResult=true;// nächstes ADC Ergebnis gilt nichts
@Stefan
Das wäre eine Idee. Allerdings sample ich damit Audiosignale und habe
kein Gefühl dafür, wie sich die daraus resultierende Zeitverschiebung
zwischen Abtastzeitpunkten auf das Ergebnis auswirkt.
@Karl heinz
Ähm, ich will aber keinen Wert verwerfen. Ich möchte 7x Channel 1
einlesen, dann einmal Channel 2, dann wieder 7x Channel 1 und so weiter.
Das alles im gleichen Takt. Die Ergebnisse von Ch1 sollen in ein Array,
die Ergebnisse von Ch2 in ein anderes Array.
Consox schrieb:> Ich möchte 7x Channel 1> einlesen, dann einmal Channel 2, dann wieder 7x Channel 1 und so weiter.> Das alles im gleichen Takt. Die Ergebnisse von Ch1 sollen in ein Array,> die Ergebnisse von Ch2 in ein anderes Array.
Ah ok. dann musst du praktisch den ADC bereits auf den nächsten Kanal
weiterschalten, wenn die letzte Messung für einen Kanal gerade im laufen
ist.
Wo ist dann das Problem?
Wenn du immer 8 ADC Messungen machen willst, schaltest du bereits nach
der 7.ten den ADC in den nächsten Kanal. Du musst dir nur merken, dass
die nächste Messung für die die ISR aufgerufen wird, noch für den
vorhergehenden Kanal gilt. Im Prinzip genau so, wie ich das mit dem
Discard gemacht habe, nur anstelle von verwerfen speicherst du den Wert
noch beim vorhergehenden Kanal.
Aufzeichnen auf Papier (die x Achse ist die Zeitachse) hilft, Ordnung in
das Chaos zu bringen und sich anzusehen, in welcher Reihenfolge welche
Dinge, beim Betreten der ISR gemacht werden müssen und warum.
Consox schrieb:> Das wäre eine Idee. Allerdings sample ich damit Audiosignale und habe> kein Gefühl dafür, wie sich die daraus resultierende Zeitverschiebung> zwischen Abtastzeitpunkten auf das Ergebnis auswirkt.> ...> Ähm, ich will aber keinen Wert verwerfen.
Dann bleibt dir nichts anderes übrig, als sich mit dem "verwirrend und
unschön" anzufreunden. Soo wild ist das ja aber nun auch nicht. Du lässt
z.B. eine Variable von 0 bis 7 durch zählen. Bei 5 wechselst du auf Ch2,
bei 6 zurück auf Ch1. Bei 0-6 hast du die Ch1-Ergebnisse, bei 7 das
Ch2-Ergebnis.
Hallo,
Karl heinz Buchegger schrieb:> Wo ist dann das Problem?> Wenn du immer 8 ADC Messungen machen willst, schaltest du bereits nach> der 7.ten den ADC in den nächsten Kanal. Du musst dir nur merken, dass> die nächste Messung für die die ISR aufgerufen wird, noch für den> vorhergehenden Kanal gilt. Im Prinzip genau so, wie ich das mit dem> Discard gemacht habe, nur anstelle von verwerfen speicherst du den Wert> noch beim vorhergehenden Kanal.
Dabei aber daran denken, daß der Kanal erst nach dem 2. ADC-Takt
umgeschaltet werden darf, erst dann ist der Sample&Hold-Wert stabil.
Das würde eine Wartezeit in der ISR bedeuten, die vermutlich auch wieder
Probleme bereitet.
Gruß aus Berlin
Michael
Michael U. schrieb:> Dabei aber daran denken, daß der Kanal erst nach dem 2. ADC-Takt> umgeschaltet werden darf, erst dann ist der Sample&Hold-Wert stabil.> Das würde eine Wartezeit in der ISR bedeuten, die vermutlich auch wieder> Probleme bereitet.
Warum denn nicht...?
* Auslesen des ADC und Kanal umschalten in der ADC-ISR, Timer I-Flag
zurücksetzen (siehe Unten).
* ADC (kurze Zeit später) durch einen Timer-Event triggern.
Timer-Trigger muss natürlich etwas länger als die Wandelzeit sein.
Dadurch werden vermutlich auch die Zeitabstände zwischen den Samples
gleichmäßiger.
@ Werner B. (werner-b)
>Warum denn nicht...?>* Auslesen des ADC und Kanal umschalten in der ADC-ISR, Timer I-Flag>zurücksetzen (siehe Unten).>* ADC (kurze Zeit später) durch einen Timer-Event triggern.
Und wozu wurde der Free running mode erfunden?
>Timer-Trigger muss natürlich etwas länger als die Wandelzeit sein.>Dadurch werden vermutlich auch die Zeitabstände zwischen den Samples>gleichmäßiger.
Dafür gibt es den Free running mode. Dort ist die Abtastrate absolut
gleichmäsig.
Aber mal rechnen. Der ADC braucht 50..200kHz, sinnvollerweise wird man
ihn immer mit nahe 200kHz betreiben. Ein Takt sind also 5us. Macht bei
max. 20 MHz 100 Takte. Naja, die kann man verschmerzen. In C dauert der
ISR Einsprung sowieso etwas länger, weil meist mehr Register auf dem
Stack landen. Dann noch ADC Ergebnis auslesen und speichern, ggf. was
einfaches berechnen. Wenn dann immer noch keine 5µs vorbei sind (im
Simulator prüfen), kann man ausnahmsweise ein _delay_us() einbauen, auch
wenn man das in einem Interrupt sonst nicht macht.
MfG
Falk
P S Aber irgendwie hat Atmel da gepennt. Siehe Beschreibung im
Datenblatt unter "Changing Channel or Reference Selection". Wäre es
nicht DEUTLICH sinnvoller, wenn eben genau WÄHREND der sampling time der
Update von ADMUX gesperrt ist, und während der gesammten Conversion Time
ein Update möglich ist. Denn Nach der Sampling Time ist der MEsswert
doch in der Sample & Hold Stufe fest, da kann der analoge Eingang doch
zappeln? Oder etwa nicht? Oder gibt es vielleicht ei Übersprechen vom
Eingang in die Sample & Hold?
Hallo,
Falk Brunner schrieb:> P S Aber irgendwie hat Atmel da gepennt. Siehe Beschreibung im> Datenblatt unter "Changing Channel or Reference Selection". Wäre es> nicht DEUTLICH sinnvoller, wenn eben genau WÄHREND der sampling time der> Update von ADMUX gesperrt ist, und während der gesammten Conversion Time> ein Update möglich ist. Denn Nach der Sampling Time ist der MEsswert> doch in der Sample & Hold Stufe fest, da kann der analoge Eingang doch> zappeln? Oder etwa nicht? Oder gibt es vielleicht ei Übersprechen vom> Eingang in die Sample & Hold?
ja, wenn sie da noch ein Register eingebaut hätten, in das die MUX-Daten
geschrieben werden und dann intern nach dem Abkoppeln der S&H diese
intern übernommen hätten, müßte man darüber nicht nachdenken.
Andererseits war der ADC im AVR wohl auch eher für "langsame" Sachen
gedacht und da stört sowas dann weniger.
Gruß aus Berlin
Michael