Forum: Mikrocontroller und Digitale Elektronik Arduino - Frequenzzähler nach Nick Gammon - 2 Fragen


von derTed (Gast)


Lesenswert?

Hallo,

ich habe hier: https://www.gammon.com.au/timers ein Codebeispiel für 
einen Frequenzzähler gefunden (erster Code-Block unter "Frequency 
Counter sketch for Atmega328"). Diesen Code möchte ich nun für einen 8 
MHz (intern) Atmega 328P adaptieren.

Frage 1:

Wenn ich den Code richtig verstehe, dann müssen nur die Werte von 124 
auf 7999 für OCR2A sowie TCCR2B von bit (CS20) | bit (CS22); auf bit 
(CS20); abgeändert werden, so dass der Prescaler deaktiviert ist.

Wenn ich den Code dann aber mit einer festen Frequenz (aus dem 
Frequenzgenerator) teste, wächst der im seriellen Monitor angezeigte 
Wert kontinuierlich an bis irgendwann ein Overflow erreicht wird und er 
von vorne hochzählt. Lasse ich den Code unverändert, dann wird eine 
konstante Frequenz angezeigt, die halt falsch ist, da ich keine 16 MHz 
verwende.

Kann mir jemand sagen, was ich übersehen haben könnte?

Frage 2:


Im Code von Nick Gammon kommt folgende Passage vor:

1
  // if just missed an overflow
2
  if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256)
3
    overflowCopy++;


Kann mir jemand erklären, was genau hier gemacht wird und warum? 
Besonders was es mit dem Wert 256 auf sich hat?


Vielen Dank!

Ted

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Lass doch den ganzen Code unverändert, du musst ja nur die Ausgabe 
entsprechend umrechnen. Da der Timer nun mit 500Hz läuft, werden doppelt 
so viele Pulse gezählt, also lediglich die Ausgabe auf
1
float frq = (timerCounts *  2000.0) / timerPeriod;
ändern.

von derTed (Gast)


Lesenswert?

Ja, das wäre auch eine Möglichkeit, aber ich würde den Code schon gerne 
verstehen :)

von m.n. (Gast)


Lesenswert?

derTed schrieb:
> Wenn ich den Code richtig verstehe, dann müssen nur die Werte von 124
> auf 7999 für OCR2A

Einen 16 Bit Wert in ein 8 Bit Register zu schreiben, ist keine 
sinnvolle Lösung. Lass den Timer2 einfach 2 ms Intervalle erzeugen und 
skaliere wie folgt:
timerPeriod = ms/2;

Mit dem internen Takt vom 328 wirst Du nur sehr grobe Schätzwerte 
erhalten.
Für tiefe Frequenzen ist der beschriebene Zähler mit fester Torzeit 
unbrauchbar. Ich gebe Dir ein Programmbeispiel und eine Anpassung für 
eine genauere Referenzfrequenz für einen Arduino UNO: 
http://www.mino-elektronik.de/fmeter/fm_software.htm#bsp7

von derTed (Gast)


Lesenswert?

Hi,

oh, ich habe tatsächlich total übersehen, dass es sich um ein 8 Bit 
Register handelt, vielen Dank für den Hinweis.

Ich werde mir auch mal dein Codebeispiel angucken.

Kann mir trotzdem noch jemand Frage 2 beantworten, nur für mein 
Verständnis?

Danke!

von m.n. (Gast)


Lesenswert?

Wenn man mit einen Hardware-Timer (hier T1) Ereignisse zählt und diese 
zu einem bestimmten Zeitpunkt auslesen möchte, muß man die Überläufe 
korrekt auswerten. Probleme kann es geben, wenn der Lesezugriff 
gleichzeitig mit einem Überlauf oder während gesperrter Interrupts 
auftritt.

ISR (TIMER1_OVF_vect)
  {
  ++overflowCount;               // count number of Counter1 overflows
  }  // end of TIMER1_OVF_vect

wird dann zu spät ausgeführt, sodaß overflowCount noch nicht 
aktualisiert wurde. Das Ergebnis ist daher um 65536 (0x10000) zu 
niedrig.
Ist TOV1 gesetzt und der gelesene Wert von T1 noch klein, gibt es noch 
einen nicht bewerteten Überlauf, der beim Auslesen berücksichtigt werden 
muß.
Die andere Möglichkeit wäre, daß T1 0xffff liefert und TOV1 gesetzt ist. 
Hier muß der Überlauf nach dem Auslesen aufgetreten sein oder man hat 
mehr als 4,096 ms bei der Auswertung "vertüddelt".

Die Grenze 256 (16 µs @ 16 MHz) ist mir zu knapp bemessen, weshalb ich 
lieber 0x8000 verwende und damit der Auswertung eine deutlich längere 
Zeit gebe.

von Peter D. (peda)


Lesenswert?

