Measuring frequency with Arduino

There are many signals that contain necessary information in frequency. For instance, SparkFun's HH100D humidity sensor outputs measurements via frequency signal (although it has i2C interface, those pins are used for reading calibration values. Actual measurements com via FOUT line).

There are two ways to measure a frequency with Arduino:

Using FreqCounter library. It can measure frequencies up to several MHz, and is very precise. However, measurement pin is fixed to digital pin 5. Also it may affect Arduino PWM outputs, increasing their duty cycles. In case you don't use PWM and you need to measure frequency of just one signal, FreqCounter is an excellent choice

Using pulseIn() function from standard Arduino libraries. The technique I'm suggesting below is free from FreqCounter limitations, so you can use it on any pin. However, it's minimal wave period is 10 uS, with corresponding maximum measurable frequency of 50 kHz

PulseIn function returns the length of the pulse (in microseconds) or 0 if no pulse started before the timeout. To get the frequency you can use f = 1 / T equation, however, that depends on duty cycle of the signal.

We suggest that we have a square wave with 50% duty cycle, and measure the length of the pulse by using pulseIn function. Then we will multiply that value for 2 to obtain signal period: (the distance between red lines on the image):

To get frequency in Hz for a 50% square wave you can use

freq = 500000/pulseIn(5, LOW);

Notice the value of 500 000 uS instead of 1 000 000 uS (= 1 second), because I need to use signal's period (T) in the formula, not pulse length(tpulse) that pulseIn returns.With duty cycle of 50% signal period will be T = 2*tpulse, so the formula will finally look like f = 1second / ( 2*tpulsemicroseconds) = 500 000 microseconds / tpulse = f Hertz

However, using pulseIn has several peculiarities that you need to consider.

The first one is the necessity of obtaining average values.

Most people usually take only one measurement with pulseIn() function. In many cases, frequency is not very stable, so we need to calculate an average value over time.

Something like 1024 samples will be enough, however, for better results, you may increase the value - even up to 20-30k samples (however, in case with HH100D sensor, there's almost no difference in frequency for 4096 and 32767 samples).

We wait for the pulse to occur in 250 mS. If you are using very slow signals, increase this value as you need. (pin, HIGH, 250000)

The second peculiarity is lesser precision than FreqCounter library can provide.

I recommend using FreqCounter, and switch to pulseIn only in cases when FreqCounter is unavailable. As an alternative, you can increase accuracy of you pulseIn measurements even more. Read this article to learn how to do this.