Forum: Compiler & IDEs Frequenz am ICP1 messen


von Erik B. (bibabulks)


Angehängte Dateien:

Lesenswert?

Hallo,

Sinn dieses Programms ist es eine Frequenzmessung über das Input Capture 
Pin durchzuführen...

Ich verwende für die Messaufgabe einen Atmega168 mit 20MHz Taktfrequenz.
Beim Test des Programmes mit einem Frequenz-Generator erhalte Ich bis
ca. 2kHz sehr gute Ergebnisse, d.h. dass die ausgegebene Frequenz auf
dem Display mit 1Hz Genauigkeit übereinstimmt.
Erhöht man die Frequenz bis 5kHz so muss man feststellen, dass Sie bis
zu 3Hz abweichen kann. Bei 10kHz ist die Auflösug schon so schlecht,
dass man sich mit einer Auflösung von 10 Hz bis 20 Hz abfinden muss.

Meine Frage: kann mir jemand weiterhelfen den Code zu verbessern, oder
einen Tip geben, um die Messgenauigkeit zu verbessern? Entweder bei 2kHz
Auflösung von 0,1Hz oder bei 20kHz Auflösung von 1Hz? Ist das überhaupt
möglich?

Hintergrund ist Ich möchte Frequenzen bis 150Mhz messen, die über Teiler
bis in den kHz-Bereich herunter geteilt werden sollen. Teilungsfaktor
bei 2kHz der Messfrequenz wäre dann nach Adam Ries 75 000 macht bei
einer Auflösung von 1Hz, wie es bisher ist 75 kHz Gesamtauflösung. Dies
möchte Ich gern verbessern.

Danke im vorraus

von Karl H. (kbuchegg)


Lesenswert?

floats vermeiden
Mit float hast du so um die 6 signifikante Ziffern. Bei dir könnten es 
auch nur 5 sein durch die Division.


Das hier
1
    while(1)              // Endlosschleife im Main