m.n. schrieb:
> weshalb ich
> lieber 0x8000 verwende

Ergibt auch kürzeren Code, es muß nur ein Bit getestet werden.

von derTed (Gast)


Lesenswert?

Hi,

ist leider etwas länger her (hatte keine Zeit mich mit dem Thema weiter 
zu beschäftigen und den Thread dann vergessen, sorry :( )

m.n. schrieb:
> Die andere Möglichkeit wäre, daß T1 0xffff liefert und TOV1 gesetzt ist.
> Hier muß der Überlauf nach dem Auslesen aufgetreten sein [...].

Dazu noch drei Verständnisfragen:

1. Ich verstehe den Teil "Überlauf muss nach dem Auslesen aufgetreten 
sein" nicht so ganz. Kannst du das vielleicht nochmal etwas 
ausführlicher erklären?

2. Warum brauche ich eigentlich die zusätzliche Prüfung auf einen Wert 
(hier 256 oder die vorgeschlagenen 0x8000) überhaupt? Wenn TOV1 gesetzt 
ist, dann muss T1 doch nur kleiner 0xffff sein. Der Wert (256) begrenzt 
ja nur die messbaren Frequenzen zusätzlich. Und sollte tatsächlich TOV1 
gesetzt sein und T1 > 0xffff, dann ist die Frequenz, die ich messen 
will, für den µC sowieso zu schnell. Damit müsste ich doch nur TOV1 
prüfen, oder?

3. Angenommen Counter #1 läuft über und die zugehörige ISR_1 soll 
aufgerufen werden. Geht aber gerade nicht, da bereits eine andere (z.B. 
ISR_2) läuft. Da der Überlauf ja TOV1 gesetzt hat, kann ISR_1 
abgearbeitet werden, sobald die zurzeit laufende ISR_2 abgeschlossen 
ist. Wenn ISR_2 jetzt aus irgendeinem Grund/Fehler sehr lange läuft 
(und/oder Counter #1 zu schnell hochzählt) und während TOV1 gesetzt ist, 
läuft Counter #1 ein weiteres Mal über. Verstehe ich es richtig, dass 
dieser zweite Überlauf dann "verpufft", da er nirgends 
zwischengespeichert werden kann (TOV1 ist ja noch vom ersten Überlauf 
gesetzt)?


m.n. schrieb:
> Für tiefe Frequenzen ist der beschriebene Zähler mit fester Torzeit
> unbrauchbar.

Weshalb?

Nochmal vielen Dank!

Ted

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

>8 MHz (intern)
Die Präzision des eingebauten RC-Oszillators ist für einen 
Frequenzzähler nicht berauschend. Im verlinkten Quelltext ist die Rede 
von 16 MHz, das ist der Arduino Quarzoszillator.

von derTed (Gast)


Lesenswert?

Achso, hatte ich vergessen: Ich nutze nun einen externen 8 Mhz Quarz.

von c-hater (Gast)


Lesenswert?

derTed schrieb:

> Diesen Code möchte ich nun für einen 8
> MHz (intern) Atmega 328P adaptieren.

Wozu soll das gut sein? Der interne Takt ist dermaßen ungenau, dass es 
völliger Schwachsinn ist, damit irgendwas "messen" zu wollen.

von derTed (Gast)


Lesenswert?

Siehe Post eins über dir...

von m.n. (Gast)


Lesenswert?

derTed schrieb:
> Und sollte tatsächlich TOV1
> gesetzt sein und T1 > 0xffff,

Beachte bitte, daß T1 niemals > 0xffff sein kann. Und dann denke noch 
einmal neu nach.
Nach der langen Zeit habe ich keine Lust, alles wieder neu zu lesen.

Oder mache es so, wie Du meinst. Dann merkst Du selbst, daß der Überlauf 
einer speziellen Betrachtung bedarf.

von chris_ (Gast)


Lesenswert?

Hier gäb's noch einen Frequenzzähler:
Beitrag "Frequenzzähler Uno"

von derTed (Gast)


Lesenswert?

m.n. schrieb:
> derTed schrieb:
>> Und sollte tatsächlich TOV1
>> gesetzt sein und T1 > 0xffff,
>
> Beachte bitte, daß T1 niemals > 0xffff sein kann. Und dann denke noch
> einmal neu nach.
> Nach der langen Zeit habe ich keine Lust, alles wieder neu zu lesen.
>
> Oder mache es so, wie Du meinst. Dann merkst Du selbst, daß der Überlauf
> einer speziellen Betrachtung bedarf.

Gut, dann T1 = 0xffff. Darum ging es mir gar nicht. Ich hatte nicht 
verstanden, was du mit der von mir, oben zitierten Aussage meintest. Ich 
glaube, dass ich mittlerweile drauf gekommen bin.

Mir ist schon klar, dass die Überläufe einer speziellen Betrachtung 
bedürfen... darf ich denn nicht nachfragen, wenn ich etwas nicht 
komplett verstehe? Was soll denn die "Mach wie ich sage oder lass mich 
in Ruhe"-Mentalität?

So viel Text hat der Thread jetzt auch wieder nicht...

chris_ schrieb:
> Hier gäb's noch einen Frequenzzähler:
> Beitrag "Frequenzzähler Uno"

Danke, gucke ich mir an!

von m.n. (Gast)


Lesenswert?

derTed schrieb:
> So viel Text hat der Thread jetzt auch wieder nicht...

Aber Du hattest einen anderen Code verlinkt, auf den sich Deine Frage 
bezog. Den müßte man auch wieder ansehen ...

> Ich glaube, dass ich mittlerweile drauf gekommen bin.

Dann ist doch gut.

von Rainer V. (a_zip)


Lesenswert?

derTed schrieb:
> darf ich denn nicht nachfragen, wenn ich etwas nicht
> komplett verstehe?

Doch, darfst du! Jedoch erwarte ich dann eine genaue Beschreibung, bis 
wohin du was verstehst und dann was du nun nicht mehr verstehst. Das ist 
deine Arbeit an der Problemlösung und du wirst merken, dass der Zwang, 
dein Verständnis und dein Unverständnis genau zu beschreiben, dich sehr 
oft schon auf die Lösung stößt!
Als ich vor etlichen Jahren den Sprung von Windoof zu Linux gemacht 
habe, habe ich auch Python gelernt. Und nach ausgiebigem 
(Anfänger)Fragen im Python-Forum bin ich genau auf diesen Trichter 
gekommen. Ich kann es jedem nur empfehlen, so mit seinen 
Verständnisfragen umzugehen. Ist schon erstaunlich, was sich da an 
Unverständnis einfach in Luft auflösen kann :-)
Gruß Rainer

von m.n. (Gast)


Lesenswert?

Rainer V. schrieb:
> derTed schrieb:
>> darf ich denn nicht nachfragen, wenn ich etwas nicht
>> komplett verstehe?
>
> Doch, darfst du! Jedoch erwarte ich dann eine genaue Beschreibung, bis
> wohin du was verstehst und dann was du nun nicht mehr verstehst. Das ist
> deine Arbeit an der Problemlösung und du wirst merken, dass der Zwang,
> dein Verständnis und dein Unverständnis genau zu beschreiben, dich sehr
> oft schon auf die Lösung stößt!

Hinzu kommt, daß dieses Problem immer und immer wieder angesprochen 
wird. Da fehlt dann der Nerv, das jedesmal wieder ausführlich zu 
erklären.

von derTed (Gast)


Lesenswert?

Rainer V. schrieb:
> Jedoch erwarte ich dann eine genaue Beschreibung, bis
> wohin du was verstehst und dann was du nun nicht mehr verstehst.

Naja, ich bin eigentlich der Meinung, dass ich das gemacht habe. Frage 
#1 ist ja nur die Bitte, etwas neu zu formulieren.

m.n. schrieb:
> Hinzu kommt, daß dieses Problem immer und immer wieder angesprochen
> wird.

Gut, ist bei Foren nun mal so...

Würdet ihr mir bitte noch die folgenden Fragen beantworten?

derTed schrieb:
> m.n. schrieb:
>> Für tiefe Frequenzen ist der beschriebene Zähler mit fester Torzeit
>> unbrauchbar.
>
> Weshalb?

derTed schrieb:
> 3. Angenommen Counter #1 läuft über und die zugehörige ISR_1 soll
> aufgerufen werden. Geht aber gerade nicht, da bereits eine andere (z.B.
> ISR_2) läuft. Da der Überlauf ja TOV1 gesetzt hat, kann ISR_1
> abgearbeitet werden, sobald die zurzeit laufende ISR_2 abgeschlossen
> ist. Wenn ISR_2 jetzt aus irgendeinem Grund/Fehler sehr lange läuft
> (und/oder Counter #1 zu schnell hochzählt) und während TOV1 gesetzt ist,
> läuft Counter #1 ein weiteres Mal über. Verstehe ich es richtig, dass
> dieser zweite Überlauf dann "verpufft", da er nirgends
> zwischengespeichert werden kann (TOV1 ist ja noch vom ersten Überlauf
> gesetzt)?




Bezüglich den Werten 256 oder 0x8000 (Frage zwei von oben):
Eigentlich muss ich ja vom "Ende" der maximalen Counterzahl (65535) so 
"weit" weg bleiben, dass in der Zeit, die die CPU vom Zwischenspeichern 
des aktuellen Zählerwerts bis zum Prüfen, ob TOV1 gesetzt ist, die 
maximale Frequenz (die gezählt/gemessen werden soll) keinen Überlauf 
erzeugen kann, oder?

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.