2 ADC-Kanäle "gleichzeitig" abtasten - AVR Atmega32

Gast #1029255
Lesenswert?

Hallo,

um einen Filteralgorithmus auf einem ATMega32 anwenden zu können, muss 
ich zwei analoge Signale miteinander vergleichen können.
Dabei scheitere ich gerade daran, diese beiden Signale quasi 
gleichzeitig abzutasten (interner ADC sollte ausreichen).

Meine Idee war folgende: Die relativ genaue Abtastfrequenz (10 kHz) wird 
über einen Timer-Compare-Match-Interrupt, der den ADC triggert, 
realisiert.
Für einen Kanal funktioniert das zufriedenstellend.

Jetzt wollte ich den Vergleichswert im Timerregister da, wo die Kanäle 
wechseln, so niedrig einstellen (mehrere Werte versucht), dass die 
Abtastung im Rahmen des Möglichen quasi zeitgleich abläuft. Wenn der 
zweite Kanal ausgelesen wurde, wird wieder der notwendige Wert für die 
Abtastfrequenz im Vergleichsregister gesetzt.

Bitte schaut euch mal den Quellcode an und sagt mir, was ich falsch 
mache bzw. anders machen kann.

Vielen Dank und Gruß
sigosi
Angehängte Dateien:
Gast #1029287
Lesenswert?

Nun, tatsächlich zeitgleich bekommst Du sie natürlich nicht. Das ist Dir 
auch klar, wenn ich das recht sehe.

Andererseits ist mir nicht klar, warum die überhaupt, die nachfolgende 
Wandlung des zweiten Kanals durch den Timer startest.

Ich nehem an, das die Abtastungen schon relativ genau, mit den 10kHz 
erfolgen müssen.

Die Abtastungen lassen sich aber auch durch einen Interrupt des 
AD-Wandlers selbst starten. Musst mal nach ADIF und ADIE Bits gucken 
(atmega128).

D.h. Du könntest die erste Wandlung durch den Timer starten, damit sie 
regelmässig stattfindet. Die zweite Wandlung aber durch den 
ADC-Interrupt anstsossen, damit sie möglichst schnell nach der ersten 
erledigt wird.

Schliesslich erreichst Du die maximale Messrate wenn Du alle Wandlungen 
durc den ADC-Int anstösst.
Gast #1029294
Lesenswert?

Am besten erledigt man das mit Hardware: 'track & hold' heißt das auf 
deutsch.
Direkt an die ADC-Eingänge schaltet man Kondensatoren (10n - 100n), die 
über Analogschalter mit dem Eingangssignal verbunden sind. Zur Messung 
öffnet man die Schalter (Portpin) und misst die Spannungen an den 
Kondensatoren. Auch wenn die Messungen zeitlich nacheinander erfolgen, 
sind die Meßwerte dem gleichen Zeitpunkt zuzuordnen.
Gast #1029410
Lesenswert?

Hallo,

vielen Dank schonmal für die Rückmeldungen.

Ich hatte auch schon versucht, die zweite (quasizeitgleiche) Wandlung 
direkt mit ADC-Int. auszulösen. Hab aber auch das noch nicht so richtig 
hinbekommen.
Muss ich dazu denn nicht auch den AD-Wandler in einen anderen Modus 
(free-running) bringen?
Wäre nett, wenn ihr mir mal Ideen für nen Quellcode in der ISR 
vorschlagen könntet.
Gast #1029427
Lesenswert?

>Die relativ genaue Abtastfrequenz (10 kHz)

Da das nun auch schon ziemlich viel ist, wird es letztlich immer darauf 
hinauslaufen, dass Du im Schema

1 --- 2 --- 1 --- 2 --- 1 --- 2 --- ...

misst (die Zahlen stehen für die Kanäle).

Den zweiten Kanal kannst Du maximal schnell nach dem ersten samplen, 
wenn Du den ADC-Conversion-Complete-Interrupt verwendest.  Dann sieht es 
vielleicht so aus:

1 - 2 ----- 1 - 2 ----- 1 - 2 ----- ...

Das, was Du jedoch willst, nämlich das...

12 -------- 12 -------- 12 -------- ...

