Indholdsfortegnelse:

Høj opløsning frekvens tæller: 5 trin (med billeder)
Høj opløsning frekvens tæller: 5 trin (med billeder)

Video: Høj opløsning frekvens tæller: 5 trin (med billeder)

Video: Høj opløsning frekvens tæller: 5 trin (med billeder)
Video: PREPRESS: (1:23:12 min) Digitale billeder, opløsning, fra RGB til CMYK, ICC-profiler, PDF/X etc 2024, November
Anonim

Denne instruerbare viser en gensidig frekvensmåler, der er i stand til at måle frekvenser hurtigt og med rimelig præcision. Den er lavet med standardkomponenter og kan laves i en weekend (det tog mig lidt længere:-))

EDIT: Koden er nu tilgængelig på GitLab:

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

Trin 1: Old School Frequency Counting

Old School Frequency Counting
Old School Frequency Counting
Old School Frequency Counting
Old School Frequency Counting

Den gamle skolemåde til at måle frekvensen af et signal er at bruge en logisk AND-gate, indføre signalet, der skal måles, til en port og et signal med en præcis 1 sekund høj tid til den anden port og tælle output. Dette fungerer ganske godt for signaler på et par kHz langt ind i GHz. Men hvad nu hvis du vil måle et lavfrekvent signal med god opløsning? Sig, at du vil måle frekvensen af lysnettet (her 50 Hz). Med den gamle skolemetode vil du se en konstant 50 på din skærm, hvis du er heldig, men mere sandsynligt vil du se displayskiftet fra 49 til 50 eller 50 til 51. Opløsningen er 1 Hz, og det er det. Du vil aldrig se 50,002 Hz, medmindre du er villig til at øge porttiden til 1000 sekunder. Det er mere end 16 minutter, for en enkelt måling!

En bedre måde at måle lavfrekvente signaler på er at måle perioden for den. At tage lysnettet som et eksempel igen, har en periode på 20 millisekund. Tag den samme logiske AND-gate, fodre den med, siger 10 MHz (0,1 us pulser) og dit signal på den anden port og ud kommer 200000 pulser, så periodetiden er 20000,0 uS, og det oversætter tilbage til 50Hz. Når du måler bare 199650 pulser, er frekvensen 50.087 Hz, det er meget bedre, og det er på kun et sekund målingstid. Desværre fungerer dette ikke godt med højere frekvenser. Tag for eksempel, vi vil nu måle 40 kHz. Med den samme 10 MHz inputfrekvens som referencen måler vi nu kun 250 pulser. Når vi tæller kun 249 pulser giver beregningen 40161 Hz og med 251 er resultatet 39840 Hz. Det er ikke en acceptabel løsning. Selvfølgelig øger referencefrekvensen resultaterne, men der er en grænse for, hvad du kan bruge i en mikrocontroller.

Trin 2: Den gensidige måde

Den gensidige måde
Den gensidige måde
Den gensidige måde
Den gensidige måde

En løsning, der fungerer til både lave og højere frekvenser, er en gensidig frekvensmåler. Jeg prøver at forklare dens princip. Du starter med en måltid, der er cirka 1 sekund, det behøver ikke at være særlig præcist, men det er en rimelig tid til en måling. Tilfør dette 1 Hz-signal til en D-flipflop på D-indgangen. Intet sker endnu på output (s). Tilslut det signal, du vil måle, til CLOCK-indgangen på D-flip-floppen.

Så snart dette signal går fra LOW til HIGH, overfører udgangen fra D-flipflop tilstanden af D-input til output (Q). Dette stigende signal, der går, bruges til at begynde at tælle indgangssignalet samt et referenceurssignal.

Så du tæller TO signaler på nøjagtig samme tid, det signal du vil måle og et referenceur. Dette referenceur skal have en præcis værdi og være stabil, en normal krystaloscillator er fin. Værdien er ikke særlig vigtig, så længe den er en høj frekvens, og dens værdi kendes godt.

Efter et stykke tid, sig et par millisekunder, gør du D-input for D-flipflop lav igen. Ved den næste CLOCK-indgang følger udgangen Q input-tilstanden, men intet andet sker, fordi mikrokontrolleren er indstillet til kun at reagere på et RISING-signal. Efter målingstiden er overstået (ca. 1 sekund) gør du D-input HIGH.

Igen ved den næste CLOCK-input følger Q-udgangen, og dette RISING-signal udløser mikrokontrolleren, denne gang for at afslutte tællingen af begge tællere.

Resultatet er to tal. Det første tal er antallet af pulser talt fra referencen. Da vi kender referencefrekvensen, kender vi også den tid, det tog at tælle disse pulser.

Den anden er tallet antallet af impulser fra det indgangssignal, vi måler. Da vi startede præcist på de stigende kanter af dette signal, er vi meget sikre på antallet af pulser af dette indgangssignal.

