mikrocontroller.net

Forum: Compiler & IDEs Frequenz am ICP1 messen


Autor: Erik B. (bibabulks)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
    while(1)              // Endlosschleife im Main
    {
      
      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. 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.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Erik B. (bibabulks)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Erik B. (bibabulks)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo kommt der Faktor 1.000000128 her?

Autor: Erik B. (bibabulks)
Datum:

Bewertung
0 lesenswert
nicht 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???

Autor: Erik B. (bibabulks)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Erik B. (bibabulks)
Datum:

Bewertung
0 lesenswert
nicht 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!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.