...ist bei 10 kHz leider unrealisierbar.
Gast #1029442
Lesenswert?

>Hab aber auch das noch nicht so richtig hinbekommen.
Na, dann poste es doch jetzt mal hier, wenn Du magst.
Dann findet man das schon.
Ich denke im Forum hier wirst Du dazu auch einiges finden.
Da würde ich zuerstmal nachlesen. Dann weisst Du das Du die gröbsten 
Sachen raushast.

>Muss ich dazu denn nicht auch den AD-Wandler in einen anderen Modus
>(free-running) bringen?
Ja.
Gast #1029454
Lesenswert?

Das war das, was ich schon versucht hatte. Aber ich seh' grade, dass es 
zwar der free-running-Modus ist, den ich einstelle (oder?), ich aber die 
Interrupts ausgeschaltet hatte. Damit wollt ich verhindern, dass die 
Routine sich selbst aufruft.
Hat aber nicht geklappt wie ich wollte.

Wie könnte es denn mit Nutzung des Int. klappen?
Hab leider nix Vergleichbares im Forum gefunden.
Angehängte Dateien:
Gast #1029547
Lesenswert?

Du solltest nicht den free running mode nutzen.
Du kannst den ADC doch gezielt per Register starten (ADSC)...

also Programmablauf etwa so wenn maximal Rate gewünscht ist:
1
1. MAIN: auf Kanal 1 schalten, ADC start dann warten bis arrays voll.
2
(ADC wandelt)
3
2. ADC ISR: ADC-Wert im Array 1 Speichern, auf Kanal 2 umschalten, ADC starten
4
(ADC wandelt)
5
3. ADC ISR: ADC-Wert im Array 2 Speichern, auf Kanal 1 umschalten, ADC starten
6
(ADC wandelt)
.... 2 und 3 wiederhohlen sich endlos.

Und so wenn exakt 10K Rate gewünscht ist:
1
1. MAIN: Timer Setup, dann auf volle arrays warten
2
2. Timer ISR: Auf Kanal 1 schalten, ADC starten
3
(ADC wandelt)
4
3. ADC ISR: ADC-Wert im Array 1 Speichern, auf Kanal 2 umschalten, ADC starten
5
(ADC wandelt)
6
4. ADC ISR: ADC-Wert im Array 2 Speichern
2..4 wiederholen sich entsprechend der Timer einstellung.

Du mußt natürlich in einer Globalen Variable Speichern welchen
Kanal du gerade bearbeitest damit die ADC ISR jeweils das eine oder das 
andere tut.

Ausserdem solltest du nicht cli() (da überflüssig)
und niemals sei() in einer ISR verwenden....
Gast #1029594
Lesenswert?

Ja. Es gibt nicht wirklich viel konkretes.
Schau mal unter:

Beitrag "ADC für Single und Free Run"

Auch die Sachen über Interrupts würde ich Dir sehr empfehlen.

Die Reihenfolge sollte ungefähr so sein:

-1. ADC initialisieren.
0. Mux setzen
1. Auslösung der AD-Wandlung auf Timer setzen
2. Timer starten
3. Timer löst AD-Wandlung aus.  ADC auf Freerunning setzen  MUX 
toggeln
4. ADC ready INT löst aus.
5. Wert holen
6. auto trigger of
7. ADC ready INT löst aus
8. Wert holen
9. Fertig, wieder zu 0

Es werden also zwei Interrupts, der ADC-Ready und der Timer INT benutzt.

Seite 207 vom 32er Manual (2503K–AVR–08/07) ist auch wichtig.

Das kann man noch besser erklären, aber versuchs einfach schon mal zu 
verstehen.
Gast #1029597
Lesenswert?

@ Tim
>Du solltest nicht den free running mode nutzen.
Warum sollte er das nicht?

>Du kannst den ADC doch gezielt per Register starten (ADSC)...
Schon.
Man kann ihn auch im Freerunning mode betreiben oder?

Das es so geht wie Du schreibst ist sicher, aber es ist langsamer als 
der Freerunning-Mode.

Der Witz ist ja eben, das man nicht jede Wandlung von Hand startet, 
sondern automatisch. Damit ist die größtmögliche Wandlungsrate 
erreichbar.
Gast #1029672
Lesenswert?

@Spinne
>>Du solltest nicht den free running mode nutzen.
>Warum sollte er das nicht?

Weil man nicht zu beliebigen Zeitpunkten die MUX umschalten darf.

>Schon.
>Man kann ihn auch im Freerunning mode betreiben oder?

Wenn die Mux Umschaltung zu Richtigen Zeitpunkt passiert.

> Das es so geht wie Du schreibst ist sicher, aber es ist langsamer als
> der Freerunning-Mode.

jo, es kommt die Verzögerung zum aufruf und verarbeitung der ISR
zwischen den beiden Messungen.
Selbst wenn der ADC mit den mindestens notwendigen 260kHz läuft, dürfte
nur ein ADC Takt verloren gehen.

In deinem Fall müsste man bei Punkt 3 warten bis die MUX geändert werden 
darf.
Dann folgt Wandlung exakt auf Wandlung.

@sigosi:
Interner Ablauf wäre dann:
Kanal1, ADC start, warten bis 1 ADC Clock rum ist, Kanal2,
IRQ mit wert von Kanal1, Autorun abschalten,
(Zum Zeitpunkt des IRQ läuft bereits die 2. Wandlung für Kanal2)
IRQ mit wert von Kanal2

Ich muss zugeben die Lösung ist genial :-)
Gast #1029832
Lesenswert?

>Tim:
>"Die 1. Messung nach dem Umschalten der ADC MUX ist Schrott
>(datasheet)."
>Ich meine auch, sowas gelesen zu haben, finde aber die Aussage nicht
>mehr. Nach dem Aufwachen aus dem ADC-Sleep braucht er 13 Takte
>zusätzlich, aber wo steht, daß das immer so ist? Könnte man mit einem
>externen Mux diese Pause vermeiden?

Es handelt sich um die allererste Messung nach dem ADC-Start.
Danach kann man umschalten wie man will. Diér zu verwerfende Wert hängt 
mit dem nicht festgelegten Wert des Sample-&Hold-Gliedes beim 
"Einschalten" zusammen.
Gast #1030345
Lesenswert?

Sorry, habe mich bezüglich der 1. Wandlung nach MUX
umschaltung geirrt....
Im Datasheet steht nur das man nach umschaltung von Vref
die 1. Messung entsorgen soll.

@sigosi:
Für welche der 2 möglichen Methoden hast du dich entschieden?
Der C-Code sieht aus wie eine mischung aus beidem....
Gast #1030630
Lesenswert?

>Ich dachte, ich hätte mich für die Lösung ohne free running entschieden...?

Das kannst Du natürlich machen. Aber ich dachte Du wolltest das die 
zweite Wandlung so schnell wie möglich nach der ersten erfolgt.

Ich verweise nochmal auf Seite 207 vom 32er Manual (2503K–AVR–08/07)

Dort steht, wann man den MUX umschalten kann und was das für Folgen hat.
Gast #1031258
Lesenswert?

Hallo,

ich hab mal free-running-mode und single-conversion-mode 
gegenübergestellt.
Sind beide Fkt eurer Meinung nach richtig? Was würdet ihr ändern?

Beide Funktionen liefern bei der Abtastung der beiden Kanäle (am 1. 
Kanal liegt testweise ein 1kHz-Sinus, am 2. konstant Vcc )allerdings 
dasselbe FALSCHE Ergebnis: In array1 steht  konstant 0 und in array2 
konstant 16256. Wo auch immer das herkommt.
Wie gesagt, für einen Kanal wird ein 1kHz Sinus wunderbar 10-mal pro 
Periode abgetastet.

Hab S.207 studiert, ist mir auch klar. Aber wo in meinem C-Code setz ich 
denn dann ADMUX sicher? Wie kann ich denn da einschätzen wo z.B. genau 
ein ADC-Clock-Cycle rum ist?
Angehängte Dateien:
Gast #1031343
Lesenswert?

Einen Fehler hab ich grade sebst gefunden denk' ich:
Im else-Zweig muss es ADMUX &= ... heißen.
Das löst das Problem aber nicht. Im Gegenteil, das Programm kommt aus 
irgendeiner Schleife nicht mehr raus...
Gast #1031371
Lesenswert?

Hab S.207 studiert, ist mir auch klar. Aber wo in meinem C-Code setz ich
denn dann ADMUX sicher?

Du musst ihn nach dem Start einer Messung setzen. Aber nicht unmittelbar 
danach, wie im folgenden noch erklärt wird.

Vor allem nicht in dem INT vom ADC, denn der schlägt zu wenn die 
Wandlung abgeschlossen ist. Du musst aber nach dem Start der 
Wandlung den MUX umstellen. Siehe mein Post vom 27.10.2008 22:18

>Wie kann ich denn da einschätzen wo z.B. genau ein ADC-Clock-Cycle rum ist?

S. 207
Abschnitt: Changing Channel or Reference Selection
Erster Absatz. Letzter Satz.

>The user is thus advised not to write new channel or reference selection >values 
to ADMUX until one ADC clock cycle after ADSC is written.

D.h. du musst, ausgehend von Deiner Systemtaktfrequenz (CKDIV beachten) 
und Deinem Prescaler den ADC-Takt ausrechnen. Dann weisst Du wielange 
ein Takt dauert.
Gast #1031459
Lesenswert?

Soweit hab ich das verstanden. Wie gesagt, die Theorie dahinter ist mir 
klar. Mein ADC läuft mit 125 kHz.
Gibt es in meinem Quellcode schon eine mögliche Stelle den MUX 
"unbeschadet" umzuschalten? Oder muss ich dazu eine eigene Routine 
programmieren?
Gast #1031508
Lesenswert?

>Gibt es in meinem Quellcode schon eine mögliche Stelle den MUX
>"unbeschadet" umzuschalten? Oder muss ich dazu eine eigene Routine
>programmieren?

Was ist daran so kompliziert?
1
ADMUX = (ADMUX & 0x1F) | x;      // x = 0..31
Gast #1031577
Lesenswert?

@sigosi:
Wieso lauft der ADC bei dir nur mit 125kHz?
1
10.000 Sampels/Sec * 2 Kanäle * 13 Takte = 260kHz
Geht aber nur wenn Wandlung auf Wandlung kommt und Freerunning mode 
eingeschaltet bleibt...
Die 2 hier aufgezeigten Methoden halten den ADC zwischendrin an,
d.h. du brauchst mehr als 260kHz ADC clock.
Gast #1031579
Lesenswert?

>Gibt es in meinem Quellcode schon eine mögliche Stelle den MUX
>"unbeschadet" umzuschalten? Oder muss ich dazu eine eigene Routine
>programmieren?

Deinen Code habe ich mir gerade angeschaut. Er hat mit der von mir 
vorgeschlagenen Methode nur entfernt zu tun.

Bitte lies nochmal mein Post vom 27.10.2008 22:18

Wenn aber, dann kannst Du das MUX bit einfach toggeln. Das if ist 
unnötig. Ausserdem sollte der Free-Running-Mode natürlich schon vorher 
aktiv sein.
Und wieso Auto-Trigger ausschalten und dann wieder einschalten. Ich 
würde das eher mal beseite lassen. Ansonsten solltest Du mal 
kommmentieren und beschreiben was für einen Ablauf Du Dir vorstellst.

Aber das hat mit der von mir vorgeschlagenen Methode nichts zu tun. D.h. 
Du machst da was ganz anderes als ich vorgeschlagen habe.
Falls Du den Weg weitergehen willst, musst Du das sagen. Wie gesagt, 
gibt das aber nicht die schnellste Methode.
Gast #1031664
Lesenswert?

@ Tim
In Deinem Post vom 27.10.2008 23:19 schriebst Du:
>In deinem Fall müsste man bei Punkt 3 warten bis die MUX geändert werden
>darf.

In meinem Post vom 27.10.2008 22:18 schrieb ich:
>3. Timer löst AD-Wandlung aus.  ADC auf Freerunning setzen  MUX toggeln
Gast #1031717
Lesenswert?

@ Spinner
>2. Timer starten
>3. Timer löst AD-Wandlung aus. ADC auf Freerunning setzen MUX toggeln

Dazwischen dürfte wohl etwas zeit vergehen in der der ADC nix tut.
Und wenn dem so ist, reichen die 260kHz nicht.
Ausserdem musste man dann den AVR mit 260kHz*ADC_Clockdiv betreiben.

>In meinem Post vom 27.10.2008 22:18 schrieb ich:
>3. Timer löst AD-Wandlung aus.  ADC auf Freerunning setzen  MUX toggeln

Ich habe das jetzt so interpretiert dass der Timer den ADC startet.
Und ab dem moment wo er läuft 1 ADC clock gewartet werden muss bis
zur MUX umschaltung.

Oder liege ich da Flasch?
Gast #1031734
Lesenswert?

>ADC auf Freerunning setzen  MUX toggeln

Im free-running-mmode läuft der AD-Wandler kontinuierlich. Das heißt, er 
wandelt um, zeigt das fertige Ergebnis per Flag (kann ISR auslösen) an, 
und beginnt sofort mit einer neuen Wandlung!

Wenn nun in dieser ISR das MUX getoggelt wird (also zwischen zwei 
Kanälen umgeschaltet wird), so wird die nächste Wandlung mit diesem 
neuen Kanal ausgeführt(da ja zZ eine Wandlung läuft).
Somit ist das toggeln auch Zeitunkritisch.

also muss die ISR etwa so aussehen:
1
volatile uint16_t   au16AdcRes[32];
2

3
ISR(adc-complete)
4
{
5
  //----- aktuellen Kanal holen ------
6
  uint8_t  _u8AktKanal  =  (ADMUX & 0x1F);
7
  //----- adc-Wert abholen -----------
8
  au16AdcRes[u8AktKanal  ] = ADC;
9
  //----- nächsten Kanal -------------
10
  u8AktKanal  =  (u8AktKanal+1) & 0x1F;    // 0..31
11
  ADMUX = (ADMUX & 0x1F) | u8AktKanal;
12
}
Wenn der AD-Wandler kontinuierlich läuft, und der ISR-adc-fertig aktiv 
ist, dann tut diese ISR die Ergebnisse in das Array au16AdcRes ablegen.

Da du nur zwei Kanäle brauchst, kann dein Array kleiner werden, und die 
Zeile mit dem // 0..31 muss angepasst werden...
Gast #1031797
Lesenswert?

@ Tim

>>2. Timer starten
>>3. Timer löst AD-Wandlung aus. ADC auf Freerunning setzen MUX toggeln
>Dazwischen

Zwischen der Auslösung des Timer ints und dem setzen auf Freerunning und 
umstellen des MUX?
Du hast ja auch schon richtig geschrieben, das Du Umstellung des MUX 
nicht sofort sondern erst nach einem AD-Takt erfolgen darf.

Mir ist nicht ganz klar, worauf Du hiermit hinauswillst. Möglicherweise 
auf die Geschwindigkeit des Ablaufs. Falls ja: 2. und 3. verzögern 
nichts, da die Wandlung schon läuft. Während der Wandlung wird der MUX 
umgestellt.

>dürfte wohl etwas zeit vergehen in der der ADC nix tut.
Also beiehst Du Dich auf die Zeit zwischen 2. und 3. Richtig?

>Und wenn dem so ist, reichen die 260kHz nicht.
>Ausserdem musste man dann den AVR mit 260kHz*ADC_Clockdiv betreiben.
Ich habe das nicht kalkuliert. Mag sein. Mein Bestreben war, so schnell 
wie möglich zu wandeln.


>>In meinem Post vom 27.10.2008 22:18 schrieb ich:
>>3. Timer löst AD-Wandlung aus.  ADC auf Freerunning setzen  MUX toggeln

>Ich habe das jetzt so interpretiert dass der Timer den ADC startet.
>Und ab dem moment wo er läuft 1 ADC clock gewartet werden muss bis
>zur MUX umschaltung.

