Moin,
vorweg ich habe die Suchfunktion verwendet aber nichts konkretes zu
meine Problem Gefunden.
Ich möchte ein Signal über den ICP-Pin erfassen, welches zwischen 13- 60
Hz variiert.
Ich habe versucht das mit dem Input Capturing zu verstehen, werde da
aber nicht so richtig schlau raus.
Wollte wie folgt vorgehen:
Timer 1, jede ms aufrufen, diesen also im Hintergrund laufen lassen.
Ich teile hierzu den CLk von 16Mhz auf 16/64Mhz.
Also 4us.
Nur wie bekomm ich den Timer jetzt auf 1ms?
Nun brauch ich aber einen Zweiten Interrupt den Output Compare, der den
Zählstand sichert, wenn eine Flanke auftritt an dem PIN oder?
Dieser wird dann aufgerufen, wenn eine Flanke an dem ICP-PIN erfolgt.
Das problem hierbei ist ich weiß nicht wie der ISR Interrupt Vector in C
heißt. Wo kann man das denn nachgucken, im Datenblatt steht dies ja so
direkt nicht drin.
Code sieht unvollständig bisher so aus:
Du hast die Logik hinter Input Capture nicht verstanden.
Du lässt Zähler1 laufen, wenn dann ein Signal am Input Capture Pin ICP1
eintrifft, sichert der Atmel den Zählerstand von TCNT1 nach ICR1, und
löst einen Capture Interrupt aus wenn der freigegeben ist.
Im Capture Interrupt zieht man den vorherigen Zählerstand, den man sich
in einer Variablen merkt, vom neuen Wert des ICR1 ab und erhält so die
Periodendauer in Anzahl der Zyklen des Zähler1. Das versuchst Du
bereits, nur gehört das eben in den TIMER1_CAPT_vect rein. Bei 13 - 60
Hz ergeben sich dann Werte ICR1_alt - ICR1 von 19230 - 4166
Man könnte auch in der Capture ISR den Zähler auf 0 setzen und erhält so
ohne Subtraktion im ICR1 direkt die Periodendauer. Allerdings entsteht
dann durch den während der Befehlsausführung weiterlaufenden Zähler ein
Fehler, der evtl. aber nicht stört.
Die weitere Auswertung der Frequenz würde man dagegen in der Mainloop
machen, durch ein Flag gesichert um ein Überschreiben des Wertes während
der Berechnung zu verhindern.
Und Output Compare hat etwas mit PWM zu tun, das ICR1 Register kann auch
dafür verwendet werden, aber das scheint mir nicht das zu sein was Du
willst. Außer Du möchtest aus der Periodendauer gleich wieder eine davon
abhängige PWM machen.
Die Namen aller Interruptvektoren stehen übrigens in iom8.h, die Du
sicherlich einbindest.
> Ich möchte ein Signal über den ICP-Pin erfassen, welches zwischen> 13- 60 Hz variiert.>> Ich habe versucht das mit dem Input Capturing zu verstehen, werde> da aber nicht so richtig schlau raus.
Das ist eigentlich ganz einfach. Wenn ein Input-Capture-Ereignis
eintritt, wird der aktuelle Zählerwert automatisch in einem Register
zwischengespeichert. Du kannst dir dann auch einen Interrupt generieren
lassen, mit dem du diesen Wert abholst.
Wollte wie folgt vorgehen:
> Timer 1, jede ms aufrufen, diesen also im Hintergrund laufen lassen.
Das hat dann aber nicht mehr viel mit Input Capture zu tun.
> Ich teile hierzu den CLk von 16Mhz auf 16/64Mhz.> Also 4us.> Nur wie bekomm ich den Timer jetzt auf 1ms?
Du schaltest ihn in den CTC-Modus und schreibst ins dafür verwendete
Output-Compare-Register einen Wert von 250. Dann bekommt der Timer alle
Millisekunde einen Reset, und der Output-Compare-Interrupt wird dabei
ausgelöst.
> Nun brauch ich aber einen Zweiten Interrupt den Output Compare,> der den Zählstand sichert, wenn eine Flanke auftritt an dem PIN> oder? Dieser wird dann aufgerufen, wenn eine Flanke an dem ICP-PIN> erfolgt.
Der Output Compare hat nichts mit einer Flanke am Pin zu tun. Der wird
aufgerufen, wenn der Zähler einen bestimmten Zählwert erreicht.
> Das problem hierbei ist ich weiß nicht wie der ISR Interrupt Vector in> C heißt. Wo kann man das denn nachgucken, im Datenblatt steht> dies ja so direkt nicht drin.
Das steht in der Doku von der avr-libc.
Deine Vorstellung von Input-Capture paßt aber noch nicht ganz.
Prinzipiell kannst du deinen Timer einfach durchrennen lassen. In der
Input-Capture-ISR liest du das ICR1-Register aus und sicherst es in
einer Variablen. Wenn du die Differenz der Zähler-Werte zweier
aufeinanderfolgener Flanken nimmst, kannst du daraus die Frequenz des
Signals ermitteln. Wichtig ist dabei nur, daß zwischen zwei
Input-Capture-Ereignissen nicht mehr als ein Zählerüberlauf vorkommen
kann.
> Ich hoffe ich hab nicht zu dumme Fragen gestellt :(
Nein. Dumme Fragen stellen eigentlich fast ausschließlich diejenigen,
die glauben, ihre Fragen seien höchst intelligent.
> Man könnte auch in der Capture ISR den Zähler auf 0 setzen und> erhält so ohne Subtraktion im ICR1 direkt die Periodendauer.> Allerdings entsteht dann durch den während der Befehlsausführung> weiterlaufenden Zähler ein Fehler, der evtl. aber nicht stört.
Wobei eigentlich der wirkliche Vorteil von Input Capture ist, daß man
eben gerade diesen Fehler nicht bekommt. Sonst könnte man auch einen
normalen Interrupt-Eingang nehmen und den aktuellen Zählerwert in der
ISR auslesen.
> Sonst könnte man auch einen normalen Interrupt-Eingang nehmen und den> aktuellen Zählerwert in der ISR auslesen.
Stimmt, könnte man, aber ich hab doch geschrieben daß bei dieser Lösung
ein Fehler entsteht, was ist da jetzt nicht zu verstehen ?
Der Frequenzbereich umfasst 13-60 Hz, der entstehende Fehler ist
verschwindend gering, rechnerisch ca. 0.004Hz.
Wenn man Einsprung in die ISR, das Pushen der Register und Setzen des
Zählers mit 15 Zyklen annimmt, dann hat der Zähler bei Prescaler 64 in
dieser Zeit noch nicht einmal weitergezählt, der Fehler ist also
außerhalb der möglichen Zählerauflösung.
Bei dieser Lösung kann man auch noch eine Timer1 Overflow ISR aufsetzen,
in der man ein Flag löscht, welches man vor Verlassen der Input Compare
ISR gesetzt hat. Ist diese Flag beim erneuten Aufruf der Input Compare
ISR immer noch gesetzt, dann ist der Zähler nicht übergelaufen und man
hat eine gültige Messung.
Das macht den Code einfacher, warum sollte man das nicht nutzen, bzw.
erwähnen ?
>> Sonst könnte man auch einen normalen Interrupt-Eingang nehmen>> und den aktuellen Zählerwert in der ISR auslesen.>> Stimmt, könnte man, aber ich hab doch geschrieben daß bei dieser> Lösung ein Fehler entsteht, was ist da jetzt nicht zu verstehen ?
Nein, deine Lösung war ein Reset des Timers in der Input-Capture-ISR.
Ich wollte einfach nur darauf hinweisen, daß das den einzigen wirklichen
Vorteil von Input Capture gegenüber normalen Interrupt- oder
PCINT-Eingängen zunichte macht. Daß das bei den niedrigen Frequenzen, um
die es hier geht, keine Rolle spielt, ist natürlich richig.
Allerdings bekomme ich immer noch nicht die korrekte Frequenz raus, nur
Frage ich mich wo der fehler liegt.
Ist es nicht so, das die ISR-Routine ausgelößt wird, wenn eine steigende
Flanke ausgelößt wird?
Wenn ich nun Flanken voneinander abziehe müsste ich doch die Freqzenz
berechnen könnnen oder?
Und was wäre in meine Fall ein vernünftiger Prescaler und wie verhinder
ich Fehler, die bei einem Überlauf entstehen?
Gibt es eine andere Möglichkeit als die globalen Interrupts
auszuschalten, um schreibgeschützt, die Variabel zur berechnung zu
benutzen?
Die Timereinstellung hab ich nicht kontrolliert.
Auch der Datentyp von frequenz wäre interessant. Denn eines ist klar:
frequenz kann maximal 65536 gross werden. Mehr geht durch den 16-Bit
Timer und der jetzigen Programmierung nicht. Daher ist 1000000/frequenz
mit Sicherheit immer 0 (selbst wenn ich berücksichtige, dass du
zwischendurch noch mal 4 rechnest)
Sandro W. schrieb:
> Und was wäre in meine Fall ein vernünftiger Prescaler
Ein vernünftiger Prescaler ist dann gegeben, wenn sich deine zu
messenden Frequenzen im Zahlenbereich 0 bis 65536 gut abbilden.
Dazu kommt dann noch die Fragestellung: Wie genau will ich mein Ergebnis
eigentlich messen?
> und wie verhinder> ich Fehler, die bei einem Überlauf entstehen?
Indem du Überläufe feststellst und mit einrechnest?
> Gibt es eine andere Möglichkeit als die globalen Interrupts> auszuschalten, um schreibgeschützt, die Variabel zur berechnung zu> benutzen?
Nein.
Ist aber kein großes Thema. Die Variablen werden schnell gelesen und die
Subtraktion dauert auch nicht lange. Läuft in der Zwischenzeit in
Interrupt an, so wird er ein klein wenig verzögert. Der gecapturte Wert
ist trotzdem richtig, lediglich die Bearbeitung verzögert sich ein klein
wenig.
Karl heinz Buchegger schrieb:
> Sandro W. schrieb:>>> Und was wäre in meine Fall ein vernünftiger Prescaler>> Ein vernünftiger Prescaler ist dann gegeben, wenn sich deine zu> messenden Frequenzen im Zahlenbereich 0 bis 65536 gut abbilden.> Dazu kommt dann noch die Fragestellung: Wie genau will ich mein Ergebnis> eigentlich messen?
Und die Vorgehensweise ist genau andersrum.
Nimm deine langsamste Frequenz und rechne dir aus bis zu welchem Wert
ein 16-Bit Timer bei allen möglichen Vorteilern von einer Signalflanke
bis zur nächsten kommen wird.
Hast du das mit allen Vorteilern ausprobiert, siehst du nach, welcher
geeignet ist, so dass du ohne Berücksichtigung der Überläufe arbeiten
kannst. Geht sich das mit keinem Vorteiler aus, dann musst du auf
Überläufe gehen.
Geht es sich aber aus, dann rechnest du mit diesem Vorteiler und einem
Zählerwert + 1 wieder zurück auf die Frequenz und kriegst so raus, mit
welcher Genauigkeit du deine Frequenz messen kannst. Selbes Spiel am
anderen Ende der Skala.
Dann entscheidest du, ob dir das reicht, oder ob du mehr Aufwand treiben
willst (musst).
Ja, auch in der Programmierung muss man im Vorfeld mal etwas
Papierarbeit leisten.
Karl heinz Buchegger schrieb:
> Karl heinz Buchegger schrieb:>> Sandro W. schrieb:>>>>> Und was wäre in meine Fall ein vernünftiger Prescaler>>>> Ein vernünftiger Prescaler ist dann gegeben, wenn sich deine zu>> messenden Frequenzen im Zahlenbereich 0 bis 65536 gut abbilden.>> Dazu kommt dann noch die Fragestellung: Wie genau will ich mein Ergebnis>> eigentlich messen?>> Und die Vorgehensweise ist genau andersrum.> Nimm deine langsamste Frequenz und rechne dir aus bis zu welchem Wert> ein 16-Bit Timer bei allen möglichen Vorteilern von einer Signalflanke> bis zur nächsten kommen wird.> Hast du das mit allen Vorteilern ausprobiert, siehst du nach, welcher> geeignet ist, so dass du ohne Berücksichtigung der Überläufe arbeiten> kannst. Geht sich das mit keinem Vorteiler aus, dann musst du auf> Überläufe gehen.> Geht es sich aber aus, dann rechnest du mit diesem Vorteiler und einem> Zählerwert + 1 wieder zurück auf die Frequenz und kriegst so raus, mit> welcher Genauigkeit du deine Frequenz messen kannst. Selbes Spiel am> anderen Ende der Skala.> Dann entscheidest du, ob dir das reicht, oder ob du mehr Aufwand treiben> willst (musst).>> Ja, auch in der Programmierung muss man im Vorfeld mal etwas> Papierarbeit leisten.
Ok habe ich gemacht:
Habe noch eine Änderung die Frequenz geht bis 1,3Hz, eine Kommastelle
reicht mir von der Genauigkeit her dicke.
bei 1,3Hz
16Mhz/1024 -> 12019
16Mhz/256 -> 48077
16Mhz/64 -> 192308
Also beo 1024 und 256 erfolgt kein Überlauf.
Was mir noch nicht ganz klar ist:
Wenn der Timer 2 Flanken erfasst hat, zählt er dann weiter oder resetet
er seinen Zähler auf 0?
Wenn er weiterzählt muss ja früher oder später mal ein Überlauf
auftrteen, der zu einem Fehler führt oder nicht?
Die Variabel frequenz in dem Quellcode oben ist von uint32_t und daher
den Wert 1.000.000 aufnehmen oder nicht?
Sandro W. schrieb:
> Was mir noch nicht ganz klar ist:> Wenn der Timer 2 Flanken erfasst hat, zählt er dann weiter oder resetet> er seinen Zähler auf 0?
Zählt weiter.
> Wenn er weiterzählt muss ja früher oder später mal ein Überlauf> auftrteen, der zu einem Fehler führt oder nicht?
Überlauf kommt zwar, aber solange es nur einer ist, ist das kein
Problem. Durch die unsigned Arithmetik brauchst du das nicht
berücksichtigen. Durch die Subtraktion kommt immer die Anzahl der
Timerticks raus. Wie gesagt: Nur dann, wenn du nur 1 Überlauf hast.
Daher auch die Überlegung, den Vorteiler so einzurichten, dass sich
alles im Bereich 0 bis 65535 abspielt.
> Die Variabel frequenz in dem Quellcode oben ist von uint32_t und daher> den Wert 1.000.000 aufnehmen oder nicht?
Schon.
Aber aus deinem Timer kannst du (so wie es jetzt ist, also ohne
Berücksichtigung von mehreren Überläufen) keinen Wert erhalten, der
größer als 65536 ist. Das folgt daraus, dass es ein 16 Bit Timer ist.
Ok Vielen dank!
Soweit habe ich die Frequenzmessung jetzt zum laufen bekommen.
Ein entscheidende Problem, was ich mit dem Frequenzgenerator nicht
bedacht habe, ist, das ich unter realen Bedingungen durchaus mal eine
Frequenz von 0hz haben kann.
Das Problem ist wie detektiere ich das?
Das Input Capture das nicht erfassen kann ist klar, da kommen ja keine
Flanken mehr.
Meine erste war eventuell ein zweiter Timer der den Ausgang über längere
Zeit beobachtet und dann die Frequenz automatisch 0 setzt, wenn über
einen Zeitraum keine Frequenz vorhanden ist.
Ich frage mich ob das auch eleganter geht?
Code sieht jetzt so aus
Sandro W. schrieb:
> Ok Vielen dank!> Soweit habe ich die Frequenzmessung jetzt zum laufen bekommen.>> Ein entscheidende Problem, was ich mit dem Frequenzgenerator nicht> bedacht habe, ist, das ich unter realen Bedingungen durchaus mal eine> Frequenz von 0hz haben kann.> Das Problem ist wie detektiere ich das?>> Das Input Capture das nicht erfassen kann ist klar, da kommen ja keine> Flanken mehr.
Das nicht.
Aber der Timer zählt weiter.
Wenn 2 Timeroverflows hintereinander kommen, ohne dass dazwischen eine
Flanke lag (= der Input Capture angesprochen hat), dann ist das Signal
zu langsam.
Karl heinz Buchegger schrieb:
> Sandro W. schrieb:>> Ok Vielen dank!>> Soweit habe ich die Frequenzmessung jetzt zum laufen bekommen.>>>> Ein entscheidende Problem, was ich mit dem Frequenzgenerator nicht>> bedacht habe, ist, das ich unter realen Bedingungen durchaus mal eine>> Frequenz von 0hz haben kann.>> Das Problem ist wie detektiere ich das?>>>> Das Input Capture das nicht erfassen kann ist klar, da kommen ja keine>> Flanken mehr.>> Das nicht.> Aber der Timer zählt weiter.> Wenn 2 Timeroverflows hintereinander kommen, ohne dass dazwischen eine> Flanke lag (= der Input Capture angesprochen hat), dann ist das Signal> zu langsam.
Also müsste ich nur feststellen, wenn ein 2ter Overflow stattgefunden
hat.
Kann man das irgendwie abfragen ?
Sandro W. schrieb:
> Also müsste ich nur feststellen, wenn ein 2ter Overflow stattgefunden> hat.> Kann man das irgendwie abfragen ?
Du hängst den Overflow Interrupt auf eine ISR, dort zählst du eine
Zählvariable hoch, wenn sie nicht schon größer als 2 ist (damit
Overflows dieser Variablen vermieden werden). In der Capture ISR wird
die Variable auf 0 gesetzt. Ist die Variable bei der Auswertung größer
als 2, dann gab es offensichtlich mehere Overflows hintereinander, ohne
dass eine Flanke reinkam. Deine Entscheidung, was du dann machen willst.
Also irgendwie bin ich zu blöd, ermüsste theoretisch in der ISR-
Overflow Routine auf 3 Hochzählen und damit größer 2 sein und damit in
den else Zweig gelangen aber, tut dies nicht.
Aber ich frag mich warum, iegenltich müsste die ISR doch ausgeführt
werden.
> SREG |= 0x80; // SREG : Globales "Interrupt enable"*/
Nein. Mach das nicht. Um die Overflows global freizuschalten, benutzt du
sei();
Für dich als C-Programmierer, heißt es: Hände weg vom SREG.
>>> ersetzt, nun müsste eigentlich der Overflow aktiviert sein oder?
Probiers aus.
Schalt im Overflow Interrupt eine LED ein (das Hello World des kleinen
Mannes) und sieh nach ob sie eingeschaltet wird, wenn der Messeingang
auf Masse geschaltet wird.
Brennt sie -> ISR wird aufgerufen
Brennt sie nicht -> ISR wird nicht aufgerufen
So einfach ist das. Hilf dir selbst, dann hilft dir Gott :-)
Karl heinz Buchegger schrieb:
> Sandro W. schrieb:>> Wenn er weiterzählt muss ja früher oder später mal ein Überlauf>> auftrteen, der zu einem Fehler führt oder nicht?>> Überlauf kommt zwar, aber solange es nur einer ist, ist das kein> Problem. Durch die unsigned Arithmetik brauchst du das nicht> berücksichtigen. Durch die Subtraktion kommt immer die Anzahl der> Timerticks raus. Wie gesagt: Nur dann, wenn du nur 1 Überlauf hast.> Daher auch die Überlegung, den Vorteiler so einzurichten, dass sich> alles im Bereich 0 bis 65535 abspielt.>
Das wollte ich nochmal aufgreifen.
Was genau ist damit gemeint. Wie genau findet den die Subtraktion statt,
wenn ein Überlauf stattgefunden hat, damit noch das korrekte Ergebnis
raus kommt?
Sandro W. schrieb:
> Das wollte ich nochmal aufgreifen.> Was genau ist damit gemeint. Wie genau findet den die Subtraktion statt,> wenn ein Überlauf stattgefunden hat, damit noch das korrekte Ergebnis> raus kommt?
Wenn man bei unsigned Arithmetik einen Über oder Unterlauf einfach
ignoriert, entspricht das dem Arbeiten auf einer Zahlen'gerade' die zu
einem Ring gebogen wird. Die Arithmetik findet automatisch 'modulo zu 2
hoch Bitzahl' statt, ohne dass man irgendetwas dazu tun muss.
Das ist so wie bei einer Uhr: 56 Sekunden PLUS 5 Sekunden ergibt 1
Sekunde (und eine Minute, aber der Überlauf wird ja ignoriert)
Gleichzeitig ergibt aber auch 1 Sekunde MINUS 5 Sekunden das Ergebnis 56
Sekunden (und einen Unterlauf von 1 Minute, aber der wird ja ignoriert)