Become a subscriber (Free)

Join 29,000 other subscribers to receive subscriber sale discounts and other free resources.
Don't worry -- your e-mail address is totally secure. I promise to use it only to send you MicroZine.

Schematics and C code for a PIC frequency counter circuit operating up to about 50MHz

This PIC frequency counter circuit uses a multiplexed seven segment display to provide 8 digits and uses timer 1 to count edges of the input signal and Timer 0 to count time.

It uses the simpler method of direct frequency measurement which means that the input event (for which you want to obtain a frequency reading) is used to directly increment a counter (inside the PIC).

The other way of making a frequency counter is reciprocal counting which uses a rising edge event to trigger a counter and stops the counter on a falling edge.

The direct counting method means that the number of digits displayed depends on the input so for a 1Hz input, the digit 1 is displayed indicating a frequency of 1Hz. Reciprocal counting displays more digits for more resolution at lower frequency i.e. it can display fractions of a Hertz. However, for basic use the frequency counter shown here is extremely useful.

In the same way as the LCD counter project this frequency counter circuit uses TMR1 in 16 bit counter mode to count the input signal edges. Counter overflows are accumulated to give the total count in multiples of 65536. Adding the current value of the counter at the end gives the total count. In addition Timer 0 is used to obtain an accurate period of 1 second by counting 1e6 clock edges (Fsoc/4=1MHz) where the main clock frequency is set by a crystal resonant at 4MHz.

The other problem with 7 segment displays is that they must be updated approximately every 20ms for your eye to be fooled into seeing a continuous display so part of the Timer 0 counting goes into doing 7 segment display refresh. Normally you would use a TTL chip that does the refreshing for you (75LS47 or CMOS 4511) but the design here does it all.

The complicated bit is that the interrupt routine must be small so that the count is captured correctly while still allowing display refresh.

Specification of the frequency counter circuit

Min frequency 1Hz
Max frequency ~50MHz (limited by input pin characteristics).
Input signal level TTL

Gate time Calculation

To create a capture time of 1 second requires counting the internal clock (Fosc/4=4e6/4), and as before we use Timer0. To do this we need to use the interrupts generated when an overflow of the counter occurs.

Main clock processing period time = Fosc/4 = (1/(4e6/4)) = 1e-6 = 1us

To get to 1 second we need 1/(Fosc/4) counts = 1/ 1e-6 = 1e6

Timer 0 counter overflows every 256 counts.

Since the overflow occurs every time that the counter passes 256 we need to count 1e6/256 overflows1e6/256 = 3906.25

The extra 0.25 indicates 64 cycles are required before the last interrupt fires see the

lcd project calculations as it is exactly the same in operation.

Screen update rate

Just as in the LCD project the measurement time is 1 second the final count is actually the frequency of the input signal and again using the 1 second measurement time gives a frequency resolution of 1 Hz.

Note: The exact maximum operating frequency is determined by the PIC input pin characteristic.

Compiler Mikroelectronika MikroC Compiler Free!
Target 16F877A (retargetable to other PICs that have TMR1)
Software level Advanced.
Software notes Constant time code.
Hardware level Intermediate
Hardware notes Seven segment multiplexing.
Project version 1.04
Project files Enter your details to get the Download Link
and get the microcontroller newsletter:


(Note: Your email is safe it will never be sold or rented).
You will get All theC source code and hex file.

Note: Check your email for the project code download link.

Frequency counter circuit Test routines

Once constructed you can test the wiring out using the following two files e.g. if the 1st download file does not appear to work:

These tests will also test out a system using individual 7 segment displays.

Frequency counter circuit:Test wiring 1 Download here.
Frequency counter circuit:Test wiring 2 Download here.

Test wiring 1 : Outputs constant digits to the display and reads "12345678" from left to right.  You can use this test to see if PORTD and each transistor driver is connected correctly.

Test wiring 2 : Outputs a shifted digit set from 1-8 to test PORTD connections to each 7 segment.  Just observe each digit and make sure it goes through each number 1 to 8.


