Inhaltsverzeichnis:

Hochauflösender Frequenzzähler - Gunook
Hochauflösender Frequenzzähler - Gunook

Video: Hochauflösender Frequenzzähler - Gunook

Video: Hochauflösender Frequenzzähler - Gunook
Video: Frequenzzähler - Zeigt die Frequenz von Funksendern in der Nähe an 2024, Dezember
Anonim

Dieses anweisbare zeigt einen reziproken Frequenzzähler, der Frequenzen schnell und mit angemessener Präzision messen kann. Es besteht aus Standardkomponenten und kann an einem Wochenende hergestellt werden (ich habe etwas länger gebraucht:-))

EDIT: Der Code ist jetzt auf GitLab verfügbar:

gitlab.com/WilkoL/hochauflösender-frequenzzähler

Schritt 1: Old-School-Frequenzzählung

Old-School-Frequenzzählung
Old-School-Frequenzzählung
Old-School-Frequenzzählung
Old-School-Frequenzzählung

Die Old-School-Methode, die Frequenz eines Signals zu messen, besteht darin, ein logisches UND-Gatter zu verwenden, das zu messende Signal in einen Port und ein Signal mit einer genau 1 Sekunde hohen Zeit in den anderen Port einzuspeisen und den Ausgang zu zählen. Dies funktioniert recht gut für Signale von einigen kHz bis weit in den GHz-Bereich. Was aber, wenn Sie ein niederfrequentes Signal mit guter Auflösung messen möchten? Angenommen, Sie möchten die Netzfrequenz messen (hier 50 Hz). Mit der Old-School-Methode sehen Sie mit etwas Glück eine konstante 50 auf Ihrem Display, aber wahrscheinlicher werden Sie sehen, dass das Display von 49 auf 50 oder 50 auf 51 wechselt. Die Auflösung beträgt 1 Hz, und das war's. Sie werden nie 50,002 Hz sehen, es sei denn, Sie sind bereit, die Gate-Zeit auf 1000 Sekunden zu erhöhen. Das sind mehr als 16 Minuten für eine einzige Messung!

Eine bessere Möglichkeit, niederfrequente Signale zu messen, besteht darin, deren Periode zu messen. Nimmt man das Netz wieder als Beispiel, hat es eine Periode von 20 Millisekunden. Nehmen Sie das gleiche logische UND-Gatter, speisen Sie es mit beispielsweise 10 MHz (0,1 us-Impulse) und Ihrem Signal am anderen Port und es kommen 200000 Impulse, so dass die Periodenzeit 20000,0 us beträgt und das wieder in 50 Hz übersetzt wird. Wenn Sie nur 199650 Impulse messen, beträgt die Frequenz 50,087 Hz, das ist viel besser, und das in nur einer Sekunde Messzeit. Leider funktioniert dies bei höheren Frequenzen nicht gut. Nehmen wir zum Beispiel, wir wollen jetzt 40 kHz messen. Bei gleicher Eingangsfrequenz von 10 MHz wie die Referenz messen wir jetzt nur noch 250 Impulse. Wenn wir nur 249 Impulse zählen, ergibt die Berechnung 40161 Hz und bei 251 ist das Ergebnis 39840 Hz. Das ist keine akzeptable Auflösung. Natürlich verbessert eine Erhöhung der Referenzfrequenz die Ergebnisse, aber die Verwendungsmöglichkeiten eines Mikrocontrollers sind begrenzt.

Schritt 2: Der gegenseitige Weg

Der wechselseitige Weg
Der wechselseitige Weg
Der wechselseitige Weg
Der wechselseitige Weg

Eine Lösung, die sowohl für niedrige als auch für höhere Frequenzen funktioniert, ist ein reziproker Frequenzzähler. Ich versuche, das Prinzip zu erklären. Sie beginnen mit einer Messzeit von ca. 1 Sekunde, sie muss nicht sehr genau sein, aber es ist eine vernünftige Zeit für eine Messung. Führen Sie dieses 1 Hz-Signal in ein D-Flipflop am D-Eingang ein. An den Ausgängen passiert noch nichts. Schließen Sie das zu messende Signal an den CLOCK-Eingang des D-Flipflops an.

Sobald dieses Signal von LOW auf HIGH geht, überträgt der Ausgang des D-Flipflops den Zustand des D-Eingangs auf den Ausgang (Q). Dieses ansteigende Signal wird verwendet, um das Zählen des Eingangssignals sowie eines Referenztaktsignals zu starten.

