Innehållsförteckning:

Högupplöst frekvensräknare: 5 steg (med bilder)
Högupplöst frekvensräknare: 5 steg (med bilder)

Video: Högupplöst frekvensräknare: 5 steg (med bilder)

Video: Högupplöst frekvensräknare: 5 steg (med bilder)
Video: Как спрятать данные в ячейках Excel? 2024, November
Anonim

Denna instruerbara visar en ömsesidig frekvensräknare som kan mäta frekvenser snabbt och med rimlig precision. Den är gjord med standardkomponenter och kan göras på en helg (det tog lite längre tid:-))

EDIT: Koden är nu tillgänglig på GitLab:

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

Steg 1: Gamla skolans frekvensräkning

Gamla skolans frekvensräkning
Gamla skolans frekvensräkning
Gamla skolans frekvensräkning
Gamla skolans frekvensräkning

Det gamla skolans sätt att mäta frekvensen för en signal är att använda en logisk OCH-grind, mata signalen som ska mätas till en port och en signal med en exakt 1 sekund hög tid till den andra porten och räkna utgången. Detta fungerar ganska bra för signaler på några kHz långt in i GHz. Men vad händer om du vill mäta en lågfrekvenssignal med bra upplösning? Säg att du vill mäta nätfrekvensen (här 50 Hz). Med den gamla skolmetoden kommer du att se en konstant 50 på din skärm om du har tur, men mer troligt att du kommer att se displayen växla från 49 till 50 eller 50 till 51. Upplösningen är 1 Hz, och det är det. Du kommer aldrig att se 50,002 Hz om du inte är villig att öka grindtiden till 1000 sekunder. Det är mer än 16 minuter, för en enda mätning!

Ett bättre sätt att mäta lågfrekventa signaler är att mäta dess period. Att ta elnätet som exempel igen, har en period på 20 millisekunder. Ta samma logik OCH-gate, mata den med, säg 10 MHz (0,1 us pulser) och din signal på den andra porten och ut kommer 200000 pulser, så periodtiden är 20000,0 uS och det översätts tillbaka till 50Hz. När du mäter bara 199650 pulser är frekvensen 50.087 Hz, det är mycket bättre, och det är på bara en sekund mätningstid. Tyvärr fungerar detta inte bra med högre frekvenser. Ta till exempel, vi vill nu mäta 40 kHz. Med samma 10 MHz ingångsfrekvens som referensen mäter vi nu bara 250 pulser. När vi räknar bara 249 pulser ger beräkningen 40161 Hz och med 251 är resultatet 39840 Hz. Det är inte en acceptabel lösning. Naturligtvis förbättrar referensfrekvensen resultaten men det finns en gräns för vad du kan använda i en mikrokontroller.

Steg 2: Det ömsesidiga sättet

Det ömsesidiga sättet
Det ömsesidiga sättet
Det ömsesidiga sättet
Det ömsesidiga sättet

En lösning som fungerar för både låga och högre frekvenser är en ömsesidig frekvensräknare. Jag ska försöka förklara dess princip. Du börjar med en mättid som är cirka 1 sekund, det behöver inte vara särskilt exakt men det är en rimlig tid för en mätning. Mata in denna 1 Hz-signal till en D-flipflop på D-ingången. Inget händer än på utgångarna. Anslut den signal som du vill mäta till CLOCK-ingången på D-flipfloppen.

Så snart denna signal går från LÅG till HÖG, överför utgången från D-flipfloppen tillståndet för D-ingången till utgången (Q). Denna RISING -signal som går används för att börja räkna insignalen samt en referensklocksignal.

Så du räknar TVÅ signaler på exakt samma tid, signalen du vill mäta och en referensklocka. Denna referensklocka måste ha ett exakt värde och vara stabil, en normal kristalloscillator är bra. Värdet är inte särskilt viktigt så länge det är en hög frekvens och dess värde är väl känt.

Efter en tid, säg några millisekunder, gör du D-ingången till D-flipfloppen låg igen. Vid nästa CLOCK-ingång följer utgången Q ingångstillståndet, men inget annat händer eftersom mikrokontrollern är inställd på att reagera på endast en RISING-signal. Efter att mättiden är över (ca 1 sekund) gör du D-ingången HÖG.

Återigen vid nästa CLOCK-ingång följer Q-utgången och denna RISING-signal triggar mikrostyrenheten, denna gång för att avsluta räkningen av båda räknarna.

Resultatet är två nummer. Det första talet är antalet pulser som räknas från referensen. Som vi känner till referensfrekvensen vet vi också hur lång tid det tog att räkna dessa pulser.

Den andra siffran är antalet pulser från insignalen vi mäter. När vi började exakt på RISING -kanterna för denna signal är vi mycket säkra på antalet pulser för denna insignal.