For a tutorial on compiling these files click here.

You can recompile the frequency counter circuit files if you want examine code operation (using the built in simulator) or change the source code. Note the hex file is contained in the download.

For the general theory of operation of this circuit and notes on frequency counting for this frequency counter circuit click here.

PIC frequency counter circuit using 7 segment displays, TMR0 and TMR1.
(Click diagram to open a pdf).
7segment display frequency counter

PIC frequency counter circuit Hardware

The main circuit blocks of the frequency counter circuit are shown in the diagram below.

The 8 seven segment displays are multiplexed using a Johnson counter (4017) that activates a single output after each clock pulse. Port A drives the reset line and clock signal to the 4017 and transistors at the outputs of the 4017 are connected to the common cathode of each seven segment display. This lets the micro turn on each display sequentially. Port D drives the segment enable lines to control the character displayed.

The crystal oscillator is simply a crystal and two capacitors connected to the PIC oscillator port at OSC1 and OSC2. The capacitors can both be fixed unless you want to tune it using a frequency reference. If you don't have an accurate reference then use fixed capacitors.

The PIC micro can be any type that has Timer 0 and Timer 1 hardware and and has enough memory to hold the program and enough ports to drive the 4017 and the segment enable lines (8 bits).

The LED is toggled at the end of every gate time to indicate that the processor is alive - so if there is no input signal you can tell that the software is working.

You can program the PIC in circuit through the ICSP connector.

frequency counter schematic circuit

Learn about the tool used for creating this diagram.

PIC frequency counter circuit Software

Project files for the PIC frequency counter circuit

Compiler project files

C Source files.

Header files.

Output files

Brief description

  • Frequency_counter.c : contains the code start point (in routine 'main').
  • sevensegment.c : Seven segment refresh update routines.
  • ltoa.c converts a long word to ascii (a string).
  • bit.h : macros for bit manipulation.

All other header files contain prototypes.

PIC frequency counter circuit code operation.


This file contains the port initialization, interrupt_initialisation, main and interrupt functions.

After initialisation the code enters an endless loop where it continuously waits for update flags that are set in the interrupt routine. So in actual fact the main part of the system is not contained in "main" but in the interrupt() code.

init_ports() - Sets up port directions

init_interrupts() - Sets up Timer 0 and Timer 1 controls.

start_timer_count() - Restarts Timer 0 and 1 counts from zero and starts interrupts again.

interrupt() - Accepts and acts on interrupt events.

main() - Initialises code and enters an endless loop reacting to update flags.

Function: main

This routine is the entry point for the program and calls all initialisation functions then starts the interrupt routine and enters an endless loop waiting the the flag: 'update_display'.

When the flag is set it takes the stored timer values and calculates the total stored time. If this is non-zero it is converted to a string placed into array 'op'. This array is used by the sevensegment.c code in updating the 7 segment displays.

If the calculated value is zero then zeros are put into array 'op' for display instead.

Function: interrupt

This routine contains the main operation of the counter. As discussed Timer 1 counts events by increasing TMR1_counter for every input event (edge)'

Timer 0 counts time increasing every Fosc/4 edge.

Interrupts are generated for Timer 0 overflow (256 * (1/(Fosc/4.))) and as discussed previously the number of Timer 0 overflows that gets close to 1 second is 3906.

At this point the flag do_TMR0_end_count is set indicating to the Timer 0 interrupt service routine that the next count will be the last. At this point Timer 0 is adjusted for an overflow count of 64 Fosc/4 periods and when the interrupt fires variables are updated (prefixed with the letters 'st_'). At this point the complete 1 second time has expired and update of the display is required. This is acheived by setting the flag update_display. The routine main then reacts to this flag after the interrupt has finished.

The last thing the Timer 0 interrupt does is to call the display refresh routine display_str_8seg7 every 19 Timer 0 overflows (see sevensegment.c for details).


This file has the 8 digit seven segment display driver.