>Oder liege ich da Flasch?
Da liegst Du richtig, denke ich.
Möglicherweise habe ich Dich vorher falsch interpretiert.
Vorher schriebst Du ja:
>In deinem Fall müsste man bei Punkt 3 warten bis die MUX geändert werden  >darf.

Ich meinte, Du unterstellst, das ich vor Punkt 3. den MUX umstelle. 
Aber anscheined hast Du das nicht so gemeint.

@
Mir ist gerade nicht ganz klar, wen Du ansprichst, aber Du zitierst wohl 
mich.

>>ADC auf Freerunning setzen  MUX toggeln

>Im free-running-mmode läuft der AD-Wandler kontinuierlich. Das heißt, er
>wandelt um, zeigt das fertige Ergebnis per Flag (kann ISR auslösen) an,
>und beginnt sofort mit einer neuen Wandlung!

Das ist ja soweit klar. Meine Idee ist, den Auslöser immer von Timer auf 
Freerunning umzustellen. Gehst Du davon auch aus?


Der Zeitablauf sieht dann so aus:

(da ist so ein zeilenumbruch beim letzten "wert holen")

--init--+--timer_läuft--+--timer_isr ---+--wert holen---+--wert 
holen--->
        |               |  wandlung     |  wandlung     |
        t               t               A               A
        i               i               D               D
        m               m               C               C
        e               e               -               -
        r               r               i               i
        -               -               n               n
        s               i               t               t
        t               n               -               -
        a               t               1               2
        r
        t
Gast #1031847
Lesenswert?

>Meine Idee ist, den Auslöser immer von Timer auf
>Freerunning umzustellen. Gehst Du davon auch aus?

Nein. Wenn der AD-Wandler kontinuierlich wandelt, kann man das als 
weiteren Timer betrachten. Dieser "Timer" hat dann die Frequenz

f = f_adc / Anzahl_Takte_je_Wandlung

Somit finde ich es Unsinn, einen weiteren TImer zu sowas zu bemühen..
Gast #1031893
Lesenswert?

@ Matthias Lipinsky

>Somit finde ich es Unsinn, einen weiteren TImer zu sowas zu bemühen..

Naja, angesichts der min. 65us (bei voller Auflösung) die ich mit meiner 
Methode erreichen könnte gebe ich Dir recht.
Aber als Idee finde ich es immer noch gut. Habe das, allerdings bei 
wesentlich geringeren Wiederholraten, schon ein paarmal so gemacht.
Gast #1032065
Lesenswert?

>...diese beiden Signale quasi gleichzeitig abzutasten ...
>...liegt testweise ein 1kHz-Sinus...

Wie auch immer Ihr Euer Softwaregefrickel löst, mit dem internen ADC 
eines AVR und reiner Softwärelösung sind die o.g. Forderungen nicht zu 
erfüllen.
Um das zu erkennen, muß man garkein Programmierer sein, sondern nur den 
Meßfehler im Nulldurchgang des 1kHz Signals berechnen.
Gast #1033497
Lesenswert?

Hallo,

ich hab mir eure Beiträge alle durchgelesen und bin durch die 
verschiedenen Vorschläge etwas verwirrt ;-)
Ich möchte das Programm genauso ablaufen lassen wie im Post von Spinne 
vom 27.10.2008 22:18.
Dazu hab ich meinen aktuellen Code mal angefügt mit den Ablaufschritten 
jeweils als Kommentar neben den Zeilen. Bitte gebt mir mal 
Rückmeldungen/Verbesserungsvorschläge dazu und sagt mir, wo ich noch was 
falsch mache. Der Controller bleibt irgendwo im Programm stecken.

Zu den anderen Vorschlägen, die natürlich auch in Frage kommen:
- Wenn ich den AD-Wnadler komplett im free-running betreiben würde, 
könnte ich doch für eine konkrete Abtastrate einfach die Wandlungen 
zählen, oder?
- Die 10 kHz Abtastrate sind eurer Meinung nach ja etwas zu hoch 
gegriffen. Mir reicht im Prinzip auch 2 kHz. Welche anderen 
Möglichkeiten eröffnet mir das?
Angehängte Dateien:
Gast #1034694
Lesenswert?

Hallo,

