Frequency counter innacuracy

I'm working on a frequency counter, which is integrated into a larger program that tests several other aspects of a circuit. The frequency I'm testing for is 512 Hz, and it functions fine for the most part, but intermittently it will spit out a high value, which seems to be consistently 2Hz above the actual frequency (512Hz becomes 514Hz). I run each test sequentially as separate functions, so I don't believe they are interfering with each other. The error seems to occur most often when I leave the tester (the Arduino) running for a long period of time, and it will happen for several iterations then go back to correct operation. I've checked the frequency of the device I'm testing with an oscilloscope and it is still 512 Hz, not 514 Hz. Anyone have an idea why this would occur?

my code:

float test_Freq()
{
  float sum = 0;
  int count = 0;
  
  CAPStartTime = 0;
  CAPEndTime=0;
  CAPDuration=0;
  
  while (count < 500)
  {
    
    while(digitalRead(CAP) != LOW){}                   // Wait for falling edge
    while(digitalRead(CAP) != HIGH){}                  // Wait for rising edge
    noInterrupts();
    CAPStartTime = float(micros());
    interrupts();
    while(digitalRead(CAP) != LOW){}                   // Wait for Rising edge
    while(digitalRead(CAP) != HIGH){}                  // Wait for Rising edge
    noInterrupts();
    CAPEndTime = float(micros());
    interrupts();
    CAPDuration = CAPEndTime - CAPStartTime;
    sum = sum + (1000000 / CAPDuration);
    count++;
  }
  return(sum/500);
   
}

Not that I've initialized the CAP variables globally and didn't include them in this.

What I would check:

As sum is a float with only few bits of precission there may be rounding error's. Is it possible to use an unsigned long for these calculations, it is more precise and has no rounding errors. (OK overflow may occur).

CAPStartTime = float(micros());

maybe use unsigned longs here too. As micro will overflow every 70 minutes - http://www.arduino.cc/en/Reference/Micros - the float representation will also, you don't gain anything by using floats.

Using unsigend longs will make the code faster too as the math is simpler.

Further check the pulseIn() command - http://www.arduino.cc/en/Reference/PulseIn - as this is what I recognize in your code. You might dive into its source too!

Finally keep the comments and code in sync :wink:

float test_Freq()
{
  #define SAMPLES 500

  unsigned long sum = 0;
  int count = 0;
  
  unsigned long CAPStartTime = 0;
  unsigned long CAPEndTime = 0;
  unsigned long CAPDuration = 0;
  
  while (count < SAMPLES )
  {
    
    while(digitalRead(CAP) != LOW);                   // Wait for falling edge
    while(digitalRead(CAP) != HIGH);                  // Wait for rising edge
    noInterrupts();
    CAPStartTime = micros();
    interrupts();
    while(digitalRead(CAP) != LOW);                   // Wait for [glow]FALLING [/glow]edge
    while(digitalRead(CAP) != HIGH);                  // Wait for Rising edge
    noInterrupts();
    CAPEndTime = micros();
    interrupts();
    if (CAPEndTime < CAPStartTime)
    {
       // there is an overflow detected ...
    }
    CAPDuration = CAPEndTime - CAPStartTime;
    sum = sum + (1000000 / CAPDuration);
    count++;
  }
  return(((float)sum)/SAMPLES );  // finally make it a float 
}