Inhoudsopgave:

Frequentieteller met hoge resolutie - Ajarnpa
Frequentieteller met hoge resolutie - Ajarnpa

Video: Frequentieteller met hoge resolutie - Ajarnpa

Video: Frequentieteller met hoge resolutie - Ajarnpa
Video: High Frequency Stimulation Apparaat - Groothandel Safety4you 2024, Juli-
Anonim

Deze instructable toont een wederzijdse frequentieteller die frequenties snel en met redelijke precisie kan meten. Het is gemaakt met standaard componenten en kan in een weekend worden gemaakt (het kostte me wat langer:-))

EDIT: De code is nu beschikbaar op GitLab:

gitlab.com/WilkoL/high-resolution-frequency-counter

Stap 1: Old School Frequentie Tellen

Old School Frequentie Tellen
Old School Frequentie Tellen
Old School Frequentie Tellen
Old School Frequentie Tellen

De ouderwetse manier om de frequentie van een signaal te meten is door een logische EN-poort te gebruiken, het te meten signaal naar de ene poort te voeren en een signaal met een exacte 1 seconde hoge tijd naar de andere poort en de output te tellen. Dit werkt vrij goed voor signalen van een paar kHz tot ver in de GHz. Maar wat als u een laagfrequent signaal met een goede resolutie wilt meten? Stel dat u de frequentie van het lichtnet wilt meten (hier 50 Hz). Met de ouderwetse methode zie je een constante 50 op je scherm als je geluk hebt, maar meer kans dat je het scherm ziet veranderen van 49 naar 50 of 50 naar 51. De resolutie is 1 Hz, en dat is alles. U zult nooit 50.002 Hz zien tenzij u bereid bent de gate-tijd te verhogen tot 1000 seconden. Dat is meer dan 16 minuten, voor een enkele meting!

Een betere manier om laagfrequente signalen te meten is door de periode ervan te meten. Als we opnieuw het lichtnet als voorbeeld nemen, heeft dat een periode van 20 milliseconde. Neem dezelfde logische EN-poort, voed deze met bijvoorbeeld 10 MHz (0,1 us-pulsen) en je signaal op de andere poort en er komen 200000 pulsen uit, dus de periodetijd is 20000,0 uS en dat vertaalt zich terug in 50 Hz. Als je slechts 199650 pulsen meet, is de frequentie 50,087 Hz, dat is een stuk beter, en het is in slechts één seconde meettijd. Helaas werkt dit niet goed bij hogere frequenties. Neem bijvoorbeeld, we willen nu 40 kHz meten. Met dezelfde 10 MHz ingangsfrequentie als de referentie meten we nu slechts 250 pulsen. Als we slechts 249 pulsen tellen, geeft de berekening 40161 Hz en met 251 is het resultaat 39840 Hz. Dat is geen acceptabele resolutie. Natuurlijk verbetert het verhogen van de referentiefrequentie de resultaten, maar er is een limiet aan wat u in een microcontroller kunt gebruiken.

Stap 2: De wederzijdse manier

De wederkerige manier
De wederkerige manier
De wederkerige manier
De wederkerige manier

Een oplossing die werkt voor zowel lage als hogere frequenties is een reciproke frequentieteller. Ik zal proberen het principe uit te leggen. Je begint met een meettijd van ongeveer 1 seconde, het hoeft niet heel precies te zijn maar het is wel een redelijke tijd voor een meting. Voer dit 1 Hz signaal in een D-flipflop op de D-ingang. Op de uitgang(en) gebeurt nog niets. Sluit het signaal dat je wilt meten aan op de CLOCK-ingang van de D-flipflop.

Zodra dit signaal van LAAG naar HOOG gaat, geeft de uitgang van de D-flipflop de toestand van de D-ingang door aan de uitgang (Q). Dit STIJGENDE signaal wordt gebruikt om zowel het ingangssignaal als een referentiekloksignaal te tellen.