Nu er det bare en beregning at bestemme frekvensen af indgangssignalet.

Et eksempel, lad os sige, at vi har disse signaler, og vi vil måle f-input. Referencen er 10 MHz, genereret af en kvartskrystaloscillator. f_input = 31.416 Hz f_reference = 10000000 Hz (10 MHz), målingstiden er ca. 1 sekund

I denne tid tællede vi 32 pulser. Nu tager en periode af dette signal 1 / 31,416 = 31830,9 uS. Så 32 perioder tog os 1.0185892 sekunder, hvilket er lidt over 1 sekund.

I dette 1.0186 sekund vil vi også have talt 10185892 pulser af referencesignalet.

Dette giver os følgende oplysninger: input_count = 32 reference_count = 10185892 f_reference = 10000000 Hz

Formlen til beregning af den resulterende frekvens er denne: freq = (input_count * f_reference) / ref_count

I vores eksempel er det: f-input = (32 * 10000000) / 10185892 = 31,416 Hz

Og dette fungerer godt for både lave og høje frekvenser, kun når indgangssignalet kommer tæt på (eller endda højere end) referencefrekvensen, er det bedre at bruge standard "gated" måling. Men så kunne vi også blot tilføje en frekvensdeler til indgangssignalet, da denne gensidige metode har den samme opløsning for enhver frekvens (op til referencen igen). Så uanset om du måler 100 kHz direkte divideret med en ekstern 1000x divider, er opløsningen den samme.

Trin 3: Hardware og dens skematiske

Hardware og dens skematiske
Hardware og dens skematiske
Hardware og dens skematiske
Hardware og dens skematiske

Jeg har lavet et par af denne type frekvensmålinger. For længe siden lavede jeg en med en ATMEGA328 (den samme controller som der er i en Arduino), senere med ARM mikro controllere fra ST. Den seneste blev lavet med en STM32F407, der var klokket til 168 MHz. Men nu spekulerede jeg på, hvad hvis jeg gør det samme med en * meget * mindre. Jeg valgte en ATTINY2313, der kun har 2 kbyte FLASH -hukommelse og 128 bytes RAM. Displayet jeg har er en MAX7219 med 8 syv segmentskærme på det, disse skærme er tilgængelige på Ebay for kun 2 euro. En ATTINY2313 kan købes for omkring 1,5 euro. Resten af de dele, jeg brugte, koster bare øre pr. Stk. Dyrest var nok projektkassen af plast. Senere besluttede jeg at få det til at køre på et lithium-ion batteri, så jeg havde brug for at tilføje en (LDO) 3.3V spændingsstabilisator, et batteriopladningsmodul og selve batteriet. Dette øger prisen noget, men jeg gætter på, at den kan bygges for mindre end 20 euro.

Trin 4: Koden

Koden
Koden
Koden
Koden

Koden blev skrevet i C med Atmel (Microchip) Studio 7 og programmeret i ATTINY2313 ved hjælp af en OLIMEX AVR_ISP (klon?). Åbn (main.c) i zip -filen herunder, hvis du vil følge beskrivelsen her.

INITIALISERING

Først blev ATTINY2313 indstillet til at bruge en ekstern krystal, da den interne RC-oscillator er ubrugelig til måling af noget. Jeg bruger en 10 MHz krystal, som jeg indstiller til den korrekte 10 000 000 Hz frekvens med en lille variabel kondensator. Initialiseringen tager sig af at indstille porte til input og output, opsætning af timerne og muliggøre afbrydelser og initialisering af MAX7219. TIMER0 er opsat til at tælle et eksternt ur, TIMER1 det interne ur og også for at fange tællerens værdi ved ICP's stigende kant, der kommer fra D-flipflop.

Jeg diskuterer hovedprogrammet sidst, så næste er afbrydelsesrutinerne.

TIMER0_OVF

Da TIMER0 tæller op til 255 (8 bits) og derefter ruller over til 0, har vi brug for en afbrydelse for at tælle antallet af overløb. Det er alt, TIMER0_OVF gør, bare tæl antallet af overløb. Senere kombineres dette tal med værdien af selve tælleren.

TIMER1_OVF

TIMER1 kan tælle op til 65536 (16 bit), så afbrydelsen TIMER1_OVF tæller også antallet af overløb. Men det gør mere. Det formindskes også fra 152 til 0, hvilket tager cirka 1 sekund og derefter indstiller en udgangsstift, der går til flip-floppens D-indgang. Og det sidste, der gøres i denne afbrydelsesrutine, er at reducere timeout-tælleren fra 765 til 0, hvilket tager cirka 5 sekunder.

TIMER1_CAPT

