Die bessere Option ist statt dessen einen Timer/Counter zählen zu lassen. Damit belastet man nicht das Interrupt-System und das Programm wird nicht ständig unterbrochen.
Das Prinzip ist hier erklärt:
http://www.atmel.com/Images/doc8365.pdf
Da steht "Frequency measurement from 10Hz to Timer_Clock_frequency/2.5"
Wenn das stimmt gehen bei 16 MHz bis zu 6,4 MHz. Habe ich aber mit so hohen Frequenzen noch nicht gemacht (nur unter 100kHz).
Jetzt hat man da auf dem Mega das Problem, dass idiotischerweise die meisten Takt-Pins der Timer nicht auf das Arduino-Board herausgeführt wurden:
http://arduino.cc/en/Hacking/PinMapping2560
Mit T0 zerschießt man sich millis() und delay() auf Timer0, also nimmt man am besten Timer5 mit T5 auf Pin 47.
Timer5 funktioniert sehr ähnlich wie der Timer1 der hier erklärt ist:
http://maxembedded.com/2011/06/28/avr-timers-timer1/
Hier gibt es eine Übersicht auf deutsch:
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer
Die Register und Flags sind auch im Datenblatt erklärt:
Einfach z.B. nach TCNT5, TIMSK5 und TCCR5B suchen
- Man verwendet hier auch den millis() Zähler von Timer0 um die Zeit zu zählen.
- Pin 47 ist T5 und damit der externe Takt von Timer5. Die Flanke wird über die Bits CS52, CS51 und CS50 (Clock Select) im TCCR5B Register ausgewählt. Hier wird man wohl 111 für die steigende Flanke nehmen.
- Wenn alle drei CS5n Bits 0 sind ist der Timer gestoppt. Das ist der Ausgangszustand
- im TIMSK5 Register den Overflow Interrupt mit TOIE5 aktivieren (anders als im Tutorial oben hat hier jeder Timer ein eigenes Masken und Flag Register, aber das merkt man nur an den Namen der Register). Dann kann man in ISR(TIMER5_OVF_vect) mitzählen ob der Timer überläuft, wenn mehr als 65535 Impulse eintreffen.
Dann macht man das:
1.) Timer/Counter Register TCNT5 und Overflow Variable auf 0 setzten
2.) Timer5 über das Timer/Counter Control Register B freigeben mit TCCR5B |= 0x07; //untere drei Bits auf 1
3.) mit millis() entsprechend warten
4.) Nach einer bestimmten Zeit Timer5 wieder über die CS Bits stoppen mit TCCR5B &= ~0x07;
5.) TCNT5 enthält die Anzahl der eingegangen Impulse. Diese muss man mit den Überlaufen verrechnen. Über die Torzeit kommt man dann an die Frequenz
Hört sich jetzt kompliziert an, aber ist auf der MaxEmbedded Seite oben alles erklärt, was die Register und deren Bits betrifft. Beispiel Code für die Initialisierung (da aber CS nicht setzen, da du extern taktest) und den Overflow-Interrupt (da braucht man nur das Inkrementieren der Variable) ist auch dabei. Ist zwar für den AVR allgemein (deshalb die ganze direkte Port-Adressierung) aber läuft so auch auf dem Arduino (aber statt main() und while(1) einfach loop() nehmen).
Der Unterschied ist, dass der Timer da ständig läuft und nach x Überläufen was gemacht wird. Bei dir willst du den Timer starten und anhalten und danach die Anzahl der Überlaufe und den Zählerstand auslesen. Der Unterschied im Code ist aber minimal.
Du musst dann nur noch über millis() die Torzeit hinzufügen.Dazu steht was in den App Notes:
If a frequency of 500kHz is to be measured, a gate time of 1ms would result in good use of the 16-bit timer/counter’s range.