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
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.
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.
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.
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.
>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.
>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.
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.
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....
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.
@ 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.
@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 :-)
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?
>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.
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?
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....
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?
>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.
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?
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...
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.
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?
>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?
@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.
>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.
@ 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.
@ 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
@ 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?
>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
volatileuint16_tau16AdcRes[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...
@ 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
>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..
@ 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.
>...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.
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?
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!
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?
>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.
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?
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