Dette er TIMER1_CAPT-afbrydelsen, der udløses hver gang D-flipfloppen sender det et signal ved indgangssignalets stigende kant (som forklaret ovenfor). Capture -logikken sørger for at gemme værdien af TIMER1 -tælleren på tidspunktet for capture, den gemmes såvel som overløbstælleren. Desværre har TIMER0 ikke en input capture -funktion, så her læses dens aktuelle værdi og dens aktuelle værdi for overløbstælleren. En meddelelsesvariabel er sat til en til hovedprogrammet for at fortælle, at det er nye data.

Næste er to funktioner til styring af MAX7219

SPI

Selvom der er en Universal Serial Interface (USI) tilgængelig i chippen, valgte jeg ikke at bruge den. MAX7219 -displayet skal styres via SPI, og det er muligt med USI. Men bitbanging SPI er så enkelt, at jeg ikke tog mig tid til at gøre det med USI.

MAX7219

Protokollen til opsætning af MAX7219 er også ganske enkel, når du har læst manualen til den. Det har brug for en 16 bit værdi for hvert ciffer, der består af 8 bits for ciffernummeret (1 til 8) efterfulgt af 8 bits for det nummer, det skal vise.

HOVED-PROG

Det sidste er at forklare hovedprogrammet. Den kører i en uendelig loop (mens (1)), men gør faktisk kun noget, når der er en besked (1) fra afbrydelsesrutinen, eller når timeout -tælleren er løbet ned til nul (intet indgangssignal).

Den første ting, der skal gøres, når den variable meddelelse er indstillet til en, er nulstilling af timeout -tælleren, vi ved jo, at der er et signal til stede. D-flipflop nulstilles for at gøre den klar til den næste trigger, der kommer efter måltiden (vent et sekund).

De numre, der er registreret i capture-afbrydelsen, tilføjes for at give referencetællingen og input-frekvens-tællingen. (vi skal sørge for, at referencen aldrig kan være nul, da vi vil dividere med den senere)

Næste er en beregning af den faktiske frekvens. Jeg vil bestemt ikke bruge flydende tal på en mikrokontroller med kun 2 kbyte flash og kun 128 bytes ram, jeg bruger heltal. Men frekvenser kan være som 314,159 Hz, med flere decimaler. Derfor multiplicerer jeg inputfrekvensen ikke kun med referencefrekvensen, men også med en multiplikator, og tilføjer derefter et tal til, hvor decimaltegnet skal gå. Disse tal bliver meget meget store, når du gør det. F.eks. med et input på 500 kHz, en reference på 10 MHz og en multiplikator på 100, giver dette 5 x 10^14, det er virkelig stort! De vil ikke længere passe i et 32 bit nummer, så jeg bruger 64 bit tal, der vil gå helt op til 1,8 x 10^19 (det fungerer fint på en ATTINY2313)

Og den sidste ting at gøre er at sende resultatet til MAX7219 displayet.

Koden kompileres til omkring 1600 bytes, så den passer ind i den 2048 bytes flash, der er tilgængelig i ATTINY2313.

Sikringsregistrene skal se sådan ud:

UDVIDET 0xFF

HØJ 0xDF

LAV 0xBF

Trin 5: Nøjagtighed og præcision

Nøjagtighed og præcision
Nøjagtighed og præcision
Nøjagtighed og præcision
Nøjagtighed og præcision
Nøjagtighed og præcision
Nøjagtighed og præcision

Nøjagtighed og præcision er to separate dyr. Præcisionen her er syv cifre, hvad den faktiske præcision er, afhænger af hardwaren og kalibreringen. Jeg kalibrerede 10 MHz (5 MHz på testpunktet) med en anden frekvensmåler, der har en GPS -disciplineret oscillator.

Og det fungerer ganske godt, den laveste frekvens, jeg prøvede, er 0,2 Hz, den højeste 2 MHz. Det er spot on. Over 2 MHz begynder controlleren at miste afbrydelser, ikke rigtigt overraskende, når du ved, at TIMER0 genererer over 7800 afbrydelser pr. Sekund ved 2 MHz indgangssignal. Og ATTINY2313 skal også gøre andre ting, afbrydelserne fra TIMER1, med yderligere 150 afbrydelser pr. Sekund og selvfølgelig foretage beregningerne, kontrollere displayet og D-flipflop. Når du ser på den faktiske enhed, vil du se, at jeg kun bruger syv af de otte cifre i displayet. Jeg gør dette af flere grunde.

For det første er, at beregningen af inputfrekvensen er en division, den vil næsten altid have en rest, som du ikke kan se, da det er en heltal division. For det andet er, at kvartskrystaloscillatoren ikke er temperaturstabiliseret.

Kondensatorerne, der indstiller den til den korrekte 10 MHz, er keramiske, meget følsomme over for temperaturændringer. Så er der det faktum, at TIMER0 ikke har indbygget capture -logik, og afbrydelsesfunktionerne tager alle lidt tid at udføre deres arbejde. Jeg synes, at syv cifre alligevel er godt nok.

Anbefalede: