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 :-)
OK, vielen Dank. Das sind wirklich gute Vorschläge. Ich komme erst morgen dazu, sie auszuprobieren. Meld mich dann mal bei Erfolg bzw. Misserfolg.
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?
>Muss ich nach den jeder Kanalumschaltung machen?
Nein. Wie oben schon geschrieben...
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?
1 | ADMUX = (ADMUX & 0x1F) | x; // x = 0..31 |
@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 | 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...
@ 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
Sorry, da wo ein einzelnes @ steht sollte eigentlich @ Matthias Lipinsky (lippy) stehen.
>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?
Ok danke! Ich habs jetzt auch verstanden! War wohl noch bissel zu zeitig heut Früh! :-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.