Here is an improved version of the frequency counter sketch. There were a couple of problems with the previous version:
-
when you attach the interrupt, you can get an immediate interrupt if this input is already high. This resulted in some jitter in the frequency reading. So I now ignore the first interrupt.
-
if the pulse count (i.e. frequency multiplied by the sample time in seconds) was greater than about 4000 then the calculation would overflow. So I have changed it to use floating point calculation instead. This also give a more precise result when the number of cycles counted is low.
// Frequency counter sketch, for measuring frequencies low enough to execute an interrupt for each cycle
// Connect the frequency source to the INT0 pin (digital pin 2 on an Arduino Uno)
volatile unsigned long firstPulseTime;
volatile unsigned long lastPulseTime;
volatile unsigned long numPulses;
void isr()
{
unsigned long now = micros();
if (numPulses == 1)
{
firstPulseTime = now;
}
else
{
lastPulseTime = now;
}
++numPulses;
}
void setup()
{
Serial.begin(19200); // this is here so that we can print the result
pinMode(3, OUTPUT); // put a PWM signal on pin 3, then we can connect pin 3 to pin 2 to test the counter
analogWrite(3, 128);
}
// Measure the frequency over the specified sample time in milliseconds, returning the frequency in Hz
float readFrequency(unsigned int sampleTime)
{
numPulses = 0; // prime the system to start a new reading
attachInterrupt(0, isr, RISING); // enable the interrupt
delay(sampleTime);
detachInterrupt(0);
return (numPulses < 3) ? 0 : (1000000.0 * (float)(numPulses - 2))/(float)(lastPulseTime - firstPulseTime);
}
void loop()
{
float freq = readFrequency(1000);
Serial.println(freq);
delay(1000);
}