Measuring the Frequency of a TTL circuit

Here is freq counter we use for DCDW, its speed is determined by the incoming freq and the number of digits of precision you specify. It also has code to reject noisy signals. Probably slower than you want and too many features, but you might find the autoscaling approach useful. There is a fundamental limit on precision vs measurement rate and this is one way to approach it.

long countFrequency (int pin, int precision)  
{
// counts frequency of an incoming pulse train
// this code is licensed under Creative Commons Attribution-ShareAlike
//
// pin              any digital input pin (int)
// precision        number of significant digits, 2, 3 or 4 (int)
// returns:         frequency in Hz (long)
//
// written for Dirt Cheep Dumb Wireless sensor telemetry boards
// using OOK radio links (SparkFun etc) which output noise on no RF in
// so this looks for consistent pulse width as criterion against noise
// returns negative numbers for all errors such as noise
//
  int pulses;                   // total number of pulses to time 
  int pulse;                    // pulse count
  unsigned long timeout= 10000; // microsecs for pulseIn() to wait before giving up
  unsigned long t0;             // start time hack
  unsigned long time;           // delay in millisec
  unsigned long needTime = 1;   // delay needed for precision in millisec
  unsigned long duration;       // length of one pulse 
  unsigned long totDuration;    // total duration of first ten pulses 
  unsigned long minDuration;    // minimum length of a valid pulse 
  unsigned long maxDuration;    // maximum length of a valid pulse 
  constrain (precision, 1, 5);                 // keepin it sane
  for (int i = 1; i < precision; i++) {
    needTime = needTime * 10;
  }  // millisecs of tone count needed to get desired precision
  long DCDWfrequency = 0;                      // nothin' yet
  totDuration = 0;                             // clear this to start
  for(pulse = 0; pulse < 10; pulse += 1)       // count 10 incoming pulses 
  {                                   
    duration = pulseIn(pin, LOW, timeout);     // wait for one complete pulse cycle
    if (duration == 0) {
      return -(long)pulse;
    }  // if pulse timout then abort, return neg of bad pulse
    totDuration += duration;
  } 
  maxDuration = totDuration / 7;
  minDuration = totDuration / 14;
  // now we have a range of average pulse durations
  // so start counting 'pulses' pulses, increasing 'pulses' by 10x each time
  // until a string of pulses meets the minimum total time for accuracy
  for (pulses = 10; pulses < 100000; pulses = pulses * 10)
  {
    DCDWfrequency = 0;                           // nothin' yet
    t0 = millis();                               // start time
    for(pulse = 0; pulse < pulses; pulse += 1)   // count incoming pulses 
    {                                   
      duration = pulseIn(pin, LOW, timeout);     // wait for one complete pulse cycle
      if (duration == 0) {
        return -(long)pulse;
      }    // pulse timout: abort, return neg of bad pulse
      if (duration > maxDuration)                  // pulse too long: abort, return error code
      {
        return -(long)duration;
      }
      if (duration < minDuration) 
      {
        return -(long)duration;
      }
    } 
    time = millis()-t0;                          // got all pulses, so time = now - start

    if (time > needTime)                              // if time is enough for precision we are done
    {
      if (debug)
      {
        Serial.print(precision);  
        Serial.print(" digits ");  
        Serial.print(needTime);  
        Serial.println(" ms need:   ");  
        Serial.print(pulses);  
        Serial.print(" pulses = ");  
        Serial.print(time);  
        Serial.println(" millisecs ");  
      }
      DCDWfrequency = 1000 * (unsigned long)pulses / time;  // frequency in Hz
      return (long)DCDWfrequency; 
    }
  }
  return -9999;
}