Answering a question on another forum, I write an arduino sketch to measure frequency. Let's call it "GPS assisted" to get extra-precision.
Thought, someone could find it useful as well. Written for AtMega2560, though it would be easy to adapt code to any AtMega uCPU, arduino or similar. One condition apply, both pin Tn and ICPn has to be brought out to header. Arduino UNO, for example has Timer1, Mega2560 - Timer5, etc.
/*
Using Input Capture to extra-precise frequency measurements
on Arduino Mega2560.
GPS 1 PPS clock is supplied on pin 48 (ICP5).
(Ublox NEO-7M unit was tested.)
External signal is connected to pin 47 (T5).
Prints the result over Serial Monitor.
Commands:
1: activate printout - "d".
2: switch to internal clock - "i1".
3: switch to external clock - "i0".
Range 1 Hz <-> 6 MHz, (16 MHz if internal selected).
Released into the public domain.
Created by Anatoly Kuzmenko, April 2018
k_anatoly@hotmail.com
*/
String in_String = "";
boolean end_input = false;
uint8_t adres_reg = 0;
uint8_t debug_osm = 0;
volatile int32_t frequency = 0;
volatile uint8_t tmr_overf = 0;
volatile uint8_t f_capture = 0; // flag
void setup()
{
Serial.begin(115200);
in_String.reserve(200);
init_tmr5();
}
void loop()
{
int32_t tempr = 0;
char * pEnd;
if(debug_osm) {
if(f_capture) {
Serial.print(F("\n\tFreq: "));
Serial.print(frequency, DEC);
f_capture = 0;
}
}
serialEvent();
if( end_input) {
char cmd = in_String[0];
in_String[0] = '+';
if( cmd == 'd' ) {
debug_osm = 1 - debug_osm;
if(debug_osm) Serial.print(F("\nDebug aktiv."));
else Serial.print(F("\nDebug de-aktiv."));
}
if( cmd == 'i' ) {
tempr = strtol( in_String.c_str(), &pEnd, 10);
Serial.print(F("\n\tInput: "));
if(tempr) Serial.print(F("internal 16 MHz."));
else Serial.print(F("external pin-D5."));
input_clock(tempr);
}
in_String = "";
end_input= false;
}
}
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
in_String += inChar;
if (inChar == '\n') {
end_input= true;
}
}
}
Timer5 Tab:
void input_clock(uint8_t inp)
{
if(inp) {
TCCR5B &= ~(1<<CS52); // internal
TCCR5B &= ~(1<<CS51);
TCCR5B |= (1<<CS50);
}
else {
TCCR5B |= (1<<CS52); // external clock
TCCR5B |= (1<<CS51);
TCCR5B |= (1<<CS50);
}
}
void init_tmr5(void)
{
TCCR5A = 0;
TCCR5B = 0;
TCCR5B |= (1<<CS50); // set prescaler to 16 MHz
TCCR5B |= (1<<ICNC5); // input noise canceler on
TCCR5B |= (1<<ICES5); // input capture edge select
TIMSK5 |= (1<<TOIE5); // Overflow Interrupt Enable
TIMSK5 |= (1<<ICIE5);
}
ISR(TIMER5_OVF_vect) {
tmr_overf++;
}
ISR(TIMER5_CAPT_vect) {
static uint16_t last_v = 0;
uint16_t curr_v = ICR5;
if((TIFR5 & (1<<TOV5)) && (curr_v < 0x7F)) {
tmr_overf++;
TIFR5 |= (1<<TOV5);
}
frequency = curr_v + tmr_overf *65536UL;
frequency -= last_v;
last_v = curr_v;
tmr_overf = 0;
f_capture = 1;
}