Nu är det bara en beräkning för att bestämma insignalens frekvens.

Ett exempel, låt oss säga att vi har dessa signaler och vi vill mäta f-ingång. Referensen är 10 MHz, genererad av en kvartskristalloscillator. f_input = 31.416 Hz f_reference = 10000000 Hz (10 MHz), mättiden är ca. 1 sekund

Under denna tid räknade vi 32 pulser. Nu tar en period av denna signal 1 / 31,416 = 31830,9 uS. Så 32 perioder tog oss 1,0185892 sekunder, vilket är drygt 1 sekund.

I denna 1.0186 sekund kommer vi också att ha räknat 10185892 pulser av referenssignalen.

Detta ger oss följande information: input_count = 32 reference_count = 10185892 f_reference = 10000000 Hz

Formeln för att beräkna den resulterande frekvensen är följande: freq = (input_count * f_reference) / ref_count

I vårt exempel är det: f-input = (32 * 10000000) / 10185892 = 31,416 Hz

Och detta fungerar bra för såväl låga frekvenser som höga frekvenser, bara när insignalen kommer nära (eller till och med högre än) referensfrekvensen är det bättre att använda standard "gated" sätt att mäta. Men då kan vi också helt enkelt lägga till en frekvensdelare till insignalen eftersom denna ömsesidiga metod har samma upplösning för valfri frekvens (upp till referensen igen). Så oavsett om du mäter 100 kHz direkt dividerat med en extern 1000x divider, är upplösningen densamma.

Steg 3: Hårdvara och dess schematiska

Hårdvara och dess schematiska
Hårdvara och dess schematiska
Hårdvara och dess schematiska
Hårdvara och dess schematiska

Jag har gjort några av denna typ av frekvensräknare. För länge sedan gjorde jag en med en ATMEGA328 (samma styrenhet som det finns i en Arduino), senare med ARM -mikrokontroller från ST. Det senaste gjordes med en STM32F407 klockad på 168 MHz. Men nu undrade jag om jag gör samma sak med en * mycket * mindre. Jag valde en ATTINY2313, som bara har 2 kbyte FLASH -minne och 128 byte RAM. Displayen jag har är en MAX7219 med 8 sju segmentskärmar på den, dessa skärmar är tillgängliga på Ebay för bara 2 euro. En ATTINY2313 kan köpas för cirka 1,5 euro resten av delarna jag använde kostar bara cent per styck. Dyrast var nog projektlådan av plast. Senare bestämde jag mig för att få det att köra på ett litiumjonbatteri så jag behövde lägga till en (LDO) 3,3V spänningsstabilisator, en batteriladdningsmodul och själva batteriet. Detta ökar priset något, men jag antar att det kan byggas för mindre än 20 euro.

Steg 4: Koden

Koden
Koden
Koden
Koden

Koden skrevs i C med Atmel (Microchip) Studio 7 och programmerades in i ATTINY2313 med en OLIMEX AVR_ISP (klon?). Öppna (main.c) i zip -filen nedan om du vill följa beskrivningen här.

INITIALISERING

Först var ATTINY2313 inställd på att använda en extern kristall eftersom den interna RC-oscillatorn är värdelös för att mäta någonting. Jag använder en 10 MHz kristall som jag ställer in på rätt 10 000 000 Hz frekvens med en liten variabel kondensator. Initialiseringen tar hand om att ställa in portar på ingångar och utgångar, konfigurera timers och möjliggöra avbrott och initialisering av MAX7219. TIMER0 är inställt för att räkna en extern klocka, TIMER1 den interna klockan och även för att fånga värdet på räknaren vid ICP: s stigande kant, som kommer från D-flipfloppen.

Jag diskuterar huvudprogrammet sist, så nästa är avbrottsrutinerna.

TIMER0_OVF

Eftersom TIMER0 räknar upp till 255 (8 bitar) och sedan rullar över till 0 behöver vi ett avbrott för att räkna antalet överflöden. Det är allt TIMER0_OVF gör, bara räkna antalet överflöden. Senare kombineras detta nummer med värdet på själva räknaren.

TIMER1_OVF

TIMER1 kan räkna upp till 65536 (16 bitar), så avbrottet TIMER1_OVF räknar också antalet överflöden. Men det gör mer. Det minskar också från 152 till 0 vilket tar cirka 1 sekund och sedan ställer in en utgångsstift som går till flip-floppens D-ingång. Och det sista som görs i denna avbrottsrutin är att minska timeout-räknaren från 765 till 0, vilket tar cirka 5 sekunder.

TIMER1_CAPT