Je telt dus TWEE signalen op exact hetzelfde moment, het signaal dat je wilt meten en een referentieklok. Deze referentieklok moet een precieze waarde hebben en stabiel zijn, een normale kristaloscillator is prima. De waarde is niet erg belangrijk, zolang het maar een hoge frequentie is en de waarde ervan goed bekend is.

Na enige tijd, zeg een paar milliseconden, maak je de D-ingang van de D-flipflop weer laag. Bij de volgende CLOCK-ingang volgt de uitgang Q de toestand van de ingang, maar verder gebeurt er niets omdat de microcontroller is ingesteld om alleen op een STIJGEND signaal te reageren. Na afloop van de meettijd (ca. 1 seconde) maakt u de D-ingang HOOG.

Bij de volgende CLOCK-ingang volgt weer de Q-uitgang en dit STIJGENDE signaal activeert de microcontroller, dit keer om het tellen van beide tellers te beëindigen.

Het resultaat is twee cijfers. Het eerste getal is het aantal pulsen geteld vanaf de referentie. Omdat we de referentiefrequentie kennen, weten we ook hoe lang het duurde om die pulsen te tellen.

Het tweede getal is het aantal pulsen van het ingangssignaal dat we aan het meten zijn. Omdat we precies op de STIJGENDE flanken van dit signaal zijn begonnen, hebben we veel vertrouwen in het aantal pulsen van dit ingangssignaal.

Nu is het slechts een berekening om de frequentie van het ingangssignaal te bepalen.

Een voorbeeld, laten we zeggen dat we deze signalen hebben en dat we de f-ingang willen meten. De referentie is 10 MHz, gegenereerd door een kwartskristaloscillator. f_input = 31,416 Hz f_reference = 10000000 Hz (10 MHz), de meettijd is ca. 1 seconde

In deze tijd telden we 32 pulsen. Nu duurt een periode van dit signaal 1 / 31.416 = 31830,9 uS. Dus 32 perioden kostte ons 1.0185892 seconden, dat is iets meer dan 1 seconde.

In deze 1.0186 seconde zullen we ook 10185892 pulsen van het referentiesignaal hebben geteld.

Dit geeft ons de volgende informatie: input_count = 32 reference_count = 10185892 f_reference = 10000000 Hz

De formule om de resulterende frequentie te berekenen is deze: freq = (input_count * f_reference) / ref_count

In ons voorbeeld is dat: f-ingang = (32 * 10000000) / 10185892 = 31,416 Hz

En dit werkt goed voor zowel lage frequenties als hoge frequenties, alleen wanneer het ingangssignaal dichtbij (of zelfs hoger dan) de referentiefrequentie komt, is het beter om de standaard "gated" manier van meten te gebruiken. Maar dan zouden we ook gewoon een frequentiedeler aan het ingangssignaal kunnen toevoegen, aangezien deze reciproke methode dezelfde resolutie heeft voor elke frequentie (weer tot aan de referentie). Dus of je nu 100 kHz direct meet of gedeeld door een externe 1000x deler, de resolutie is hetzelfde.

Stap 3: Hardware en zijn schema

Hardware en zijn schema
Hardware en zijn schema
Hardware en zijn schema
Hardware en zijn schema

Ik heb een paar van dit soort frequentietellers gemaakt. Lang geleden heb ik er een gemaakt met een ATMEGA328 (dezelfde controller als er in een Arduino zit), later met ARM microcontrollers van ST. De nieuwste is gemaakt met een STM32F407 geklokt op 168 MHz. Maar nu vroeg ik me af wat als ik hetzelfde zou doen met een *veel* kleinere. Ik koos voor een ATTINY2313, die slechts 2 kbyte FLASH-geheugen en 128 bytes RAM heeft. Het display dat ik heb is een MAX7219 met 8 zevensegmentendisplays erop, deze displays zijn op Ebay verkrijgbaar voor slechts 2 euro. Een ATTINY2313 kan worden gekocht voor ongeveer 1,5 euro, de rest van de gebruikte onderdelen kosten slechts cent per stuk. Het duurst was waarschijnlijk de plastic projectdoos. Later besloot ik om het op een lithium-ionbatterij te laten werken, dus ik moest een (LDO) 3.3V-spanningsstabilisator, een batterij-oplaadmodule en de batterij zelf toevoegen. Dit verhoogt de prijs enigszins, maar ik denk dat het voor minder dan 20 euro kan worden gebouwd.

