Sunday, 25 May 2014

Improved Arduino Frequency Counter

This is an old post, preserved for reference.
The products and services mentioned within are no longer available.

I built a Simple Arduino Frequency Counter last year, and it's been quite a useful project. Over the time it's been in use, I've been tinkering with it to improve the display and accuracy. This started off with a simple display of the frequency in Hz. I modified the code slightly to add some commas to make it easier to read:
That's how it stayed for a while. I'm now building a signal generator, and I thought it would be good to include this on the front panel, so I tidied the layout further and added a display of the signal period (1 / frequency).
I had noticed it seemed to read a little low, so I revisited the code to improve performance. The original worked by setting up an internal counter to count pulses coming into one of the pins. It waited one second, then read the counter. The count was taken as the frequency, the display was updated and the counter reset. I've now gone for a different mechanism, an interrupt driven approach, similar to that in this forum post.

I've altered that slightly, and now what it does is enable an interrupt on change on a pin. When that is triggered, it stores the start time. It then changes the interrupt to go to a different routine, and when that is called, counts pulses and stores the time of the last pulse. It then waits one second again and calculates the frequency, based on the time between the first and last pulse, to improve accuracy. As per the follow up to that forum post, I've taken into account ignoring the initial isr call as this may happen if the pin is high when the interrupt is enabled. I've done this with a third isr, again trying to keep the code in there down. The new code can be downloaded here.
The circuit remains very simple, basically connect the input to pin 2 (interrupt 0), and connect an LCD display however is most convenient, and alter the setup call to the standard Liquid Crystal library as appropriate. On breadboard, I used the pins nearest the display.
When transferred to a circuit board, all that is required is the ATMega328P, 16MHz crystal and 22pF caps, some 100nF decoupling caps and a main 47uF cap. The 10K multiturn pot is LCD contrast, overkill for what is required, but it fits neatly with the layout.
Add connectors for power, signal and the LCD. I used two 6 pin connectors as the central 4 pins of the LCD are unused. Again, these are wired using the  nearest and most convenient pins. The R/W pin is optional as it is always pulled low, but again for convenience, I connected that to a pin on the boarded version. The 6 pin 'stackable' connectors are used for arduino shields, but are ideal here as the long pins can be bent to make contact with the ATmega328P, reducing the amount of wiring to very little, mainly point to point using component leads.
I programmed the ATmega328P using the Arudino IDE and 'upload with programmer' and my trusty USBTinyISP. Then just install the LCD module, a standard HDD44780 based 16X2 LCD (in this case white on blue for a change) and connect up an input.
There is no input protection here, as it is intended to be used where the input is coming from a TTL chip in the same piece of equipment, using the same power supply. If you plan to use this with an external input, some protection and buffering would be required. This is left as an exercise for the reader.