2
    {
3
      
4
      for( i=0; i<j; i++)      // Messschleife für j Messungen
5
      {
6
        summe += erg;      // Summieren der gemessenen T's          
7
      }
summiert nicht j einzelne Messungen auf, sondern ein und dieselbe 
Messung  j mal. Dein Mittelwert ist also alles andere als ein Mittelwert 
von j unabhängigen Messungen.


Diese Berechnung
     erg = (overflows*65536) + endtime - starttime;
ist nicht richtig.
Die Anzahl der Overflows muss anders eingerechnet werden.


Je höher deine Frequenz wird, desto kleiner wird das erg hier
  erg = (overflows*65536) + endtime - starttime;
werden.
Je kleiner das erg hier aber wird, desto größere Schritte macht die 
daraus errechnete Frequenz

Ab einer bestimmten Grenzfrequenz ist es daher nicht mehr sinnvoll, die 
Zeitdauer von einer Flanke zur nächsten zu messen, sondern das 
Messprinzip umzudrehen: Man zählt zb 1 Sekunde lang, wieviele Flanken im 
zu messenden Signal vorkommen.

von Oliver (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
>       for( i=0; i<j; i++)      // Messschleife für j Messungen
>       {
>         summe += erg;      // Summieren der gemessenen T's
>       }
> summiert nicht j einzelne Messungen auf, sondern ein und dieselbe
> Messung  j mal.

Aber nur, wenn nicht mittendrin die ISR ausgeführt wurde, und erg sich 
verändert. Da das irgendwo in der Berechnung passieren kann, können da 
auch unsinnige float-Werte entstehen.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Oliver schrieb:

> Aber nur, wenn nicht mittendrin die ISR ausgeführt wurde, und erg sich
> verändert. Da das irgendwo in der Berechnung passieren kann, können da
> auch unsinnige float-Werte entstehen.

Hab ich zuerst auch gedacht.
In seinem Fall allerdings nicht. Da ist noch eine Absicherung mit einem 
Flag drinnen, so dass die ISR erst dann wieder zu messen anfängt, wenn 
die Hauptschleife bestätigt, dass sie sich das Ergebnis geholt hat - das 
workFlag.


Alles in allem wieder mal:
Code geklaut ohne ihn analysiert oder verstanden zu haben. Dafür dann 
naiv ein paar Variablen auf float gewechselt und dann wundert man sich.

von Erik B. (bibabulks)


Lesenswert?

Vielen Dank für die schnellen Antworten

ja sorry ist mein erster Versuch mit µC zu Rande zukommen . . .

>summiert nicht j einzelne Messungen auf, sondern ein und dieselbe
>Messung  j mal. Dein Mittelwert ist also alles andere als ein Mittelwert
>von j unabhängigen Messungen.

Könnte man in der for schleife noch eine if-Verzweigung reinbasteln, die 
auf eine Abfrage des workflag's wartet, bis sie erg aufaddiert, und 
anderenfalls die Laufvariable -1 rechnet? Oder hab ich einen Denkfehler?

>Ab einer bestimmten Grenzfrequenz ist es daher nicht mehr sinnvoll, die
>Zeitdauer von einer Flanke zur nächsten zu messen, sondern das
>Messprinzip umzudrehen: Man zählt zb 1 Sekunde lang, wieviele Flanken im
>zu messenden Signal vorkommen.

D.h. Den Zähler zu einem definierten Zeitpunkt starten(Bei 
Flankenwechsel) d.h dieser zählt dann von 0 an hoch. Die Überläufe 
zählen. mit der ISR die Flanken zählen. Nach 1 Sekunde stoppen, Endzeit 
vom Zähler merken und dann die Berechnung ausführen. Bis zu welcher 
Frequenz kann man so messen??? Und mit welcher Auflösung?

Vielen Dank nochmal werds ausprobieren....

CU

von Oliver (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
>> Aber nur, wenn nicht mittendrin die ISR ausgeführt wurde, und erg sich
>> verändert. Da das irgendwo in der Berechnung passieren kann, können da
>> auch unsinnige float-Werte entstehen.
>
> Hab ich zuerst auch gedacht.
> In seinem Fall allerdings nicht.

Zumindest der erste oder gar die ersten paar Werte werden beim ersten 
Start des Programms 0 sein, bis die ISR den ersten berechneten Wert in 
erg geschrieben hat.

Danach greift dann die Synchronisation über das Flag.

Oliver

von Erik B. (bibabulks)


Angehängte Dateien:

Lesenswert?

Hallo,

Hab mir mal noch ein paar Gedanken gemacht . . .
Danke an Karl Heinz Buchegger, dein Tip hat mir weitergeholfen. Habe den 
Quelltext jetzt soweit verändert, dass Ich gut und gerne bis 300kHz 
messen kann :-) wie Karl schrieb, 1s lang messen und dabei Flanken 
zählen.

Hätte mal die Bitte, dass sich jemand mal den Code anschaut und mir sagt 
wo noch Verbesserungspotential ist??? Wäre cool !

PS: Es werden zwei Ausgaben auf dem Display realisiert, eine ohne und 
mit Korrektur... In einer möglichen späteren Umsetzung wird nur die mit 
korrektur verwendet.

Gruß Erik

von Karl H. (kbuchegg)


Lesenswert?

Wo kommt der Faktor 1.000000128 her?

von Erik B. (bibabulks)


Lesenswert?

Genauer Wert für die Berechnung von 20Mhz / 1024 wäre ja 19531,25 und 
wenn man das wiederum abzieht von 2^16 rundet er ja auf 46005. Somit hab 
Ich ja einen Fehler von 0.25 x 19531.25Hz oder nicht ? ? ?

Das sind 12,8µs also verkürzt sich das Messintervall um diese Zeit.
statt 1 s tatsächlich 0,9999872s ja hab dann noch 1/0.9999872 gerechnet.

Hoffe hab mir das richtig gedacht???

von Erik B. (bibabulks)


Lesenswert?

Oder einfacher: den Wert multiplizieren mit 0,9999872! Spart das 
rechenzeit?

von Karl H. (kbuchegg)


Lesenswert?

Erik Brachmann schrieb:
> Genauer Wert für die Berechnung von 20Mhz / 1024 wäre ja 19531,25 und
> wenn man das wiederum abzieht von 2^16 rundet er ja auf 46005. Somit hab
> Ich ja einen Fehler von 0.25 x 19531.25Hz oder nicht ? ? ?

Deine Berechnung klingt zumindest plausibel.
Mal sehen, ob wir auf einem anderen Weg zu gleichen Ergebnis kommen.

Du setzt Den Zähler so, dass 19531 Timertakte bis zum Überlauf 
entstehen.
Das sind 19531 * 1024 = 19999744 CPU Takte

Da 20000000 ziemlich genau 1 Sekunde entsprechen, sind daher 19999744 
Zyklen

    20000000      1
    19999744      x
  ---------------------
          1 * 19999744
    x = ------------------ = 0.9999872 Sekunden
           20000000

Sieht daher gut aus.

Ob das allerdings viel bringt, wage ich mal zu bezweifeln. Hauptsächlich 
daher, weil dein Quarz mit einiger Sicherheit keine 20000000 
Schwingungen in der Sekunde macht. Das können durchaus +/- 100 bis 150 
Schwingungen mehr oder weniger sein. Und damit bist du dann schon in der 
Nähe deiner Korrektur.

Aber ist ok.
Das einzige was ich tun würde: Den Zahlenwert nicht direkt in den Code 
rein, sondern als Formel ausdrücken in Abhängigkeit der CPU Frequenz und 
Verteiler.

Auch bin ich kein besonderer Freund des Vorladens im Interrupt. Will man 
einem Timer einen limitierten Zählbereich aufzwingen, dann gibt es dafür 
den CTC-Modus.

von Erik B. (bibabulks)


Lesenswert?

Bedanke mich für die sehr schnelle Antwort. Werd mir den CTC - Modus als 
nächstes vornehmen, danke für den Tip.

Mein Ziel ist es Frequenzen so hoch und genau wie öglich zu messen.
Bin jetzt bei 300kHz +-1Hz. Das ist eigentlich schon gut. Bei meiner 
Frequenz die Ich messen möchte liegt maximal bei 150MHz, müsste Ich da 
nur noch 500 runterteilen.

Wie Hoch kann Ich maximal messen. Ich denke da ist jetzt bald Schluss, 
wenn Ich noch andere Aufgaben mit dem Controller machen will, sonst 
bearbeitet er ja nur Interrupts!

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.