Detta är TIMER1_CAPT-avbrottet som utlöses varje gång D-flipfloppen skickar en signal till den stigande kanten av insignalen (enligt förklaringen ovan). Capture -logiken tar hand om att spara värdet på TIMER1 -räknaren i ögonblicket för inspelningen, den sparas liksom överflödesräknaren. Tyvärr har TIMER0 ingen inmatningsfångningsfunktion så här läses dess nuvarande värde och dess aktuella värde för överflödesräknaren. En meddelandevariabel är inställd på en för huvudprogrammet för att berätta att det är nya data.

Nästa är två funktioner för att styra MAX7219

SPI

Även om det finns ett Universal Serial Interface (USI) tillgängligt i chipet valde jag att inte använda det. MAX7219 -skärmen måste styras via SPI och det är möjligt med USI. Men bitbanging SPI är så enkelt att jag inte tog mig tid att göra det med USI.

MAX7219

Protokollet för att konfigurera MAX7219 är också ganska enkelt när du har läst bruksanvisningen. Den behöver ett 16 bitars värde för varje siffra som består av 8 bitar för siffran (1 till 8) följt av 8 bitar för det nummer som den behöver visa.

MAIN-PROG

Det sista är att förklara huvudprogrammet. Den körs i en oändlig slinga (medan (1)) men gör faktiskt bara något när det finns ett meddelande (1) från avbrottsrutinen eller när timeouträknaren har gått ner till noll (ingen insignal).

Det första du ska göra när det variabla meddelandet är inställt på ett är att återställa timeouträknaren, trots allt vet vi att det finns en signal närvarande. D-flip-floppen återställs för att göra den redo för nästa trigger som kommer efter mättiden (vänta en sekund).

De siffror som registreras i fångstavbrottet läggs till för att ge referensräkningen och ingångsfrekvensräkningen. (vi måste se till att referensen aldrig kan vara noll eftersom vi kommer att dela med den senare)

Därefter är en beräkning av den faktiska frekvensen. Jag vill verkligen inte använda flytande nummer på en mikrokontroller med bara 2 kbyte flash och bara 128 byte ram jag använder heltal. Men frekvenser kan vara som 314,159 Hz, med flera decimaler. Därför multiplicerar jag ingångsfrekvensen inte bara med referensfrekvensen utan också med en multiplikator och lägger sedan till ett tal till vart decimalpunkten ska gå. Dessa siffror blir väldigt mycket stora när du gör det. T.ex. med en ingång på 500 kHz, en referens på 10 MHz och en multiplikator på 100, ger detta 5 x 10^14, det är verkligen enormt! De kommer inte längre att passa in i ett 32 -bitars nummer så jag använder 64 -bitars nummer som kommer att gå hela vägen upp till 1,8 x 10^19 (som fungerar bra på en ATTINY2313)

Och det sista du ska göra är att skicka resultatet till MAX7219 -skärmen.

Koden kompileras till cirka 1600 byte, så den passar in i 2048 bytes flash som finns i ATTINY2313.

Säkringsregistren ska se ut så här:

UTÖKAD 0xFF

HÖG 0xDF

LÅG 0xBF

Steg 5: Noggrannhet och precision

Noggrannhet och precision
Noggrannhet och precision
Noggrannhet och precision
Noggrannhet och precision
Noggrannhet och precision
Noggrannhet och precision

Noggrannhet och precision är två separata djur. Precisionen här är sju siffror, vad den faktiska precisionen är beror på hårdvaran och kalibreringen. Jag kalibrerade 10 MHz (5 MHz på testpunkten) med en annan frekvensräknare som har en GPS -disciplinerad oscillator.

Och det fungerar ganska bra, den lägsta frekvensen jag försökte är 0,2 Hz, den högsta 2 MHz. Det är spot on. Över 2 MHz börjar regulatorn att förlora avbrott, inte riktigt förvånande när du vet att vid 2 MHz insignal genererar TIMER0 över 7800 avbrott per sekund. Och ATTINY2313 måste göra andra saker också, avbrotten från TIMER1, med ytterligare 150 avbrott per sekund och naturligtvis göra beräkningarna, styra displayen och D-flipflop. När du tittar på den faktiska enheten ser du att jag bara använder sju av de åtta siffrorna i displayen. Jag gör detta av flera skäl.

För det första är att beräkningen av ingångsfrekvensen är en division, den kommer nästan alltid att ha en återstod, som du inte ser eftersom det är en heltalsdelning. För det andra är att kvartskristalloscillatorn inte är temperaturstabiliserad.

Kondensatorerna som ställer in den på rätt 10 MHz är keramiska, mycket känsliga för temperaturförändringar. Sedan finns det det faktum att TIMER0 inte har inbyggd logik för fångst och att avbrottsfunktionerna alla tar lite tid att utföra sitt arbete. Jag tycker att sju siffror är bra nog ändå.

Rekommenderad: