Forum: Compiler & IDEs ADC Kanal in ISR umschalten


von Consox (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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_t NrSamples;              // Anzahl der Samples für den momentanen Kanal
2
uint8_t SampleChannel;          // Auf welchem Kanal wird gesampelt
3
uint8_t DiscardADCResult;       // 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
     -> Ergebnis gilt und wird für den SampleChannel abgelegt
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
   ADMUX umstellen;
13
   DiscardADCResult = true;    // nächstes ADC Ergebnis gilt nichts
14
 }
15
}

von Consox (Gast)


Lesenswert?

@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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Consox (Gast)


Lesenswert?

Danke euch Beiden. Wenn man das mit einfachen Worten von jemand Anderem 
hört, sieht die Lösung gleich viel einfacher aus.

von Michael U. (amiga)


Lesenswert?

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

von Werner B. (werner-b)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

@  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?

von Michael U. (amiga)


Lesenswert?

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

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.