Sie zählen also ZWEI Signale gleichzeitig, das zu messende Signal und eine Referenzuhr. Dieser Referenztakt muss einen genauen Wert haben und stabil sein, ein normaler Quarzoszillator ist in Ordnung. Der Wert ist nicht sehr wichtig, solange es sich um eine hohe Frequenz handelt und sein Wert gut bekannt ist.

Nach einiger Zeit, sagen wir ein paar Millisekunden, machen Sie den D-Eingang des D-Flipflops wieder niedrig. Beim nächsten CLOCK-Eingang folgt der Ausgang Q dem Zustand des Eingangs, aber es passiert nichts weiter, da der Mikrocontroller so eingestellt ist, dass er nur auf ein RISING-Signal reagiert. Dann, nach Ablauf der Messzeit (ca. 1 Sekunde) machen Sie den D-Eingang auf HIGH.

Beim nächsten CLOCK-Eingang folgt wieder der Q-Ausgang und dieses RISING-Signal triggert den Mikrocontroller, diesmal das Zählen beider Zähler zu beenden.

Das Ergebnis sind zwei Zahlen. Die erste Zahl ist die Anzahl der Pulse, die von der Referenz gezählt werden. Da wir die Referenzfrequenz kennen, kennen wir auch die Zeit, die zum Zählen dieser Impulse benötigt wurde.

Die zweite Zahl ist die Anzahl der Impulse des gemessenen Eingangssignals. Da wir genau an den RISING-Flanken dieses Signals begonnen haben, sind wir sehr zuversichtlich, was die Anzahl der Impulse dieses Eingangssignals angeht.

Jetzt ist es nur noch eine Berechnung, um die Frequenz des Eingangssignals zu bestimmen.

Nehmen wir als Beispiel an, wir haben diese Signale und möchten den f-Eingang messen. Die Referenz ist 10 MHz, erzeugt von einem Quarzkristalloszillator. f_input = 31,416 Hz f_reference = 10000000 Hz (10 MHz), die Messzeit beträgt ca. 1 Sekunde

In dieser Zeit haben wir 32 Impulse gezählt. Nun dauert eine Periode dieses Signals 1 / 31,416 = 31830.9 us. Für 32 Perioden brauchten wir also 1,0185892 Sekunden, was etwas mehr als 1 Sekunde ist.

In dieser 1.0186 Sekunde werden wir auch 10185892 Impulse des Referenzsignals gezählt haben.

Daraus ergeben sich folgende Informationen: input_count = 32 reference_count = 10185892 f_reference = 10000000 Hz

Die Formel zur Berechnung der resultierenden Frequenz lautet: freq = (input_count * f_reference) / ref_count

In unserem Beispiel ist das: f-Eingang = (32 * 10000000) / 10185892 = 31,416 Hz

Und dies funktioniert sowohl für tiefe als auch für hohe Frequenzen gut, nur wenn das Eingangssignal der Referenzfrequenz nahe (oder sogar höher) kommt, ist es besser, die standardmäßige "gated" -Messmethode zu verwenden. Dann könnten wir aber auch einfach einen Frequenzteiler zum Eingangssignal hinzufügen, da dieses reziproke Verfahren für jede Frequenz (bis auf die Referenz wieder) die gleiche Auflösung hat. Unabhängig davon, ob Sie 100 kHz direkt messen oder durch einen externen 1000x-Teiler dividieren, ist die Auflösung dieselbe.

Schritt 3: Hardware und ihr Schaltplan

Hardware und ihr Schaltplan
Hardware und ihr Schaltplan
Hardware und ihr Schaltplan
Hardware und ihr Schaltplan

Ich habe einige dieser Art von Frequenzzählern hergestellt. Vor langer Zeit habe ich einen mit einem ATMEGA328 (derselbe Controller wie in einem Arduino), später mit ARM-Mikrocontrollern von ST. Der neueste wurde mit einem STM32F407 mit 168 MHz getaktet. Aber jetzt habe ich mich gefragt, was wäre, wenn ich dasselbe mit einem *viel* kleineren mache. Ich habe mich für einen ATTINY2313 entschieden, der nur 2kByte FLASH-Speicher und 128 Byte RAM hat. Als Display habe ich ein MAX7219 mit 8 7-Segment-Displays, diese Displays gibt es bei Ebay für nur 2 Euro. Ein ATTINY2313 ist für ca. 1,5 Euro zu haben, die restlichen Teile kosten nur Cent pro Stück. Am teuersten war wohl die Projektbox aus Kunststoff. Später entschied ich mich, es mit einem Lithium-Ionen-Akku zu betreiben, also musste ich einen (LDO) 3.3V Spannungsstabilisator, ein Akku-Lademodul und den Akku selbst hinzufügen. Dies erhöht den Preis etwas, aber ich denke, es kann für weniger als 20 Euro gebaut werden.