The first output from the 4017 is not connected so this acts as the reset state. At every call the next digit is output on port D and the 4017 is advanced one bit by strobing the clock. In this way after each call the next digit is displayed.

Function: init_display_str_8seg7 -

This routine nitialises the hardware and index counter to a known state.

Function: display_str_8seg7

The routine is deliberately small and does not output all the digits at once since it is directly called from the interrupt routine i.e. it is part of the interrupt routine. At each call of this routine the next digit is output with the next digit selected by incrementing idx (the scope of the variable idx within file sevensegment.c so nothing else can see or alter it).

This means that the routine is not taking too long so that other interrupts can be serviced.

The actual call rate in the interrupt is when Timer 0 has overflowed 19 times and it is also the last thing that the interrupt code looks at since it is not as important as capturing frequency events or counting time. This number is:

19*256*Fosc/4 = 19*256*1e-6 = 0.0049s ~ 5ms

So all 8 digits are updated at about 5ms*8 = 40ms which is 25Hz.

It was found by experiment but is the repeat rate that you would expect .


This is a public domain conversion of a long word to ascii output.

It could be made more efficient but allows use of any number base.


This contains macros for bit manipulation which should be compiler independent.

End of code description for the frequency counter circuit.

New! Comments

Have your say about what you just read! Leave me a comment in the box below.

Claim Your: Useful

"Arduino Software Guide"

   Right Now...

Jump from frequency counter circuit
to Best Microcontroller Projects Home Page. 

Privacy Policy | Contact | About Me

Site Map | Terms of Use

Visit our Facebook Page:

   Click Here

Recent Articles

  1. Using the MAX6675 or How to easily measure Extreme temperatures

    How to use the MAX6675 and an Arduino to measure temperatures from 0°C to 1024°C with two components: A chip - the MAX6675, and a Sensor: - a type-K thermocouple.

    Read more

  2. How to use the DHT22 (or DHT11) with an Arduino; full code and description. Also including a comparison of the DHT11 vs DHT22.

    The Essential Guide to the DHT22/11 humidity sensor including a library code guide for the Arduino. Learn how to determine Humidity, Dew point and Heat Index.

    Read more

  3. How to Use the MAX7219 to drive an 8x8 LED display Matrix on the Arduino.

    The Essential Guide to the MAX7219; What it is and how you can easily use one in any of your projects.

    Read more

Sign up for MicroZine
''The'' Microcontroller Newsletter

Enter your first Name and primary email address in the form below:

And receive absolutely FREE a full project for:

"Measuring Analogue Voltages
Without An ADC"

(Using only one pin).

Instant Download:
You Can
Get It Right Now

Warning: This project could be  Removed 
at any time.  

It will  NOT be 
available indefinitely SO
To avoid 
disappointment  get it:


Don't worry -- your e-mail address is totally secure. I promise to use it only to send you MicroZine
Remember this is a project with full description and fully debugged C Source code - and it's not available from the main website.

You can only get it through this newsletter.

To get exclusive access Enter your first name Name and primary email address Now in the form above.:

But wait !

There's more...

You'll receive more
free and exclusive reports as well as site information and site product updates

Scroll up to the form above and sign up NOW. Don't forget it's FREE and if you don't like it, you can unsubscribe at any time.

Click Here Now to use the form above to get your Valuable information absolutely free.

Readers Comments

"I wanted to thank
you so so so much
for all the information
you have provided in
your site it's


- Ranish Pottath

"This site really is
the best and my favorite.
I find here many useful
projects and tips."

- Milan


"Awesome site,
very, very easy and nice
to navigate!"

- Matt

Learn Microcontrollers

"Interested in

Sign up for The
Free 7 day guide:


"I am a newbie to PIC
and I wanted to say
 how great your
site has been for me."

- Dave


"Your site is a great
and perfect work.

- Suresh


"I couldn't find the correct
words to define
yourweb site.

Very useful, uncovered,
honest and clear.

Thanks so much for
your time and works.

- Anon