Ich möchte gerne einen Zähler realisieren, der mit möglichst hoher
Frequenz läuft. Zum Beispiel mit der Taktfrequenz des µC. Ich möchte
nämlich bestimmte Ereignisse der "CPU-Zeit" zuordnen können.
Dazu braucht ich aber mindestens einen 32 bit breiten Zähler. Kann ich
das so machen, daß ich einen 16 bit Hardware Zähler des AVR laufen
lasse, und mit dem "Überlauf-Interrupt" einfach ein Word hochzähle?
Mal angenommen, das geht... wie löse ich die zwei Probleme:
1. Wenn ich den aktuellen Zählerwert beim Eintritt eines Ereignisses zur
späteren Verwendung "kopiere", kann ich das nur Byte für Byte machen.
Was ist aber, wenn sich während des Kopierens der Zähler ändert? Zum
Beispiel von 65535 auf 65536? Wenn mein Zähler mit der Taktfrequenz
läuft, wird er sich ja zwangsläufig während des Auslesens ändern.
2. Wie erreiche ich eine Lösung für Punkt 1, ohne daß der Zähler durch
diese Lösung einzelne Schritte überspringt. Das würde ja passieren, wenn
ich die Interrupts während des Auslesens des Zählers sperre.
Mach es einfacher. Setzte zum Begin deiner Messung ein IO-Ausgangspin
auf HIGH und am Ende auf Low. Mit einem Oszilloskop kann man wunderbar
die Zeit messen. Ausserdem kann man das auch recht gut und genau
simulieren, der Simulator zählt für dich die Takte.
MfG
Falk
Darf man fragen, was du machst, dass du Zeitpunkte mit einer derart
hohen Auflösung definieren musst?
Woher weißt du, wie lange es exakt (also auf den CPU-Takt genau) dauert,
bis dein Programm vom Auslösen des Ereignisses an gerechnet überhaupt
mitkriegt, dass etwas passiert ist?
Wie gut hast du deinen Quarz thermisch stabilisiert, so dass die exakte
Anzahl der Taktzyklen irgendeine Aussagekraft in Bezug auf die dadurch
verstrichene Zeit erlaubt. Oder verwendest du eine exaktere Zeitbasis
als einen Quarz?
(Worauf ich mit den letzten Fragen hinaus will: Selbst wenn du auf die
Quarzschwingung genau eine Zeitdauer abmesssen kannst, hilft dir das
Ergebniss nicht viel. Ein 16Mhz Quarz schwingt nicht exakt auf
16000000.000 Hz. Gut, das könnte man noch ausmessen. Aber er verändert
seine Frequenz auch mit der Umgebungstemperatur.)
> kann ich das nur Byte für Byte machen.> Was ist aber, wenn sich während des Kopierens der Zähler ändert?> Zum Beispiel von 65535 auf 65536? Wenn mein Zähler mit der> Taktfrequenz läuft, wird er sich ja zwangsläufig während des> Auslesens ändern
Ja klar.
Zu allererst: Deine Überlegung bezüglich des Überlaufs ist so schon
grundsätzlich korrekt.
Wenn es sich um ein externes Ereignis handelt, könnte man mit dem
Capture Input arbeiten, bei dem die Hardware den aktuellen Zählerstand
umkopiert.
Möchtest du aber dein Programm auf CPU-Takt Genauigkeit ausmessen,
läufst du in ein Problem, das zb. Physiker haben, wenn sie in immer
kleinere Dimensionen vorstossen: Irgendwann beeinflusst die Messung das
zu messende System. In deinem Fall: Du kriegst ja den Timer auch nicht
kostenlos. Das Setzen, Starten, Auslesen des Timers kostet auch
CPU-Takte. Takte, die normalerweise vernachlässigbar sind, bei den
Dimensionen die du dir aber vorstellst schon ins Gewicht fällt.
Dennoch sollte man sich zuallererst die Frage stellen: Wie genau ist
eigentlich "möglichst genau" und warum muss das so genau sein wie ich
mir das vorstelle. Wie wirkt sich meine Messungenauigkeit im Ergebnis,
das ich erhalten möchte, eigentlich aus?
Powermichi schrieb:
> Mal angenommen, das geht... wie löse ich die zwei Probleme:>> 1. Wenn ich den aktuellen Zählerwert beim Eintritt eines Ereignisses zur> späteren Verwendung "kopiere", kann ich das nur Byte für Byte machen.> Was ist aber, wenn sich während des Kopierens der Zähler ändert? Zum> Beispiel von 65535 auf 65536? Wenn mein Zähler mit der Taktfrequenz> läuft, wird er sich ja zwangsläufig während des Auslesens ändern.>> 2. Wie erreiche ich eine Lösung für Punkt 1, ohne daß der Zähler durch> diese Lösung einzelne Schritte überspringt. Das würde ja passieren, wenn> ich die Interrupts während des Auslesens des Zählers sperre.
Schön, daß Du die Probleme richtig erkannt hast.
Die Lösung:
Beitrag "AVR Timer mit 32 Bit"
Peter
Zur Anwendung:
Ich bekomme einen externen Interrupt von einem Timing-Generator, der zur
GPS-Sekunde synchronisiert ist. Leider nur einmal pro Sekunde. Meine
Anwendung macht Messungen und ich muß die Messungen einer definierten
Zeit zuordnen. Statt jetzt eine PLL zu bauen etc., wollte ich einfach
die CPU-Takte mitzählen, die seit dem Interrupt verstrichen sind. Die
Auflösung ist sicher höher als die Genauigkeit, also unnütz, aber es
erschien mir einfacher, so vorzugehen.
Mit dem Code von Peter komme ich schonmal weiter, danke. Auch, wenn ich
in Assembler schreibe (-n muß).
Wenn es um ein externes Signal geht, dann nimmt man wenn möglich die
Input-capture funktion. Damit kriegt man die unteren 16 Bits in Hardware
direkt mit der Flanke.
Wie gut die Ganuigkeit des GPS Signals ist hängt vom Empfänger ab, der
Sekundenpuls kann aber schon sehr genau sein. Über einen kurze Zeit ist
auch ein einfacher Quarz schon sehr stabil. Es ist damit gar nicht so
sinnlos bis auf einen Taktzyklus ganu zu messen.
Für eine Sekunde könnten auch 24 Bits schon reichen (bis 16 MHz Takt).
Input Capture geht nicht, da ich meinen Zählerstand zu internen
Vorgängen abspeichern will. Der externe Interrupt setzt lediglich den
Zähler zurück. Aber ich denke, mit den Tips komme ich ganz gut weiter.
Eine eigene Frage?
Dieser Thread ist über 17 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.