Schritt 4: Der Code

Der Code
Der Code
Der Code
Der Code

Der Code wurde in C mit Atmel (Microchip) Studio 7 geschrieben und mit einem OLIMEX AVR_ISP (Klon?) in den ATTINY2313 programmiert. Öffnen Sie (main.c) in der Zip-Datei unten, wenn Sie der Beschreibung hier folgen möchten.

INITIALISIERUNG

Zuerst wurde der ATTINY2313 so eingestellt, dass er einen externen Quarz verwendet, da der interne RC-Oszillator für Messungen unbrauchbar ist. Ich verwende einen 10-MHz-Quarz, den ich mit einem kleinen variablen Kondensator auf die richtige Frequenz von 10 000 000 Hz abstimme. Die Initialisierung kümmert sich um das Setzen von Ports auf Ein- und Ausgänge, das Einrichten der Timer und das Aktivieren von Interrupts und die Initialisierung des MAX7219. TIMER0 ist so eingestellt, dass es einen externen Takt zählt, TIMER1 den internen Takt und auch den Wert des Zählers an der steigenden Flanke von ICP, die vom D-Flipflop kommt, zu erfassen.

Ich werde das Hauptprogramm zuletzt besprechen, also sind als nächstes die Interrupt-Routinen.

TIMER0_OVF

Da TIMER0 bis 255 (8 Bit) zählt und dann auf 0 übergeht, benötigen wir einen Interrupt, um die Anzahl der Überläufe zu zählen. Das ist alles, was TIMER0_OVF tut, nur die Anzahl der Überläufe zählen. Später wird diese Zahl mit dem Wert des Zählers selbst kombiniert.

TIMER1_OVF

TIMER1 kann bis zu 65536 (16 Bit) zählen, der Interrupt TIMER1_OVF zählt also auch die Anzahl der Überläufe. Aber es tut mehr. Es dekrementiert auch von 152 auf 0, was etwa 1 Sekunde dauert, und setzt dann einen Ausgangspin, der zum D-Eingang des Flipflops geht. Und das letzte, was in dieser Interrupt-Routine gemacht wird, ist, den Timeout-Zähler von 765 auf 0 zu dekrementieren, was ungefähr 5 Sekunden dauert.

TIMER1_CAPT

Dies ist der TIMER1_CAPT-Interrupt, der jedes Mal ausgelöst wird, wenn das D-Flipflop an der steigenden Flanke des Eingangssignals ein Signal sendet (wie oben erläutert). Die Erfassungslogik sorgt dafür, dass der Wert des TIMER1-Zählers zum Zeitpunkt der Erfassung gespeichert wird, er wird ebenso wie der Überlaufzähler gespeichert. Leider hat TIMER0 keine Input Capture Funktion, daher wird hier sein aktueller Wert und sein aktueller Wert des Überlaufzählers gelesen. Eine Nachrichtenvariable wird für das Hauptprogramm auf eins gesetzt, um ihm mitzuteilen, dass es sich um neue Daten handelt.

Als nächstes kommen zwei Funktionen zur Steuerung des MAX7219

SPI

Obwohl im Chip eine Universal Serial Interface (USI) verfügbar ist, habe ich mich entschieden, sie nicht zu verwenden. Das Display des MAX7219 muss über SPI gesteuert werden und das ist mit der USI möglich. Aber Bitbanging SPI ist so einfach, dass ich mir nicht die Zeit genommen habe, es mit dem USI zu machen.

MAX7219

Das Protokoll zum Einrichten des MAX7219 ist ebenfalls recht einfach, nachdem Sie das Handbuch gelesen haben. Es benötigt einen 16-Bit-Wert für jede Ziffer, die aus 8 Bits für die Ziffernnummer (1 bis 8) besteht, gefolgt von 8 Bits für die anzuzeigende Zahl.

HAUPTPROG

Als letztes wird das Hauptprogramm erklärt. Es läuft in einer Endlosschleife (while(1)), tut aber nur dann wirklich etwas, wenn eine Meldung (1) von der Interrupt-Routine kommt oder der Timeout-Zähler auf Null abgelaufen ist (kein Eingangssignal).

Wenn die Variable Message auf Eins gesetzt ist, muss als erstes der Timeout-Zähler zurückgesetzt werden, schließlich wissen wir, dass ein Signal anliegt. Das D-Flipflop wird zurückgesetzt, um es für den nächsten Trigger bereit zu machen, der nach der Messzeit (Wait-a-Sekunde) kommt.

Die im Capture-Interrupt registrierten Zahlen werden addiert, um den Referenzzähler und den Eingangsfrequenzzähler zu ergeben. (Wir müssen darauf achten, dass die Referenz niemals Null sein kann, da wir später durch sie dividieren werden)

Als nächstes folgt die Berechnung der tatsächlichen Frequenz. Ich möchte sicherlich keine Floating-Zahlen auf einem Mikrocontroller mit nur 2 kByte Flash und nur 128 Byte RAM verwenden. Ich verwende Integer. Aber Frequenzen können wie 314,159 Hz sein, mit mehreren Dezimalstellen. Daher multipliziere ich die Eingangsfrequenz nicht nur mit der Referenzfrequenz, sondern auch mit einem Multiplikator und füge dann eine Zahl hinzu, wo der Dezimalpunkt stehen soll. Diese Zahlen werden sehr, sehr groß, wenn Sie das tun. Z. B. bei einem Eingang von 500 kHz, einer Referenz von 10 MHz und einem Multiplikator von 100 ergibt das 5 x 10^14, das ist wirklich riesig! Sie passen nicht mehr in eine 32-Bit-Zahl, daher verwende ich 64-Bit-Zahlen, die bis zu 1,8 x 10 ^ 19 reichen (das funktioniert auf einem ATTINY2313 gut).

Und als letztes senden Sie das Ergebnis an das Display des MAX7219.

Der Code lässt sich in etwa 1600 Byte kompilieren, passt also in den 2048 Byte großen Flash, der im ATTINY2313 verfügbar ist.

Die Fuse-Register sollten wie folgt lauten:

ERWEITERT 0xFF

HOCH 0xDF

NIEDRIG 0xBF

Schritt 5: Genauigkeit und Präzision

Genauigkeit und Präzision
Genauigkeit und Präzision
Genauigkeit und Präzision
Genauigkeit und Präzision
Genauigkeit und Präzision
Genauigkeit und Präzision

Genauigkeit und Präzision sind zwei getrennte Bestien. Die Genauigkeit beträgt hier sieben Stellen, die tatsächliche Genauigkeit hängt von der Hardware und der Kalibrierung ab. Ich habe die 10 MHz (5 MHz am Testpunkt) mit einem anderen Frequenzzähler kalibriert, der einen GPS-disziplinierten Oszillator hat.

Und es funktioniert ganz gut, die niedrigste Frequenz, die ich ausprobiert habe, ist 0,2 Hz, die höchste 2 MHz. Es ist genau richtig. Oberhalb von 2 MHz beginnt der Controller Interrupts zu verlieren, was nicht wirklich verwunderlich ist, wenn man weiß, dass TIMER0 bei 2 MHz Eingangssignal über 7800 Interrupts pro Sekunde erzeugt. Und der ATTINY2313 hat auch noch andere Dinge zu tun, die Interrupts vom TIMER1, bei weiteren 150 Interrupts pro Sekunde und natürlich die Berechnungen, Steuerung von Display und D-Flipflop. Wenn Sie sich das eigentliche Gerät ansehen, werden Sie feststellen, dass ich nur sieben der acht Ziffern des Displays verwende. Ich tue dies aus mehreren Gründen.

Erstens ist die Berechnung der Eingangsfrequenz eine Division, sie wird fast immer einen Rest haben, den Sie nicht sehen, da es sich um eine ganzzahlige Division handelt. Zweitens ist der Quarzkristalloszillator nicht temperaturstabilisiert.

Die Kondensatoren, die es auf die richtigen 10 MHz abstimmen, sind aus Keramik und sehr empfindlich gegenüber Temperaturänderungen. Dann gibt es noch die Tatsache, dass TIMER0 keine integrierte Erfassungslogik hat und die Interrupt-Funktionen alle einige Zeit brauchen, um ihre Arbeit zu erledigen. Ich denke, sieben Ziffern sind sowieso gut genug.