Jeg har genopvasket nogle eksisterende biblioteker, jeg fandt på nogle uklare fora for at måle en frekvens på digital pin 5 ved hjælp af ATmega328P / ATmega2560 Timer / Counter-moduler og en afbrydelsesbaseret tilgang for at kunne måle frekvenser op til 4MHz (-ish). Men ved hjælp af koden beskrevet nedenfor er resultaterne slukket med en faktor på nøjagtigt 100. Jeg brugte en frekvensgenerator til at udføre disse aflæsninger. Her er et eksempel på, hvad jeg har fået tilbage, når jeg genererer en 5000Hz firkantbølge (50% arbejdscyklus):
Kan nogen skal du påpege, hvad der kan være galt. Jeg har læst ATmega328P datablad flere gange nu, og det skal bare fungere! Dette er meget mærkeligt.
Rediger: Da det viser sig, at AWG, jeg bruger, har en blantant softwarefejl, der får den til at generere en bølge med en periode, der er 100 gange for længe (se billedet nedenfor). Ikke desto mindre, som Edgar påpegede, lavede jeg nogle ret store fejl ved ikke at tage højde for race betingelser. Derfor er nedenstående kode blevet opdateret. Testprogrammet er også opdateret til at generere en 50% duty cycle firkantbølge @ 5000Hz til testformål som foreslået af Edgar.
Dette er headerfilen:
#ifndef FreqCounter_h # define FreqCounter_h #include <avr / interrupt.h> # hvis defineret (ARDUINO) && ARDUINO > = 100 # inkluderer "Arduino.h" # else # inkluderer "WProgram.h" #endifnamespace FreqCounter; ekstern flygtig usigneret char f_ready; ekstern flygtig usigneret char f_mlt; ekstern flygtig usigneret int f_tics; ekstern flygtig usigneret int f_period; ugyldig start (int ms);} # endif
Dette er kildefilen:
#include <FreqCounter.h>volatile usigneret lang FreqCounter :: f_freq; flygtig usigneret char FreqCounter :: f_ready; flygtig usigneret char FreqCounter :: f_mlt;
flygtig usigneret int FreqCounter :: f_tics; flygtig usigneret int FreqCounter :: f_period; ugyldig FreqCounter :: start (int ms) {f_period = ms; GTCCR = (1<<TSM) | (1<<PSRASY) | (1<<PSRSYNC); // standse alle timere // sæt TC1 til normal tilstand = > TOV1-flag indstillet til TOP = 0xFFFF TCCR1A & = 0x00; // nulstil TC1 kontrolregister A TCCR1B & = 0x00; // nulstil TC1-kontrolregister B // indstil TC1 til at bruge ekstern urkilde, klokket på stigende kant TCCR1B | = (1<<CS10); TCCR1B | = (1<<CS11); TCCR1B | = (1<<CS12); // nulstil TC2 TCCR2A & = 0x00; // nulstil TC2-kontrolregister A TCCR2B & = 0x00; // nulstil TC2-kontrolregister B // sæt TC2 til CTC-tilstand med TOP = OCR2A = >-tæller ryddet, når TOP TCCR2A er nået | = (1<<WGM21); // TC2 er i CTC-tilstand = >-indstillingsværdi for OCR2A = TOP OCR2A = 124; // TOP nås hvert 125 tæller (startende fra 0) // indstil TC2 til at bruge en forudskaler på 1 = > 16MHz / 128 = 125kHz TCCR2B | = (1<<CS20); TCCR2B | = (1<<CS22); f_ready = 0; // nulstil klar flag f_tics = 0; // nulstil TC2-afbrydertæller // synkroniser værdien af begge timere TCNT2 = 0; TCNT1 = 0; // ryd afbrydelsesflag TIFR2 | = (1<<OCF2A); TIFR1 | = (1<<TOV1); TIMSK2 | = (1<<OCIE2A); // aktiver TC2 Output Sammenlign En afbrydelse = > udløst ved at nå TOP = OCR2A TIMSK1 | = (1<<TOIE1); // aktiver TC1 overløbsinterrupt = > udløst ved at nå TOP = MAX = 0xFFFF GTCCR & = 0x00; // genstart alle timere = > start optælling} / * * Denne ISR udløses af TC2 hver 1ms, fordi * TC2 trin med en frekvens på 16MHz / 128 = 125KHz
* og når TOP hvert 125 tæller * = > trigger frekvens = 1kHz * = > trigger periode = 1ms * * Denne ISR håndterer Gate Time generation * / ISR (TIMER2_COMPA_vect) {// trin antal TC2 interrupts (udløser når TOP = OCR2A) FreqCounter :: f_tics ++; / * * Hvis gren evalueres som sand, hvis givet gate-tid (f_period) er lig med * mængden af millisekunder TC2 er talt (= f_tics) * / if (FreqCounter :: f_tics > = FreqCounter :: f_period) {// slutning af gate tid = > måling klar TCCR1B & = ~ 0x07; // sæt TC1 til ingen clk-kilde = > TC1 holder op med at tælle TIMSK2 & = ~ (1<<OCIE2A); // deaktiver TC2 Output Sammenlign En afbrydelse TIMSK1 & = ~ (1<<TOIE1); // deaktiver TC1 overløb afbryd FreqCounter :: f_ready = 1; // sæt softwareflag til slutningen af gatingperioden // inkrement ved overløb af TCNT1 hvis (bit_is_set (TIFR1, TOV1)) FreqCounter :: f_mlt ++; // beregne frekvens FreqCounter :: f_freq = 65536 * FreqCounter :: f_mlt; FreqCounter :: f_freq + = TCNT1; // tilføj værdi af TC1 FreqCounter :: f_freq = (lang) (FreqCounter :: f_freq * 1000.0 / (dobbelt) FreqCounter :: f_tics); FreqCounter :: f_mlt = 0; }} ISR (TIMER1_OVF_vect) {FreqCounter :: f_mlt ++;}
Dette er testprogrammet:
#include <FreqCounter.h>long frq; ugyldig opsætning ( ) {// generere en firkantbølge på 5 kHz på OC0B = digital pin 5 = T1 DDRD | = _BV (PD5); // PD5 = OC0B som output TCCR0B = 0; // stop-timer TIMSK0 = 0; // deaktiver overløbsafbrydelse OCR0A = 50 - 1; // periode = 50 * 64 cyklusser OCR0B = 50 / 2-1; // 50% arbejdscyklus TCCR0A = _BV (COM0B1) // ikke-inverterende PWM på OC0B | _BV (WGM00) // hurtig PWM, TOP = OCR0A | _BV (WGM01); //...ditto TCCR0B = _BV (WGM02) //...ditto | _BV (CS00) // ur ved F_CPU / 64 | _BV (CS01); //...ditto
Serial.begin (57600); Serial.println ("Frequency Counter");} ugyldig loop () {FreqCounter :: start (1000); mens (FreqCounter :: f_ready == 0); frq = FreqCounter :: f_freq; Serial.println (frq);}
PS: Dette er mit første indlæg nogensinde på dette forum. Du er velkommen til at kommentere indholdet af mit spørgsmål. Tips til, hvordan jeg kan forbedre fremtidige spørgsmål, er altid velkomne. Hav en dejlig dag!