Stap 4: De code

De code
De code
De code
De code

De code is geschreven in C met Atmel (Microchip) Studio 7 en geprogrammeerd in de ATTINY2313 met behulp van een OLIMEX AVR_ISP (kloon?). Open de (main.c) in het zip-bestand hieronder als je de beschrijving hier wilt volgen.

INITIALISATIE

Eerst was de ATTINY2313 ingesteld om een extern kristal te gebruiken, omdat de interne RC-oscillator nutteloos is om iets te meten. Ik gebruik een 10 MHz kristal dat ik afstem op de juiste 10 000 000 Hz frequentie met een kleine variabele condensator. De initialisatie zorgt voor het instellen van poorten naar in- en uitgangen, het instellen van de timers en het inschakelen van interrupts en initialisatie van de MAX7219. TIMER0 is ingesteld om een externe klok te tellen, TIMER1 de interne klok en ook om de waarde van de teller op de stijgende flank van ICP vast te leggen, afkomstig van de D-flipflop.

Ik zal het hoofdprogramma als laatste bespreken, dus de volgende zijn de interruptroutines.

TIMER0_OVF

Omdat TIMER0 tot 255 (8 bits) telt en vervolgens doorrolt naar 0, hebben we een interrupt nodig om het aantal overflows te tellen. Dat is alles wat TIMER0_OVF doet, tel gewoon het aantal overlopen. Later wordt dit getal gecombineerd met de waarde van de teller zelf.

TIMER1_OVF

TIMER1 kan tot 65536 (16 bits) tellen, dus de interrupt TIMER1_OVF telt ook het aantal overflows. Maar het doet meer. Het neemt ook af van 152 naar 0, wat ongeveer 1 seconde duurt en stelt vervolgens een uitgangspen in, die naar de D-ingang van de flipflop gaat. En het laatste dat in deze interruptroutine wordt gedaan, is de time-outteller verlagen, van 765 naar 0, wat ongeveer 5 seconden duurt.

TIMER1_CAPT

Dit is de TIMER1_CAPT-interrupt die wordt getriggerd telkens wanneer de D-flipflop hem een signaal stuurt, aan de stijgende flank van het ingangssignaal (zoals hierboven uitgelegd). De capture-logica zorgt voor het opslaan van de waarde van de TIMER1-teller op het moment van de capture, deze wordt opgeslagen evenals de overloopteller. Helaas heeft TIMER0 geen ingangsregistratiefunctie, dus hier wordt de huidige waarde en de huidige waarde van de overloopteller gelezen. Een berichtvariabele is ingesteld op één zodat het hoofdprogramma aangeeft dat dit nieuwe gegevens zijn.

Hierna volgen twee functies om de MAX7219. te bedienen

SPI

Hoewel er een Universal Serial Interface (USI) beschikbaar is in de chip, heb ik ervoor gekozen deze niet te gebruiken. Het MAX7219-display moet via SPI worden aangestuurd en dat kan met de USI. Maar SPI bitbangen is zo eenvoudig dat ik niet de tijd heb genomen om het met de USI te doen.

MAX7219

Het protocol om de MAX7219 in te stellen is ook vrij eenvoudig als je de handleiding ervan hebt gelezen. Het heeft een waarde van 16 bits nodig voor elk cijfer dat bestaat uit 8 bits voor het cijfer (1 tot 8) gevolgd door 8 bits voor het nummer dat moet worden weergegeven.

HOOFDPROG

Het laatste is om het hoofdprogramma uit te leggen. Het loopt in een oneindige lus (while(1)) maar doet pas echt iets als er een bericht (1) is van de interruptroutine of als de time-outteller op nul staat (geen ingangssignaal).

Het eerste wat je moet doen als de variabele melding op één staat, is de time-out teller resetten, we weten immers dat er een signaal aanwezig is. De D-flipflop wordt gereset om hem klaar te maken voor de volgende trigger die na de meettijd (wacht-a-seconde) komt.

De getallen die zijn geregistreerd in de capture-interrupt worden opgeteld om de referentietelling en de ingangsfrequentietelling te geven. (we moeten ervoor zorgen dat de referentie nooit nul kan zijn, omdat we er later door zullen delen)

Daarna volgt de berekening van de werkelijke frequentie. Ik wil zeker geen zwevende getallen gebruiken op een microcontroller met slechts 2 kbytes flash en slechts 128 bytes ram. Ik gebruik gehele getallen. Maar frequenties kunnen ongeveer 314.159 Hz zijn, met meerdere decimalen. Daarom vermenigvuldig ik de ingangsfrequentie niet alleen met de referentiefrequentie maar ook met een vermenigvuldiger, en tel dan een getal op waar de komma moet komen. Deze getallen zullen heel erg groot worden als je dat doet. bijv. met een input van 500 kHz, een referentie van 10 MHz en een vermenigvuldiger van 100 geeft dit 5 x 10^14, dat is echt enorm! Ze passen niet meer in een 32-bits nummer, dus ik gebruik 64-bits nummers die helemaal tot 1,8 x 10^19 gaan (dat werkt prima op een ATTINY2313)

En het laatste wat u hoeft te doen, is het resultaat naar het MAX7219-display te sturen.

De code wordt gecompileerd tot zo'n 1600 bytes, dus het past in de 2048 bytes flash die beschikbaar is in de ATTINY2313.

De zekeringregisters moeten als volgt luiden:

UITGEBREID 0xFF

HOOG 0xDF

LAAG 0xBF

Stap 5: Nauwkeurigheid en precisie

Nauwkeurigheid en precisie
Nauwkeurigheid en precisie
Nauwkeurigheid en precisie
Nauwkeurigheid en precisie
Nauwkeurigheid en precisie
Nauwkeurigheid en precisie

Nauwkeurigheid en precisie zijn twee aparte beesten. De precisie is hier zeven cijfers, wat de werkelijke precisie is, hangt af van de hardware en de kalibratie. Ik heb de 10 MHz (5 MHz op het testpunt) gekalibreerd met een andere frequentieteller die een GPS-gedisciplineerde oscillator heeft.

En het werkt best goed, de laagste frequentie die ik heb geprobeerd is 0,2 Hz, de hoogste 2 MHz. Het is ter plaatse. Boven de 2 MHz begint de controller interrupts te verliezen, niet echt verwonderlijk als je weet dat op 2 MHz ingangssignaal TIMER0 meer dan 7800 interrupts per seconde genereert. En de ATTINY2313 moet ook andere dingen doen, de interrupts van de TIMER1, met nog eens 150 interrupts per seconde en natuurlijk de berekeningen doen, het display en de D-flipflop besturen. Als je naar het eigenlijke apparaat kijkt, zie je dat ik slechts zeven van de acht cijfers van het scherm gebruik. Ik doe dit om verschillende redenen.

De eerste is dat de berekening van de ingangsfrequentie een deling is, het zal bijna altijd een rest hebben, die je niet ziet omdat het een integer deling is. Ten tweede is de kwartskristaloscillator niet temperatuurgestabiliseerd.

De condensatoren die het afstemmen op de juiste 10 MHz zijn keramisch, zeer gevoelig voor temperatuurveranderingen. Dan is er het feit dat TIMER0 geen ingebouwde capture-logica heeft, en de interruptfuncties hebben allemaal wat tijd nodig om hun werk te doen. Ik denk dat zeven cijfers sowieso goed genoeg is.

Aanbevolen: