Frequency Counter: 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.

Frequency Counter: Specification

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

Frequency Counter: Operation

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.

Frequency Counter: 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: 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.

Frequency Counter: Compilation

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

Frequency Counter: 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

Frequency Counter: Software

Frequency Counter: Project files

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.

Frequency Counter: Code Operation.

Frequency Counter: Action file

The main action takes place in this file: Frequency_counter_4MHz_7seg_tmr1.c

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 achieved 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 initialises 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.

Top of page

Frequency Counter; (7 seg.)
      Gate time Calculation
      Screen update rate
   Test routines
      Project files
         Brief description
      Code Operation.
         Action file


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

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.

Privacy Policy | Contact | About Me

Site Map | Terms of Use