Forum: Compiler & IDEs 2 ADC-Kanäle "gleichzeitig" abtasten - AVR Atmega32


von sigosi (Gast)


Angehängte Dateien:

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

von Tim (Gast)


Lesenswert?

Die 1. Messung nach dem umschalten der ADC MUX ist schrott (datasheet).
Warum startest du nicht aus der ISR vom ADC eine neue Messung?
Dann geht das Ohne Timer und so schnell wie möglich.

von Spinne (Gast)


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.

von Gast (Gast)


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.

von sigosi (Gast)


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.

von Gast (Gast)


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.

von Spinne (Gast)


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.

von sigosi (Gast)


Angehängte Dateien:

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.

von Tim (Gast)


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

von Spinne (Gast)


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.

von Spinne (Gast)


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.

von Tim (Gast)


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 :-)

von sigosi (Gast)


Lesenswert?

OK, vielen Dank. Das sind wirklich gute Vorschläge.
Ich komme erst morgen dazu, sie auszuprobieren.
Meld mich dann mal bei Erfolg bzw. Misserfolg.

von Christoph db1uq K. (christoph_kessler)


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?

von STK500-Besitzer (Gast)


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.

von sigosi (Gast)


Angehängte Dateien:

Lesenswert?

Könnte es vielleicht so funktionieren?
Die globale Variable spar ich mir, indem ich einfach den 
MUX-Registerzustand abfrage.
Von so einem "Dummy-Readout" hab ich auch - u.a. im GCC-Tutorial - 
gelesen. Muss ich nach den jeder Kanalumschaltung machen?

von STK500-Besitzer (Gast)


Lesenswert?

>Muss ich nach den jeder Kanalumschaltung machen?

Nein. Wie oben schon geschrieben...

von Tim (Gast)


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

von sigosi (Gast)


Lesenswert?

Ich dachte, ich hätte mich für die Lösung ohne free running 
entschieden...?
Wie würde denn deiner/eurer Meinung nach die Abänderung für einen der 
beiden Wege aussehen?

von Spinner (Gast)


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.

von sigosi (Gast)


Angehängte Dateien:

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?

von sigosi (Gast)


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

von Spinner (Gast)


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.

von sigosi (Gast)


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?

von Matthias L. (Gast)


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

von Tim (Gast)


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.

von Spinner (Gast)


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.

von Spinner (Gast)


Lesenswert?

@ Tim
>Die 2 hier aufgezeigten Methoden halten den ADC zwischendrin an,
>d.h. du brauchst mehr als 260kHz ADC clock.
Die von mir vorgeschlagene tut das nicht.

von Spinner (Gast)


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

von Tim (Gast)


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?

von Matthias L. (Gast)


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

von Spinner (Gast)


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

von Spinner (Gast)


Lesenswert?

Sorry, da wo ein einzelnes @ steht sollte eigentlich

@  Matthias Lipinsky (lippy)

stehen.

von Matthias L. (Gast)


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

von Spinner (Gast)


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.

von Gast (Gast)


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.

von sigosi (Gast)


Angehängte Dateien:

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?

von sigosi (Gast)


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!

von Tony (Gast)


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?

von STK500-Besitzer (Gast)


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.

von Tony (Gast)


Lesenswert?

Ach so! u8AktKanal ist der Kanalzähler und wird dann
einfach mit "|" angehängt!
Also Admux (11111) und u8AktKanal z.B (111)
ergibt dann Admux (11111111)
oder?

von Tony (Gast)


Lesenswert?

Ok danke!
Ich habs jetzt auch verstanden!
War wohl noch bissel zu zeitig heut Früh! :-)

von Michael U. (amiga)


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

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.