wollte euch mitteilen, dass ich das Programm (Quellcode vom 31.10.) zum 
Laufen gebracht habe.
Das Durchlaufen einer Endlosschleife lag nicht an fehlerhaftem Code 
sondern an der zu hohen Abtastrate. Der Compare-Wert des Timers wurde 
vor Abschluss der Wandlung im free-running für den anderen Kanal 
erreicht. Das führte natürlich dazu, dass der Int. zu früh auslöste und 
die Int.Fkt. sich immer wieder selbst aufrief ohne die Zählvariable zu 
inkrementieren und die Kanäle getrennt sauber auszulesen.
Für eine Abtastrate von 4kHz läuft das Programm.

Natürlich ist noch ein Zeitversatz für das quasizeitgleiche Abtasten 
(von Kanal1 auf Kanal2) vorhanden. Werde jetzt prüfen, ob sie 
tolerierbar ist.
Wenn nicht, werde ich's mal mit der vorgeschlagenen "track&hold"-Methode 
(Post vom 27.10.2008 18:17)

Vielen Dank für eure guten Beiträge, das Forum ist wirklich erstklassig!
Gast #1071845
Lesenswert?

Hallo zusammen!

Genau das Thema habe ich gesucht!
Ich will mit einen Atmege8 3 analoge Spannungen an 3 ADC messen.
Nun hab ich mir mal den Code von Matthias Lipinsky angeschaut!

volatile uint16_t   au16AdcRes[32];

ISR(adc-complete)
{
  //----- aktuellen Kanal holen ------
  uint8_t  _u8AktKanal  =  (ADMUX & 0x1F);
  //----- adc-Wert abholen -----------
  au16AdcRes[u8AktKanal  ] = ADC;
  //----- nächsten Kanal -------------
  u8AktKanal  =  (u8AktKanal+1) & 0x1F;    // 0..31
  ADMUX = (ADMUX & 0x1F) | u8AktKanal;
}

Wenn ich das richtig verstanden habe muß ich doch nur die Maske
von 0x1F = 11111 im ADMUX auf 0x03 also MUX 0 und MUX 1 verändern
oder?
Gast #1071851
Lesenswert?

>Wenn ich das richtig verstanden habe muß ich doch nur die Maske
>von 0x1F = 11111 im ADMUX auf 0x03 also MUX 0 und MUX 1 verändern
>oder?

Falsch verstanden.
>u8AktKanal  =  (u8AktKanal+1) & 0x1F;    // 0..31
Erhöht die Nummer des Eingangskanals, die man dann noch begrenzen 
kann/muss.

>ADMUX = (ADMUX & 0x1F) | u8AktKanal;
Liest den neuausgewählten AD-Kanal aus.
Du musst also u8AktKanal verwenden und bearbeiten.
#1071907
Lesenswert?

Hallo,
@Tim: nur nach dem Umschalten der Referenz ist die erste Messung 
Schrott.
beim Umschalten der Eingänge hängt es nur davon ab, wie niederohmig die 
Quelle ist und wie früh der Wechsel der Eingänge passiert.

Der ADC braucht 2 Wandlertakte für den S&H, ab dritten Wandlertakt kann 
der MUX umgeschaltet werden. Der Eingangskram hat dann rund 10 
Wandlertakte Zeit zum Einschwingen.

Wenn die beiden Wandlungen schnellst möglich hintereinander passieren 
sollen und auch noch halbwegs genau sein sollen, geht eigentlich nur 
folgender Ablauf:

1. Wandlung starten
warten, bis 3 ADC-Takte vorbei sind
MUX auf den anderen Eingang schalten (S&H hält jetzt den Wert des ersten 
Eingangs(
Am Ende der Wandlung des ersten Wertes den Wett holen und die 2. 
Wandlung starten.

Ob sich das geschickt in einen Timer-IRQ packen läßt, müßte man jetzt 
ausrechnen. Da der AVR nicht würfelt, ist das Verhältnis der Zeiten 
durch den ADC-Vorteiler usw. ja bekannt und konstant.

Ob sich das in reinem C erledigen läßt?
Keine Ahnung, bin ASM-Programmierer... ;-)

Gruß aus Berlin
Michael

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren