allo zusammen,
ich bin dabei, mit einer Capture Unit ein Frequenz zu messen. die
Frequenz ist recht gering und spielt zwischen 0 und ca. 250Hz.
Verwendet wird dabei ein Atmega 8. Ein Optokoppler schaltet dabei bei
jedem Signal Masse an den ICP Pin durch. Sonst liegt der ICP Pin durch
einen externen pullup (10K) auf "high". Eine LED hängt an PB1 auf active
low
(zur Frequenzdarstellung).
Das Hauptprogramm soll später einmal die Frequenz dann aus den Timer
werten berechnen, aber das Einlesen klappt im Moment noch nicht ganz.
Gedacht ist, zunächst bei fallender Flanke einzulesen, Wert sichern eine
LED einschalten, die Flanke wechseln, darin dann die LED ausschalten,
nächste fallende einlesen, Endwert sichern, LED wieder anschalten,
wieder auf steigende Flanke wechseln und darin die LED ausschalten.
Durch den Start und Endwert kann ich dann später meine Frequenz
errechnen.
Nur das Problem ist, die LED müsste mit steigender Frequenz immer
kräftiger erscheinen, bis sie für das Auge ab ca. 30-40 Hz in
"Dauerleuchten" übergeht. Leider "hängt" die LED manchmal zwischendrin,
als ob sie nicht ausgeschaltet wird, also deutlich länger und dadurch
auch heller leuchtet/flackert.
Die Singale sind vom Optokoppler logischerweise prellfrei, daher vermute
ich das Problem im Code:
Die Zeile
TIFR |= ( 1 << ICF1 );
hat ein Problem: damit werden alle aktiven Interupt flags gelöscht
(Wenn das Time Register nicht mehr per SBI ansprechbar ist, was der Fall
sein sollte). Beisser zu löschen nur
TIFR = ( 1 << ICF1 );
Die Verknüpfung macht ja die Logic im Register.
Es fehlt noch die Behandlung des Sonderfalls wenn ICP und Overflow
Interrupt fast gleichzeitig auftreten: Da kann es passieren das der
Overflow Interrupt zu spät kommt. Das ist aber ein eher selten
auftretendes Problem, das aber zu sletenen Ausreißern bei den Messwerten
führt.
Die LED sollte eine Kopie des Eingangssignals sein. Die helligkeit ist
dabei nicht unbedingt von der Frequenz abhängig.
Hallo,
heute habe ich das ganze mal nicht auf dem Breadboard versucht und siehe
da, mit einer Lochrasterplatine habe ich dieses Flackern nicht mehr.
Aber ich MUSS den Noise Cancellor aktivieren. Ohne diesen flackert es
noch mächtig.
Werde nun demnächst noch das Hauptprogramm schreiben und testen, ob die
eingelesenen Frequenzen auch stimmen, indem ich einfach ab einer
Grenzfrequenz eine LED einschalte.
Ulrich schrieb:
> Die Zeile> TIFR |= ( 1 << ICF1 );> hat ein Problem: damit werden alle aktiven Interupt flags gelöscht> (Wenn das Time Register nicht mehr per SBI ansprechbar ist, was der Fall> sein sollte). Beisser zu löschen nur> TIFR = ( 1 << ICF1 );> Die Verknüpfung macht ja die Logic im Register.
Dies verstehe ich nicht ganz (meine C-Kenntnisse sind für
Mikrocontroller nicht nicht ganz optimal).
Kann mir jemand mal den Unterschied erklären?
Ulrich schrieb:
> Es fehlt noch die Behandlung des Sonderfalls wenn ICP und Overflow> Interrupt fast gleichzeitig auftreten: Da kann es passieren das der> Overflow Interrupt zu spät kommt. Das ist aber ein eher selten> auftretendes Problem, das aber zu sletenen Ausreißern bei den Messwerten> führt.
Wie kann ich an das Problem rangehen? Der Overflow löst doch direkt nach
Verlassen der Capture ISR dann trotzdem aus und ist so kurz, dass er
wohl nicht viel bremst. Die Anzahl der Overflows spielen dann ja später
nur bei der Berechnung der Frequenz eine Rolle oder habe ich einen
Denkfehler?
>Wie kann ich an das Problem rangehen? Der Overflow löst doch direkt nach>Verlassen der Capture ISR dann trotzdem aus und ist so kurz, dass er>wohl nicht viel bremst. Die Anzahl der Overflows spielen dann ja später>nur bei der Berechnung der Frequenz eine Rolle oder habe ich einen>Denkfehler?
Der Overflow IRQ hat beim AVR eine geringere Priorität als der
Capture IRQ. (PDF Seit 14 "Reset and Interrupt Handling")
Stell dir Folgende Situation vor:
cli();
Overflow IRQ wird ausgelöst
Capture IRQ wird ausgelöst
sei();
Overflow UND Capure IRQ stehen an.
Zuerst wird der Overflow IRQ bearbeitet.
Wenn der ebenfalls anstehenden Overflow IRQ
nicht beachtet wird kommt er ein falscher Messwert raus.
Auch der nächte Capure IRQ Misst dann Schrot,
da er einen Overflow zu viel drin hat.
Also im Capture IRQ prüfen ob Overflow ansteht UND
ob der eher zur aktuellen Messung gehört (Zäherstand klein)
oder schon zur nächsten Messung (Zählerstand groß).
Im 1. Fall den Overflow mit zählen und das IRQ Flag löschen.
Der Teil mit TIFR hat nichts mit C Kenntnissen, sondern einer
spezialität der REstister TIFR bein AVR zu tun:
Das Register TIFR ist kein normales Register. Um ein Bit zu löschen
schreibt man eine 1 in genau das Bit. Wenn eine Null reingeschrieben
wird, bleibt ein Flag erhalten.
Wenn man die oder verknüpfung macht, leißt die CPU erst TIFR aus, fügt
ggf. noch ein Bit hinzu und schreibt dann wieder zurück nach TIFR. Damit
werden alle gesetzten Flags gelöscht.
Tim schrieb:
> Overflow UND Capure IRQ stehen an.>> Zuerst wird der Overflow IRQ bearbeitet.>> Wenn der ebenfalls anstehenden Overflow IRQ>> nicht beachtet wird kommt er ein falscher Messwert raus.>> Auch der nächte Capure IRQ Misst dann Schrot,>> da er einen Overflow zu viel drin hat.
Du meinst ja sicherlich, dass zuerst der Capture IRQ bearbeitet wird.
Ok, ich verstehe den 1. Fall, dass wenn ein Overflow Interrupt währned
des Capture Interrupts eintritt, dass der Messwert falsch ist.
Aber wieso wirkt sich das auf das nächste Capture Interrupt auch aus
bzw. was meinst du damit, dass dann ein Overflow zuviel drin ist? Das
verstehe ich noch nicht. Die zu messenden Frequenzen sind ja so niedrig,
das zwischen zwei Capture Interrupts auf jedenfall der Overflow
abgearbeitet wird. Daher ist mir das noch nicht ganz klar.
Angenommen ich würde die Frequenzberechnung im Hauptprogramm durchführen
(und nicht in irgendeinem Interrupt), so wäre doch mein Overflow Zähler
immer aktuell ohne dass ich mich kümmern müsste.
Dein Lösungsvorschlag ist zwar mir klar, doch weiß ich nicht, welchen
Wert man als kleinen Zähler nimmt. Theoretisch müsste ich vor der
Frequenzberechnung (angenommen macht macht diese in der ISR) abfragen,
ob das Overflow Interrupt anliegt. Und dann müsste ich wissen, wieviel
Timerzyklen seit Beginn der Capture ISR bis zur Frequenzberechnung
vergangen sind (da wo die Anzahl der Overflows relevant ist), um einen
Grenzzählerstand abzufragen...
Es hilft nichts die Auswertung im Hauptprogramm zu machen. Ein Fehler
bei der Zeitmessung kann da ja nicht mehr korrigiert werden.
Das Problem ist das ein kurz vor dem ICP Interupt aufgetretender
Overflow, der nicht mehr vor der ICP ISR ausgeführt werden kann. Ursache
kann ein Befehl mit mehr Zyken (z.B. RET) oder ein CLI/SIE Block sein.
Erkennen kann man das am besten in der ICP-ISR, und das ist gar nicht so
schwer:
Ein noch ausstehender overfow (Flag in TIFR gesetzt) müßte eigentlich
vor den ICP Interrupt, wenn der Wert im ICP Register klein ist. Ein
kleiner Wert heißt ja, dass der ICP Interrupt kurz nach dem Overflow
ausgelöst wurde.
Wenn nicht gerade extrem lange CLI/SEI Blöcke vorkommen, ist bei
anstehenden Overflow Interrupt der Wert im ICP Register entweder sehr
sehr klein (High byte 0) oder sehr groß (High Byte 255). Wo man jetzt
genau die Grenze setzt ist relativ egal, anbieten würde sich 128 fürs
High Byte.
Ulrich schrieb:
> Es hilft nichts die Auswertung im Hauptprogramm zu machen. Ein Fehler>> bei der Zeitmessung kann da ja nicht mehr korrigiert werden
Das ist der Punkt, den ich vorhin schon nicht verstanden habe.
Angenommen dieser Fall tritt auf. IPC Interrupt erfolgt, obwohl OVF
Interrupt gesetzt. Nun wird mein TimerStart und TimerEnd Wert im ICP
eingelesen (dieser ist ja ok). Die ICP wird verlassen, das ausstehende
OVF Interrupt wird direkt ausgeführt und erhöht den OVF Zähler. Der OVF
Zähler ist nun wieder aktuell.
Und nun erst erfolgt doch die Auswertung im Hauptprogramm, beide Zähler
sind aktuell, oder etwa nicht?
Dein Lösungsvorschlag dürfte in Code also so aussehen?
Martin Neumann schrieb:
> Und nun erst erfolgt doch die Auswertung im Hauptprogramm, beide Zähler> sind aktuell, oder etwa nicht?
Damit handelst du dir aber schon wieder das nächste Problem ein.
Der Overflow kann auch während der Ausführung des ICP Interrupts kommen.
D.h er gehört eigentlich nicht mehr zu dieser Messung, sondern zur
nächsten.
Dein Hauptprogramm weiß das aber nicht und rechnet dann einen Overflow
zu viel ein.