Forum: Mikrocontroller und Digitale Elektronik Wie 32-bit Zähler auf Atmel AVR?


von Powermichi (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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

von Powermichi (Gast)


Lesenswert?

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ß).

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Weiter unten hat Peter auch sein LST-File (Assembler) gepostet.

von Ulrich (Gast)


Lesenswert?

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).

von Powermichi (Gast)


Lesenswert?

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.

von Ulrich (Gast)


Lesenswert?

Man muß den Zähler zur Syncronisation nicht zurücksetzen. Es reicht wenn 
man sich den Zählerstand merkt und dann später abzieht.

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
Noch kein Account? Hier anmelden.