Hallo allerseits, zuerst möchte ich mich gleich entschuldigen, falls ich ein abgedroschenes Thema mit einem neuen Thread starte, wo evtl bereits ein Beitrag existiert, aber ich habe über die Suchfunktion nichts Spezifisches zum Thema gefunden. Wie man wahrscheinlich merkt bin ich relativ neu in der Materie, ich werde daher versuchen das Problem so gut wie möglich zu beschreiben. Grundsätzlich geht es darum mittels µC einen Sensor (in unserem Fall Beschl.sensor) mit fixer sampling rate (dzt. 100Hz, wünschenswert wären aber bis zu 300Hz) abzutasten und das Ergebnis per SPI an ein Funkmodul zu übergeben (RFM70) welches dieses an einen Datenlogger sendet (also Kommunikation Sensornode zu Empfänger). Dabei ist momentan noch nicht fixiert, ob der Sensor analog bleibt (wie momentan) oder durch einen SPI-Sensor ersetzt wird. Derzeit arbeiten wir mit einem Atmega8 mit externem Quarz (1,8432 Mhz). Der ADC wird per TimerInterrupt in einer Interruptroutine gestartet (wobei gewartet wird, bis das Ergebnis zur Verfügung steht --> ADC complete Interrupt). Das Verschicken findet nach Fertigstellung der 3 Wandlungen (3 Wandlungen per Messvorgang da 3-achsiger Beschl.sensor) statt. Jetzt haben wir aus gewissen technischen Gründen auf einen Atmega88 umgestellt. Dabei ist mir aufgefallen, dass der ADC des 88er per Triggerevent gestartet werden kann (in unserem Fall wäre das ein Timerinterrupt); was doch bedeutet, dass ich keine Timer-ISR mehr benötige, in der ich den ADC starte, sondern nur mehr den Timer initialisiere und den ADC entsprechend konfiguriere?. Meine Überlegung ist nun folgende (ich hoffe ich kann`s halbwegs verständlich rüberbringen): Der ADC wird mit dem Timer getriggert - das Starten erfolgt also in keiner ISR, sondern hardwaremäßig - ich kann nach dem Starten "quasiparallel" in meiner Main zeitlich unkritische Polling-Dinge (wie Verschicken von gepufferten Daten) abarbeiten, bis mein conversion complete flag gesetzt wird. Damit wird die ISR aufgerufen, ich lege mein Ergebnis im Puffer ab, starte den zweiten Wandlungsvorgang desselben Durchlaufes (also z.B. Wandlung des x-Wertes wurde beendet --> ADC complete flag --> ISR wird aufgerufen: x-Daten lesen und ablegen, y-Wandlung starten --> ISR verlassen) und wechsle wieder zur main für zeitunkritische Befehle und detto für die dritte Wandlung. Dann kommt der nächste Timerinterrupt und das ganze Spiel geht wieder von vorne los..Ist diese Variante grundsätzlich sinnvoll, oder ist es besser auf die 3 Werte zu warten und erst anschließend zeitunkritische Befehle auszuführen? Mir ist es deshalb unklar, da ich noch nicht ganz verstanden habe, ob die CPU durch die Aktivität des ADC blockiert ist und während der Wandlung keine anderen Dinge erledigen kann. Andererseits (ich hoffe ich verzapfe damit keinen kompletten blödsinn): CPU .. 1.8432Mhz <--> ADC max 200kHz --> ADC Befehle werden etwa nur bei jedem 9. CPU-Takt ausgeführt, bleiben also 8 ungenützte Takte dazwischen..; ist das so richtig oder kann man das nicht so einfach umrechnen? Wenn es doch stimmt, dann wären das bei einer angestrebten CPU-Frequenz von 7.3728Mhz bereits 39 ungenützte Takte, sofern auf das Ergebnis gewartet wird Ich hoffe es war nicht zu sehr verwirrend. Wäre sehr dankbar, wenn jemand weiß, wie das mit dem Timing genau aussieht lg David
Hallo David, willst Du drei ADC Eingänge abfragen ? Hast Du über Störrungen nachgedacht und evtl. eine Mittelwertbildung oder ein anderes Verfahren in betracht gezogen ? Die ADC Wandlung erfolgt per Hardware und je nach deiner Software wird in der Main auf eine Wandlung gewartet. Schau dir auch im Datenblatt die Synchronisierung von ADC Kanalwechseln an. Ich würde die gesamte Messung aller drei Kanäle per ADC ISR ausführen lassen und nur den Event der Main über - ein Flag - signalisieren. Die Ergebnisse lägen dann in einen uint16_t Array mit drei Elementen. Die Index entsprechen deinen Kanälen. Auch das Senden per SPI würde ich über einen FiFo im Interrupt erledigen lassen. Link: [1] www.atmel.com/images/doc2545.pdf -- Seite 247ff -
David Höftberger schrieb: > verstanden habe, ob die CPU durch die Aktivität des ADC blockiert ist > und während der Wandlung keine anderen Dinge erledigen kann. Die CPU wird nicht blockiert. Der ADC ist eine unabhängige HW-Einheit. > Andererseits (ich hoffe ich verzapfe damit keinen kompletten blödsinn): > CPU .. 1.8432Mhz <--> ADC max 200kHz --> ADC Befehle werden etwa nur bei > jedem 9. CPU-Takt ausgeführt, bleiben also 8 ungenützte Takte ADC Befehle werden von der CPU mit CPU Geschwindigkeit ausgeführt. Der ADC mit seinen Transistoren benutzt die 200kHz für seine Wandlung unabhängig davon. Braucht ca 13 Takte von den 200kHz für eine Wandlung. Genaueres . Datenblatt. CPU arbeitet in der Zeit mit seinem CPU Takt weiter am Programm. > CPU-Frequenz von 7.3728Mhz bereits 39 ungenützte Takte, sofern auf das > Ergebnis gewartet wird Warten tut man im Programm/ISR mit dem CPU Takt. Liegt aber an dir/Programm. Macht man nicht und wie ich den Aufbau des Programms verstanden habe, tust du das auch nicht. Dein Programm wird also zu jeder Zeit mit dem CPU Takt ausgeführt.
Hall und danke für eure Antworten. Entschuldigt bitte, dass ich mich erst jetzt melde, aber ich habe wahrscheinlich bei meinen Forumseinstellungen vergessen die Emailbenachrichtigung für neue Antworten zu aktivieren und hab die neuen Beiträge daher erst jetzt gesehen @ Uwe: > willst Du drei ADC Eingänge abfragen ? ja genau, so hätte ich das vor, allerdings weiß ich noch nicht genau, wie ich das mit dem Triggerevent handlen soll, da einerseits der Timerinterrupt die Wandlungen startet (für eine Messreihe bestehend aus 3 Wandlungen x,y,z) aber andererseits es auch nicht schlecht wäre, wenn der ADC für diese 3 hintereinanderfolgenen Einzelwandlungen (also beim Übergang von x-->y und y-->z) im kontinuierlichen Wandlungsmodus arbeiten würde (also mit seinem eigenen Interruptflag als neues Startsignal). Das wird aber wahrscheinlich nur über eine Umkonfigurierung des ADC vor den entsprechenden Programmblöcken möglich sein (triggerquelle umstellen..) > Hast Du über Störrungen nachgedacht und evtl. eine Mittelwertbildung >oder ein anderes Verfahren in betracht gezogen ? Hab ich mir noch nicht im Detail überlegt, welche Art Störungen sprichst du genau an, bzw. wie meinst du das mit einem anderen Verfahren? Wie ich bereits angesprochen habe, wäre die Alternative ein Sensor mit digitalem Ausgang. Das ist allerdings abhängig davon, was vom Ablauf her schneller ist: 3 analoge Wandlungen oder die Abfrage eines 3-achsigen SPI-Sensors Die restlichen Dinge handhabe ich auch so, wie von dir beschrieben, also über das Interruptflag vom ADC (ADC ISR), allerdings war mir nicht klar, ob der ADC nun als ein von der CPU unabhängiger Baustein angesehen werden kann, der seine Wandlungen ohne Blockierung der CPU durchführt Das mit dem Synchronisieren der Kanalwechsel hört sich interessant an, werde ich mir demnächst zu Gemüte führen :) >Auch das Senden per SPI würde ich über einen FiFo im Interrupt erledigen >lassen. Da war ich mir eben auch nicht 100%ig sicher; meinst du ich sollte die gewandelten Werte gleich nach Bereitstehen aller 3 Werte noch in der ADC ISR im SPI-FiFo ablegen und das Verschicken per UART durch das RFM70 in der main erledigen? @ Absatz: >Die CPU wird nicht blockiert. Der ADC ist eine unabhängige HW-Einheit. >ADC Befehle werden von der CPU mit CPU Geschwindigkeit ausgeführt. Der >ADC mit seinen Transistoren benutzt die 200kHz für seine Wandlung >unabhängig davon. Braucht ca 13 Takte von den 200kHz für eine Wandlung. >Genaueres . Datenblatt. CPU arbeitet in der Zeit mit seinem CPU Takt >weiter am Programm. Ok, danke, ich hatte es so vermutet. Das bedeutet also auch, nachdem der ADC seine 13 Zyklen bei 200kHz benötigt, dass die CPU bei einem gegebenen Takt von 7,..etc Mhz, da sie ja parallel in der main weiterarbeiten kann, ca. 13*39 Takte Zeit hat bis zum Eintreffen des ADC-Interrupts, was ja an und für sich eine Menge Holz ist ;-) um zeitunkritische Befehle zu erledigen (wie zum Bsp das Versenden per Uart durch das RFM70). Oder sollte das Versenden nicht durch einen evtl. eintreffenden ADC-Interrupt unterbrochen werden?
AUTSCH ADC-Wandlung im Timer-IRQ m( Was Du willst geht relativ einfach: 1. ADC im Freerunning-Mode laufen lassen und da nacheinander durchschalten 2. ADC-Werte global ablegen und Flag setzen 3. Flag auswerten und ADC-Werte via SPI abschicken Wenn Du 200Hz Sampling haben willst noch einen Timer nehmen und nur die ADC-Werte verschicken die das Kriterium erfüllen.
@ kopfkratzer
Ja danke, du hast natürlich Recht :(, ich hatte nach der Erkenntnis, des
von der CPU unabhängigen ADCs die Geschichte nicht zu Ende gedacht..
Genereller Freerunning-Modus mit zeitlich definiertem Zugriff ist die
beste Lösung.
> ADC-Wandlung im Timer-IRQ m(
Ist zwar ohnehin obsolet, aber ich hätte eigentlich keine eigene Timer
Interrupt routine vorgehabt, sondern nur den Start-Triggereingang des
ADC mit dem Timer-Ticken belegt,.. kann aber natürlich sein, dass ich
das beim 88er noch nicht richtig verstanden habe, da ich diese Info
lediglich aus dem Datenblatt und noch nicht praktisch ausprobiert habe
Hallo kopfkratzer,
>ADC im Freerunning-Mode laufen
und drei Kanäle Samplen passt nicht zusammen --> Datenblatt .
Es ist schon richtig, nach eine ADC-Wandlung den Wert per ADC-Interrupt
abholen, den Kanalwechseln - ADC-Takte beachten - und eine neue Messung
starten.
Nach drei Messungen x,y,z kann dann, z.B. das Tripel dem Uart Fifo
übergeben werden.
Peter D. PeDa hat dazu alles schon programmiert.
Uwe S. schrieb: >>ADC im Freerunning-Mode laufen > und drei Kanäle Samplen passt nicht zusammen --> Datenblatt . m( Es geht um das allgemeine Prinzip nicht darum das er nun wegen des ATMEL in der ADC-IRQ den MUX umschalten muß, das hängt vom jeweiligen µC ab.
Ok, ich verstehe deinen Ansatz. Da sich der TE aber auf einen Atmega88 bezieht, betrachte ich das Problem jetzt speziell.
In meinem FU Projekt starte ich den ADC des ATMega 88 einmal während der Intialisierung, danach sorgt der ADC Complete Interrupt fürs Auslesen des Wertes, schaltet dann den Kanal um und startet die nächste Wandlung. Das klappt so gut, das die PWM Erzeugung (der Kern des Projektes) keinen Moment aus dem Tritt gerät. Schaus dir mal an, der ADC Interrupt ist ganz am Ende des Codes: http://www.mikrocontroller.net/articles/Frequenzumrichter_Wettbewerb
Hallo, danke für eure Antworten, habs jetzt von der ADC-Seite gelöst wie von euch geraten, also Wandlung im kontinuierlichen Modus - ADC-Interrupt für 3 Wandlungen aktiviert, dann am Ende des 3. nacheinanderfolgenden Aufrufs der ADC-ISR ADC-Interrupt deaktiviert und beim nächsten Timer-Interrupt wieder aktiviert. Messwerte werden am Ende der 3. Ausführung der ADC-ISR ausgelesen und in der main weiterverarbeitet. Funktioniert eigentlich soweit - allerdings nur beim Atmega8 Womit ich auch bei meiner nächste Frage wäre: Verwendet von euch jemand Eclipse mit AVR-Plugin? Hätte die aktuellste AVR-Dude Version, Controller wird vom Projekt erkannt, auch vom AVR-Dude, die IO-Header enthält die Einträge zum 88er, aber die Rgisternamen werden nicht erkannt (z.B. Symbol OCIE2A could not be resolved, etc..). Hatte jemand bereits ein ähnliches Problem (beim Atmega8 ging eigentlich alles problemlos). Zu verändernde Register von 8 auf 88er wurden von mir berücksichtigt, mir geht es wirklich nur darum, dass die Namen nicht erkannt werden. @Matthias: Danke für den Hinweis auf dein Projekt, hab gesehen, dass die Implementierung des ADC ziemlich ähnlich ist wie bei mir
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.