Introduction: Frequency Detector Using PIC 12F683 Processor

Picture of Frequency Detector Using PIC 12F683 Processor

This project describes hardware and software I have developed which allows a small 8 bit PIC microprocessor to function as a single frequency detector or tone decoder. 

Such a circuit can be used to detect the presence of a certain frequency within an analog signal, such as an audio signal.  I could be used in remote control applications, or to detect musical notes, or for any other situation where a specific frequency must be detected in a signal that may contain other frequencies or noise.

The circuit is based an 8 pin PIC 12F683 microprocessor. Only a few additional resistors and capacitors are needed to complete a circuit that will accept an analog signal and drive a microprocessor output pin high when the selected frequency is present in the signal.  The circuit can be used as a frequecy detector IC that is part of some larger circuit of the users design.

The steps that follow detail the operation of the circuit and the program that runs on the processor. A description of the digital signal processing algorithm used by the PIC is included, but it is not necessary to understand it to make use of this circuit.

The code for programming the processor is included as a *.hex file. The source code *.asm file is also provided, to allow a user that is familiar with the Microchip PIC assembly language to modify the program. These files can be found under the step titled “Source Code”.

The operation of the circuit and the function of each component is described in the section that covers the schematic.

Step 1: Parts and Tools

This circuit can easily be built on a solder less breadboard. The components are widely available at low cost from a number of sources, such as DigiKey, Mouser, Jameco, etc. that you may already be familiar with if you work with electronics.

You will need a programmer for PIC microprocessors. I have seen instructions on this site for building your own programming device, but I cannot speak for any of them. The programmer I use is from a company called Micro Engineer Labs, Inc. at

It is also handy to have an audio generator of some sort, for testing and experimentation. This can be as simple as a connection to the line out of a PC, CD player, MP3 player, etc.

For example, to verify that the circuit works to detect a certain frequency, just play a file containing that frequency, with the audio output of the playback device connected to the input of the circuit.

A useful program for generating sound files can be downloaded for free at This program allows you to create *.wav files containing specific tones, sweeps, etc. very easily.

Step 2: Schematic and Circuit Description

Picture of Schematic and Circuit Description

The programmed PIC microprocessor (U1) is used in the circuit as shown in the schematic.
The connection labeled +5V must connect to a regulated 5V power supply, such as the output of LM7805 regulator circuit.

The A/D converter measures voltages between 0V and the supply voltage VDD, which is usually 5 volts. The analog input may be a signal that swings above and below 0 volts, so its waveform will have positive and negative portions. In order to sample the input waveform with the A/D converter, the input signal needs to be shifted. The voltage divider created by resistors R1 and R2 sets the bias at half of the 0 to VDD A/D input range. The capacitor C1 couples the AC input signal to the A/D input, so now the input waveform swings about ½ VDD instead of swinging about 0 volts, as shown in the graphs below.

R3 and R4 form a voltage divider used to set the target frequency. The processor reads the voltage at the frequency select pin and uses the value to determine the correct coefficients needed by the algorithm to determine if the target frequency is present.

R5 and R6 form a voltage divider used to set detection threshold. This allows the user to select the magnitude of the algorithm output that is necessary to make the program turn the output HIGH. The processor reads the voltage at the detection threshold pin and uses the value to determine the detection threshold.

C2 is a decoupling capacitor used with the microprocessor to keep the VDD supply free of spikes.

Step 3: Microprocessor Pin Functions

The functions of the pins on the microprocessor U1 are as follows:

1) VDD. Power supply input. Apply a regulated +5V to this pin
2) Serial Output. This pin outputs the results of the frequency detection algorithm. Additional circuitry is needed to convert to RS-232 levels if the output is to me monitored by a PC serial port.
3) Detection Threshold Setting. The voltage on this pin determines the minimum target signal amplitude need to make the frequency detection output (pin 5) go high.
4) Target Frequency Select Enable. This pin is brought low if the target frequency needs to be changed after processor startup. Otherwise, keep it tied high to maintain the current target frequency setting.
5) Frequency Detection Output. This pin goes high if the magnitude of target frequency is greater than the detection threshold set by pin 3. It is high as long as the target frequency is present and its magnitude is above the detection threshold.
6) Target Frequency Select. The input voltage on this pin is used to determine the target frequency to be detected.
7) Audio Input. This is analog input which is sampled by the microprocessors internal analog to digital converter. This pin must be biased at ½ VDD so that the audio waveform can be sampled by the analog to digital converter.
8) VSS. Connect this pin to ground.

Step 4: Target Frequency Selection

Picture of Target Frequency Selection

The target frequency is selected by means of a voltage applied to the frequency select input.
The voltage on this input is ready by the microprocessors A/D converter, and from this reading the program configures itself to decode the corresponding frequency. The frequency range that can be decoded is between 100Hz and 2148Hz.

The program always reads the target frequency select input after power up. After that, the target frequency select input is ignored, unless the target frequency select input enable is brought low. So, to make changes to the target frequency during program operation, the enable input must be low. It needs to be kept low for at least 100ms, as the input is checked at the beginning of the program loop. Once the input is brought high again, the program will ignore the target frequency select input, and the target frequency in effect will be that established while the enable pin was low.

A voltage divider is used to set the correct input voltage on the pin to select the desired target frequency. The voltage needed to set a desired frequency can be calculated as follows:

V_target_frequency_select_input = VDD*(Target_Frequency -100)/ 2048

VDD is the power supply voltage (usually 5 Volts). The valid range of frequencies for the program as written is 100Hz to 2148 Hz.

So, for a target frequency of 1000Hz, and VDD of 5 Volts, the voltage applied to the frequency select input should be:

V_target_frequency_select_input = 5*(1000 -100)/ 2048 = 2.2 volts

The graph below shows the target frequency selected versus voltage on the target frequency select input for a VDD of 5 volts.

The easiest way to set the voltage is using a voltage divider, as shown in the schematic. The voltage at the output of a voltage divider is:


The exact values of the resistors is not critical, only the ratio of their values. However, to prevent noise from upsetting the frequency select input, it is best to choose lower resistor values. As a rule of thumb, select values that are both less than 100k Ohms.

Also, a potentiometer can be used in place of fixed resistors, to provide the ability to change or adjust the target frequency. Use a potentiometer with a resistance of less than 100k Ohms.

Step 5: Detection Threshold Setting

Picture of Detection Threshold Setting

The detection threshold is set by means of a voltage applied to the detection threshold input. The voltage on this input is ready by the microprocessors A/D converter, and from this reading the program sets the detection threshold.

The software applies hysteresis to the detection threshold. Hysteresis keeps the detectopm output from switching back and forth from high to low if the magnitude of the algorithm output is riding near the detection threshold.

If you are unfamiliar with how hysteresis works, refer to the figure below. Note how the upper and lower thresholds are act to provide a clean digital output from a noisy signal that is riding about the center of the window. If you are familiar with a circuit called a Schmitt trigger, then this will be familiar to you.

The value read from the threshold setting input establishes the center value of a hysteresis window, with the upper and lower thresholds sitting symmetrically above and below the center. The output value from the algorithm must exceed the upper threshold to cause the detect output to go high, and the output value must drop below the lower threshold before the detect output will go low. The smaller variations in output value above and below the center of the window do not cause the detect output to change.

The software does not allow the detection threshold to be set all the way to zero, as this would cause the detection output to go high for any small amount of noise on the signal input.
The processor uses the VDD power supply on pin 1 as the reference for the A/D converter. If a different VDD is used the output of the algorithm for a given signal input level will change proportionately.

A voltage divider is used to set the correct input voltage on the pin to select the desired detection threshold

To calculate the voltage to apply to the detection threshold input to establish the minimum upper threshold required to detect an input signal of a certain amplitude at the target frequency, use the following equation.

V_dection_threshold_input = VDD * [342 *V_signal_at_target_freq – 27 ] / 1024

So, to set the detection threshold so that the detection output goes high for an input signal of 1 volt (peak) or greater at the target frequency, for a VDD of 5 volts, the voltage at the detection threshold input should be:

V_dection_threshold_input = 5 * [342 * 1 -27] / 1024 = 1.54 Volts.

The graph below shows the upper and lower thresholds of the hysteresis window versus voltage on the detection threshold input for a VDD of 5 volts.

The easiest way to set the voltage is using a voltage divider, as shown in the schematic. The voltage at the output of the voltage divider is:


The exact values of the resistors is not critical, only the ratio of their values. However, to prevent noise from upsetting the value read by the input, it is best to choose lower resistor values. As a rule of thumb, select values that are both less than 100k Ohms.

Also, a potentiometer can be used in place of fixed resistors, to provide the ability to change or adjust the detection threshold. Use a potentiometer with a resistance of less than 100k Ohms.

Frequencies outside the target will produce a reduced response from the algorithm. So, if the detection threshold is set to detect an input signal of 1 volt or greater at exactly the target frequency, then a signal slightly off the target frequency will need to be of greater amplitude to be detected. The response of the algorithm is sharp, so even large amplitude signals that are very far outside the target frequency will produce little or no response. Refer to the plots of algorithm response versus frequency found in other steps.

Step 6: Optional: Serial Output

The serial output pin provides a means of monitoring and recording the response of the algorithm. It is not necessary to do anything with this output, but it does allow the experimenter access to some useful information.

The serial output has the following format. The data filed are separated by commas.
Target frequency in Hertz, Upper Threshold, Lower Threshold, Current Threshold, Dectection Indication, Algorithm Magnitude output.

Below is a sample line of the output.


So, from the above sample you can see that the target frequency is 1002 Hertz, the upper threshold is 8394, the lower threshold is 6528, and the current threshold is 6506 (this is the value from the last loop). The “X1” indicates that the frequency has been detected. The magnitude of the algorithm output from the most recent run is 11063. This magnitude is greater than the upper threshold of 8394, so the frequency has been detected. If no frequency is detected, the line would contain “X0” instead of “X1”.

If you do a frequency sweep containing the target frequency and watch the magnitude value, you should see it increase as the input frequency approaches the target frequency. The magnitude will be greatest at the target frequency, and then it will drop off again as the sweep moves beyond the target frequency again.

To monitor the serial output with a PC you will need to convert the 5 volt logic level output of the microprocessor to RS-232 levels that can be read by a computers serial port. A circuit using the MAX232 chip can be used for this purpose. Some serial ports may be able to read the output by simply inverting the logic levels. There is a great deal of information on the use of the RS-232 serial port on the web to assist you if needed.

One line of output is transmitted each time the algorithm runs. The program loops about ten times per second. This output can be easily recorded to a text file by a terminal program like HyperTerminal and then imported to Microsoft Excel for further processing if desired.
When configuring a terminal to view the output, the settings to use are 9600 baud, 8N1, no parity, no flow control.

Step 7: Optional: Algorithm Details

Picture of Optional: Algorithm Details

The Goertzel algorithm is a signal processing algorithm which is used for detecting a single frequency. It is derived from the Fourier transform.

The algorithm acts as a very narrow band pass filter. It produces a very sharp response to frequencies within the pass band, and a much lower response for frequencies outside the pass band. The minute details of the Goertzel algorithm won’t be covered here.  

The algorithm loop samples the input using the microprocessor built in A/D converter. The necessary mathematical operations are performed in the time between successive samples.
The different variables used in the algorithm are defined as follows:

Xn_sample=The latest sample from the A/D converter
Xn=The latest sample from the A/D converter multiplied by the window function.
Y0=The output value presently being computed.
Y1=The previously computed output value. (The output value from the previous iteration of the loop).
Y2=The output value from the iteration the iteration before the l previous iteration of the loop.

The figure below shows a list of the variables used in the algorithm.

Refer to the flow chart in the attached PDF to see how the Goertzel algorithm portion of the program executes on the processor. Once the algorithm has processes all the samples (the attached *.hex and *.asm files use 200 samples), the real and imaginary components of the results are calculated. The real and imaginary portions are then used to compute the magnitude. The magnitude is a measure of the target frequency is present in the sampled data. The magnitude is then compared against the threshold. If the value is greater than the threshold value, the frequency is considered to be detected, and the output is set HIGH. If the magnitude is lower than the threshold, the output is set LOW.

The sharpness of the filter response versus frequency is proportional to the number of samples taken. The response of the algorithm must be sharp enough that it responds to the target frequency but produces much lower response for frequencies outside the target. A value of 200 samples was found to produce a reasonably narrow response in experimentation.

Windowing Function

After each sample is obtained from the A/D converter, it is first multiplied by a window value before being used in the subsequent calculations. Refer to the pictures below showing the frequency response of the algorithm to see the affects of the window. The magnitude of the response is lower and the width of the response is wider when the window is used, but ripples are nearly eliminated, making the determination of whether the target frequency is present easier.

There are many types of windows that can be applied in digital signal processing. This particular one is called a Hamming window. The shape of the hamming window is shown in a picture below. The plot below shows the value the window function that is used for each of the samples in the subroutine.

Step 8: Factors Affecting Performance

The hex file and source code were written for the PIC 12F683 processor. For simplicity, the processors internal 8MHz oscillator was used for the clock. The instruction cycle frequency is ¼ of this frequency, or 2MHz, so the instruction cycle time is 0.5 microsecond.

Because this processor is not a real DSP, subroutines were developed to perform the mathematical operations necessary to run the algorithm. Operations such as multiplication end up being relatively time consuming. A real DSP processor is designed to perform such operations at a vastly greater speed.

The 12F683 processor can use a clock frequency as great as 20MHz. This frequency would need to be generated from an external crystal or oscillator, and the software would have to be configured to use it as a clock source instead of the internal oscillator. Using a 20 MHz oscillator would allow the sampling rate to be increased by about a factor of 2.5. The timing constant used to set the sample period would need to be changed if the clock frequency is change. Also, any other timing critical routines, such as the bit banged serial port, would need to be modified to produce the correct timing.

Step 9: Problems Due to Aliasing

Picture of Problems Due to Aliasing

The algorithm must perform all the required processing between samples, so the maximum rate at which the audio input can be sampled will be limited by how quickly the processing can be completed. In the worst case, the algorithm takes about 420 instruction cycles to process each sample. When the processor is running on an 8MHz clock, the sampling frequency is then limited to about 4400Hz. If you are familiar with DSP, you will recall that the sampling rate must be at least twice that of any frequency in the signal, or aliasing will occur. Aliasing is when a higher frequency signal is interpreted as a lower frequency signal. For example, if you set configure the processor to detect 1000Hz and the sampling rate is 4400Hz, a signal of 3400Hz will be detected as 100Hz.

Refer to the figure below to see how aliasing works. The first plot in the figure is the baseband spectrum of the signal you are sampling. The shaded triangular area represents the shape of the spectrum. The horizontal axis is the frequency. When the baseband signal is sampled, the sampled signal spectrum will consist of the baseband signal spectrum repeated around every integer multiple of the sampling frequency, as shown in the following plots in the figure. Note that none of the spectra overlap in the first plot.

The next two plots show the spectrum of the sampled signal as the sampling frequency is reduced. Note that the repeated spectra around every multiple of the sampling frequency get closer together as a result of the reduction in sampling frequency. The bottom plot shows what happens when the sampling frequency drops below twice the bandwidth of the baseband signal. The shaded area of the repeated spectra now overlaps the baseband signal spectra. It is now possible that the frequency labeled f2 in the repeated spectra may overlap on the frequency f1 in the baseband signal. This frequency cannot be distinguished from an actual signal at frequency f1, and so it is called an alias.

To prevent aliasing, filter the input signal to reduce the frequency content that is above ½ the sample rate, in this case 2200Hz.

Step 10: Performance in the Presence of White Noise

Picture of Performance in the Presence of White Noise

The two figures below show the response of the detector when white noise is present with the desired signal. These plots are from actual data recorded from a circuit running the program on the PIC microprocessor. The first figure shows the actual shapes of the sine wave signal plus noise applied. The second figure shows the response of the algorithm when the signal is processed.

The first figure shows the response of the algorithm when a sine wave input signal is accompanied by increasing levels of white noise. The first plot is with no noise present, and the subsequent plots show the response when the noise amplitude is 20%, 50%, and 100% as large as the signal amplitude. Even with a significant amount of white noise with the signal, it can still be reliably detected.

Step 11: Problems With Overdriving the Input

Picture of Problems With Overdriving the Input

If the signal input is over driven, the signal will begin to clip, causing distortion. This distortion gives rise to harmonics of the input signal, some of which may be larger than one half the sample rate. These harmonics may be detected as aliases.

The plot below shows the algorithm output for a frequency sweep where the amplitude of the input signal was large enough to clip the sinusoidal shape. Note the additional spikes in the response. The target frequency was approximately 1000Hz, and the sampling frequency is 4400Hz. Note the short spike in the response just above 1100Hz. The third harmonic of that frequency is approximately 3400Hz, which for a 4400Hz sampling rate would alias as 1000Hz.

If false detections due to clipping are an issue, the input signal could be attenuated before being input to the processor. If the input is being driven by an amplifier, such as in an application using a microphone, the gain of the amplifier may need to be reduced to avoid clipping. It is also common to include a low pass filter as an “anti aliasing filter” prior the sampling of the signal, to filter out any frequency components larger than one half the sample frequency.

Step 12: Source Code

Important Update Jan 31, 2011.  Please read!

A viewer recently tried to assembly the *.asm file originally  included in this instructable, but receieved many "118" errors from the MPLAB assembler. This issue is due to the fact that I created the code on an older version of MPLAB. While it compiled fine on the older version, I
received the same errors when I tried it on a new version.

It seems like the directives used to set up and reserve space for variables in RAM has changed. I also noted a few other instances where the new version of MPLAB did not like the syntax of expressions that worked fine in older versions.

Also, be sure to select "absolute code" when trying to assemble the *.asm file supplied.

I have updated the *.asm file and attached it here. The only changes made are those required to assemble without errors. The updated file has "NEW" in the file name. I have left the old file attached also, in case anyone needs it, but just be advised that if you are using the latest MPLAB it will generate many errors if you use the original asm file I attached.

The *.hex file generated from the updated code appears to be identical to the one I originally attached, so I have not attached another file. The original *.hex file should work fine for just programming a part with the code as it is configured in the supplied *.asm file.


The source code for the *.hex file supplied is attached below. The program was written to use the PIC 12F683 processors built in oscillator as the clock, operating at 8MHz. If you plan to reuse the code in an application where you will be using a different clock frequency, then you will have to account for the difference in the software. The parameters that set the sampling rate will have to be changed.

If you make a change to the sampling frequency (which is 4400Hz for the program as it is written now) then you will have to generate new look up tables for the sine and cosine coefficients, as these are dependant on the sampling frequency.

If you change the number of samples used in the algorithm (which is 200 for the program as it is written now) you will have to generate a new lookup table for the window function.

It is relatively straightforward to port this code to another 8 bit PIC microprocessor. The main things to keep in mind are the oscillator frequency as described above, and the exact setup of registers associated with the peripherals used. These are usually very similar between the 8 bit PIC processors, but they can very a little bit. The processor chosen must have an A/D converter for reading the analog inputs, and a 16 bit timer to set the sampling frequency.


pp5ms (author)2017-08-12

Hi LargeMouthBass,

First I would like to thank you for sharing this project.

I would like to detect a little lower band os frequency and my question is if this is one easy modification to do. I can edit the asm file and compile again.

The range I need to detect from 67Hz till 250Hz.

If possible, can you point me the right way to do this?

I think that can be something in the asm that I can divide by two and lower the range to half, is this possible?

Thank you for any help you can give.

Best Regards,

Marcus from Brazil

JosephM134 (author)2016-02-03

Great! But what I need is a device that can recognize when a signal is in the range of 8 to 13 hertz. Can your device do frequency ranges too?

renju1234 (author)2015-03-31

i am very much interested in ur project. pls clarify the foll doubts:

1. will this project work with pic18f6520?

2. can this be changed for higher freq ranges? khz or mhz?

3. if yes, how to change the program?

4. do u use adc input channel for freq detect?

5. if so, can the program be carried out in such a way that we know in which channel the freq is detected?

6. can u help me with the pgmming? ill do the hardware part

DrDiodac (author)2013-07-08

Trying to make the hex file but did not quit. MPLAB makes mistakes and the hex file that is included here, when you try to download recorded as TMP ..
Please help me ... if someone could send me an e-mail the latest code in hex​​?
Thank you,

DrDiodac (author)2013-06-29

Great topic, sorry for my childish question :) I am not a good programmer. How do to lower the entry threshold of 100Hz for example, 30? would range from 30 Hz or even lower. This is a big change in the program?

TaZzZz (author)2013-05-07

Hi there,
I'm trying to build your circuit in my project, however, I don't know how to program the PIC 12F683.
I mean, I can't transfer the program you provide it to PIC 12F683.
So, any clue.

LargeMouthBass (author)TaZzZz2013-05-15

Do you have a PIC programmer? I use one that I purchased from years ago, but there are many other sources. There are also plans out there to build your own, but I haven't ever tried them so I can't give more guidance there.

tk5ep (author)2013-02-17

Hi, Thanks for the help.

So, this confirms that there is no real need to use an external Xtal if the problem comes from the rounded maths.
Not a big issue if you know it...
Anyway, it was fun tracking down the problem and i learned a lot looking at your code !

Thanks again,

LargeMouthBass (author)tk5ep2013-02-18

I think that it is still necessary to use a crystal, otherwise the center of the response will be different from on processor to the next, and my vary over temperature as you discovered. If an oscillator with a greater tolerance is used there will be a corresponding change to the sample rate, and since the coefficents used are a function of the sampilng rate, the response will be different fhan expected.

The limitations of the math cause the response to be at a slightly different frequency than expected. If the 1754 Hz center frequency (using the 1760Hz coefficients I mentioned in my last email) is close enough to 1750 Hz for your application, then I would use that along with the external crystal oscillator instead of the 1% tolerance internal oscillator.

Working through these issues has identified many things I had not discovered when I first create this project. It has been really helpful to improve the design. If I get time, I would like to investigate these in more detail, and possibly add an update to this article to benefit anyone else who may want to use the program so they can avoid the issues you had to work through.

tk5ep (author)LargeMouthBass2013-02-18


I'm glad if i could help to improve your design !
It works perfectly on 2 of our repeaters right now. I will see how they age and keep you informed if necessary.

I stay tuned on this discussion, so i will be alarmed when you improve the code one day.

Thanks for you great design and help. I also learned a lot looking at your code. I'm not a programmer, but a "hardwarer"...

tk5ep (author)2013-02-17

I digged into the code and found where to change the threshold pin from 3 to 6.
Now, with a 8 MHz external Xtal and threshold level set on pin 6, the circuit works !

Unfortunately, the bandpass is still not centered on the target frequency...

I measured a center frequency of 1736 Hz for a target of 1748 Hz.

The Xtal frequency is only a few Hz away from 8 MHz. So the problem is somewhere else.... :-(

Can it be that the sin and cosin values are not correct ?

Any guess ?

LargeMouthBass (author)tk5ep2013-02-17

I've been experimenting with the code today, and found the same issue you describe. I also found that the center frequency was low for what should have been about 1750 Hz. I tried using the coefficients for slightly higher frequencies, and found that the closest I could get was to use the values for 1760Hz. This resulted in a response that was centered around 1755Hz.

I think the problem is the limitations in how accurately the coefficients can be represented the way I'm doing it. There isn't really much that can be done about that, as trying to represent them with greater precision means that multiplication operations would take much longer, such that the program wouldn't even be possible on this general purpose processor.

I've attached the hex and asm files from my most recent build, which uses the 1760Hz values for response much closer to what you want. It is configured for HS_OSC.
This time, I've tested the code.

tk5ep (author)2013-02-15

Hi again !
I tried your latest version with an external Xtal, but it does not oscillate.

You say, you used the XT mode, but according to the datasheets, it is to be used up to 4 MHz only.
Maybe, it is the only reason why my Xtal does not oscillate ?

Or maybe there is another problem in the modified source ?

I doublecheked my new board and it looks OK according your new design.
Pin 2 + 3 for the Xtal + capacitors.
Pin 6 AN3 for threshold setting.

Can you have a look on it and/or send me the modified code, so i can make my own tests without bothering you.


LargeMouthBass (author)tk5ep2013-02-16

I checked my code, and I did set it up for XT mode.

I programmed a part with the code and built the circuit using the crystal, but I could not get the crystal to oscillate either. I also tried a program for a different project I built that uses the 12f683 processor with an 8MHz crystal, but the crystal didn't oscillate with that either.

I don't know what to make of that, but I suspect that there may be a problem with the crystal and capacitor circuit. I've only used that setup a couple times before, as I usually just use the intenal oscillator or an external oscillator module if the application requires higher precision.

I plan to try again using an external oscillator instead of a crystal with capacitors. I should know how that turns out in a couple days, and then I can send you actual working, tested code that uses an oscillator module. I'll let you know when I have results.

tk5ep (author)LargeMouthBass2013-02-16

HI !

I wanted to write a post again... I took the original asm file and modified ONLY the config to use the HS_OSC bit.
And now, i have a pure sine wave oscillation at 8 MHz on pin 3 i can see with my scope. Can't figure out why i don't have something on pin2 as this is an input...

I can't test the complete circuit, as i don't know how to modifiy the rest of the program to work with changed pin configuration.

So try to modify XT_OSC to HS_OSC on your latest version (with 1750HZ and changed threshold pin) and send me at least the HEX file.

Thanks for your help.

tk5ep (author)tk5ep2013-02-16

I noticed that using a scope probe introduces some additional capacitance and that reading is disturbed by it.
Using a different probe, i have a clean 4V oscillation that stop only when power supply drops down to 2V !
So, everything is just fine using HS_OSC ! I suppose XT_OSC does not have enough gain to start oscillation at 8 MHz.

tk5ep (author)2013-01-28

HI again !
I found some time and having 2 other PICs, i programmed them and made some tests.
None of the PICs has the same frequency response.... One does even not detect at the right frequency, being out of band !!
Internal frequency precision seems to be quite critical for your decoding, which os logical if based on time.

So, there must be a huge dispersion in these internal oscillator despite the 1% "high precision" claimed by the data sheet...
Or, there is something else interfering...... I saw in the data sheet that the OSCTUNE register can adjust the frequency..

I heated the PIC with my soldering iron, and the detection frequency changes also, which is quite normal...

I don't know if there is a way to measure and change the internal oscillator, but i think that for precise decoding an extrenal oscillator is mandatory !

Can you try to modify your code, so that i can use the pin 2 and 3 for an external crystal ? Maybe you can use pin 6 left free now (when using a fixed frequency) for the threshold of change the code, for a software defined threshold level ?


LargeMouthBass (author)tk5ep2013-01-28

I've made a modified version of the 1750Hz code for use with an external 8 MHz crystal (attached to pins 2 and 3). The threshold setting has been changed to pin 6.

When you connect the crystal, you will need to have two small caps connected as well, one on each side as shown in the schematic I attached. I've used 22pF caps with an 8MHz crystal on this processor before on another project , and it worked properly.

This code is configured for "XT" oscillator mode, and described in the oscillator section of the 12F683 datasheet.

I haven't tested this code, but the modifications were very minor so hopefully it works.

tk5ep (author)LargeMouthBass2013-01-28

Wow !

Thanks for that !
I will test it asap and keep you informed. Can you post the modified assembler, so i can see how you did that ?

BTW, on the 3 PICs i've tested, the bandpass is exactly the same. 34 Hz, so about 2%.

Thanks again !

LargeMouthBass (author)tk5ep2013-01-31

I will send the asm file if the code checks out. Let me know once you get a chance to test it with the crystal.

tk5ep (author)LargeMouthBass2013-02-14


I found the time to build a new pcb and ordered some 8 MHz Xtals.
I programmed a new PIC. But unfortunately, the xtal does not oscillate at all.

Can you check you hex file if it is really configured for XT ?


tk5ep (author)2013-01-26


Thanks for the explanations.
At least, we could make a test with a modified code for an external 8MHz oscillator, so we can eliminate one source of inaccuracy.

I would be interested to test it; though.


tk5ep (author)2013-01-25

Hi !

Yes, i already made an article on my page, but for the moment only in french. I will translate it in english for my radioamateur visitors. Actualy, it looks like that :

I have added the more or less universal pcb design i've made with KICAD.

BTW, i made some measures and for a frequency target of 1750Hz, the decoder detects from 1713 to 1760 Hz.
Is there any reason for this asymetrical bandpass ? For a centered bandpass, should i choose a higher target frequency ?

Thanks and apologize again,

LargeMouthBass (author)tk5ep2013-01-25

I couldn't say offhand exactly what the cause is. One thing I should add is that the constants I used in the fixed frequency code were for 1748 Hz, as they were calculated out in 4Hz increments. The next highest frequency was 1752Hz, so still 2 Hz off your target.

Part of the reason for the actual detection range may be the limitations of how accurate the the math routines are. This PIC has no native multiplication instructions, just 8 bit add and subtract, so I had to write them myself. There is some inaccuracy and rounding involved, as I had to keep them simple so they would run fast enough on a general purpose PIC with only 8 bit add and subtract.

Another source of inaccuracy may be from the fact that the program I wrote has the processor using an internal 8MHz oscillator, which doesn't have the accuracy of a crystal.

I would suspect that as a result of the various sources of inaccuracy, the actual center frequency is about 1737Hz. In general the passband should be symetrical.

I hope that this doesn't impact your application. If it does, I could look into a slightly modified version of the code that would use an external 8MHz oscillator instead of the internal one.

tk5ep (author)2013-01-25

Hello LargeMouthBass,

I have to apologize !
Your modified code for a fixed frequency works perfectly !

I make some new tests today and found a broken transistor on my test board ! I should have double checked it before.... :-((

You know what ? I'm happy !
Thanks and apologize again !


LargeMouthBass (author)tk5ep2013-01-25

I'm glad to hear that it is working!

Are you going to include details of your project on your web site?

Anyway, I'm glad it seems to be working out. Please let me know if you need any other help.

tk5ep (author)2013-01-10

I finaly found the time to test your design ... :-((
I made a small board yesterday evening and wired it right now.
The modified 1750 Hz version you put here does not work. The serial output is disabled, but no tone is detected.
I tested with the normal software and it works just as predicted... So, there must be a small mistake in the modified code.

One error i noticed in your text, the part describing the frequency selection.
The voltage divider used for the frequency setting should use R3+R4 and not R1+R2 in your formula.

I don't have the assembler to make my own tests in modyfing the code to make it work at a given frequency. This would still be fine, as i wouldn't be dependent of the supply voltage fluctuation.

Do you allow me to translate it in french and put it on my homepage ?
I'm sure it will be useful to others as well.

Thanks again for this nice circuit !!

LargeMouthBass (author)tk5ep2013-01-11


I'm sorry to hear that the 1750Hz code didn't work. It sounds like you can still make your application work by using the regular code and selecting the frequency using the analog input.

Thanks for pointing out the error. I have corrected the article to refer to the right resistors.

If you ever want to modify the code, the assembler I use is the free MPASM from

When you say you want to translate to French, are you referring to the text of the article? That should be fine, as I have posted all the details of the project here, so go ahead. Perhaps make a reference back to the original article. If anyone else can make use of the code that would be great.

Thanks for your interest in this project, I'm glad you could make use of it.

curious555 (author)2012-11-23

what is the frequency you set here as default ?? and where to change in the coding?? ( am a beginner help me plz ). How can i know the desired frequency was found by the circuit if serial output is not taken??? i want to switch ON a diode if that desired frequency was found.. is it possible without serial output, help me with any alternative way??? ALSO WHAT IS THE RANGE OF FREQUENCY DOES THIS CIRCUIT COULD DETECT ( am expecting 25khz) plz help me out... its urgent buddy ....

There is no "default" frequency. It is determined by the voltage which is read on an analog input. There is an equation in the text that can be used to find the voltage to apply to the pin to set the desired frequency to detect.

It is not necessary to use the serial output for any functions. It is there just for user information/debugging if needed. You can tell if the frequency is detected by the state of the detection output alone.

Unfortunately, the range of detectable frequencies does not extend to 25kHz. The detectable range is only 148Hz tp 2148Hz. It was designed for use in detecting audio tones. The Goertzle algorithm concept and the related mathematics can apply be applied to any frequency, if it is sampled at a sufficient rate and the samples can be processed in time. With the project shown here it is not possible to go beyond that range, as to do so it far outside the processing capability of this small general purpose processor that is only running on an 8MHz clock.

curious555 (author)2012-11-14

i want analog output to analyse it... ie; i dont want only the detection, also i want the sound output from the pic. plz guide me

This program doesn't output any analog, just the detection output. I assume that you are wanting a narrow filter for audio? That is beyond my present knowledge of DSP, and probably isn't feasible for a general purpose processor like the 12F683 used here. It would need a "real" DSP.

thanks for your response... i hav some queries here . to operate this frequency detector, whether i want to load that .asm directly or i have to write the coding on own ??? plz guide me ,, am just a beginner

The *ASM file is what the assembler program uses to generate the *.hex file that is actually used to program the part. I attached both the asm and hex files to the article. If you just want to program the part with the code I created, use your programmer to load the *.hex file onto it. You won't need to do anything with the asm file just to use my code as-is.

If you want to make your own modified versions of the code, you will have to open the *.asm file in Microchips MPLAB software, make your changes, and then reassemble to generate a new *.hex file that reflects your changes.

curious555 (author)2012-11-14

i want to analyse the amplitude i.e; output sound.... plz guide me that how to take the analog signal from the filtered output from the pic

tk5ep (author)2012-07-01

Hi !

Great project !
I would like to use your circuit for a local repeater. I want to replace the unstable NE567 decoder with a small addon board.
I only need a fixed frequency ( 1750 Hz ) and no serial data output. So for simplicity and no tuning, i would like to remove the divider for the target frequency.
I saw in the previous posts that someone modified the code to do that. I'm not a programmer, so can you help me to do that ?


LargeMouthBass (author)tk5ep2012-07-02

I can probably make a separte version of the code that would just do a single frequency. I can also disable the serial output. (The serial output is just for information only, and it is not necessary to use it to use the circuit. It could also just be left disonnected. Disabling it improves response time, but only slightly).

I won't have time to test the new code myself to verify performance though. If you have a PIC programmer, I can send you a hex file for programming, and you can test it from there.

Let me know if you think that would work for you.

tk5ep (author)LargeMouthBass2012-07-03


Yes, that would be fine. If you can send the asm file as well, it would help me to understand what you did and probably be able to modify it for any tone.

I don't have 12F683 PICs, but will order a few. I have a PIC programmer.

BTW, is the internal clock precise enough for a stable operation ? Wouldn't a external Xtal be better ?

Thanks for the answer,

LargeMouthBass (author)tk5ep2012-07-03

For some reason, my file attachments to my earlier message didn't work right. I'll try again. The uploader didn't like the *.asm file externsion, so I had to change it to .txt.

tk5ep (author)LargeMouthBass2012-07-04

Thanks a million,

I will try this ASAP and will let you know.

Thanks for taking the time to answer me and being so helpful.

LargeMouthBass (author)tk5ep2012-07-03

I've made a special version of the code which is set to detect 1750Hz. Actually, it is for 1748 Hz, as the frequency cannot be selected that precisely with the math I am doing. The serial output has been disabled.

I made the changes by commenting out the sections that read the frequency setting. I deactivated the serial output by having the code immediately return from the subroutine that ordinarily would transmit the characters. I've added notes to the asm file to show where I have made the changes. I've left the code in the asm file, even unused code, for reference. The asm for the regular version is attached to the main article.

I have not tried this special version of code in circuit, but the modifications were very straightforward, so the should work. Let me know if the code doesn't work.

The width of the frequency response is fairly narrow, refer to some of the diagrams in the main article.

The internal oscillator has a tolerance of about 1%. I've found that it works well.
The special version of code I made uses the internal oscillator, but since the serial is not used, you could connect an external oscillator to pin 2 (RA5) and modify the code to use an external oscillator.

I hope the code works for you. Let me know if you have any problems. I'd like to hear about your repeater project when you have it finished!

hydronics (author)2012-02-26

What are the advantages/disadvantage of using this PIC over a LM567 Tone Decoder?

I'm trying to design a circuit that detect/differentiate frequencies in the ranges of 190hz, 250hz and 285hz. Thanks!

LargeMouthBass (author)hydronics2012-03-16

I haven't worked much with the 567 decoder. From what I recall it was somewhat finiky, but that may not be a fair assesment.

The design I made for this instructable should work well for your application. One downside might be if you don't have a PIC programmer available and so you would need to make or buy one.

The 567 is probably somewhat less expensive than a 12F683, although the price of each is not very great. I think the 12F683 is less than $2 in small quantities from Digikey.

One strength of the detector in my instructable is that it is easily configurable using just a voltage divider on the frequency select input. You could use 3 processors running the software included in the instructable. The analog signal inputs could all be driven in parallel. A separate voltage divider would be needed on each process to select the desired frequency. The three outputs would easily interface to whatever logic your application needs.

hydronics (author)LargeMouthBass2012-03-16

cool thanks for taking the time to review my question.

you said, "if you don't have a PIC programmer available..." yea.. I'm sure one of these days I'll want to move on from the Arduino prototype playland and actually hard code something.. eh?

So just for curiosity, could this code be easily adopted for compiling into an Arduino and/or why hasn't someone done that? cheers,

nitishonway (author)2012-02-01

how about sensing 220v, 50 Hz frequency??

naveen gupta (author)2012-01-14

how the frequency detected output can be viewed ? do i need to attach a LCD display?

The frequency detect output on pin 5 is just a digital output that goes high when the selected target frequency is detected. If the algorithm results are greater than the upper threshold setting, then the line will go high.

The serial output line is optional. I included it for diagnostic purposes and to help the user better understand how the circuit works. To view the serial output, you need to convert the serial output to RS-232 levels (inverted) and connect it to a PC serial port. If your PC has no serial port, as is common on most newer PCs, you can get USB to Serial adapters that will provide a serial port.

I hope that answeres your question. If you have any other questions, feel free to ask.

Drakenpilot (author)2011-02-27

Great SW.

I am going to use the circuit for a CTCSS decoder in our local 434 MHz ham radio repeater. I have lowered the sampling frequency to 2000 Hz , disabled the analog frequency input and the serial data parts as I am not going to use them. As a concequence I can only detect one tone which is my need. With the SW set to detect 82.5 Hz, the circuit detects from 81 Hz to 85 Hz and no triggering on the adjacent tones. Very good performance

I have noticed one peculiarity. The time elapsed from a tone is applied to the input and until Pin 5 goes high varies between 110 msecs and 240 msecs. As i have disabled the serial communication and also the reading of the frequency at Pin 6, I would expect a fairly constant delay in detecting. any thougts about this?

I just thought of another detail that may make the detector output timing more consistent.

All my previous comments still apply, but there may also be a bit of an issue with the coupling network of R1, R2, and C1. These parts essentially form a first order high pass filter. The roll off frequency is f = 1/ (2 * pi * C1 * R1 || R2). With the values of 10k and 1 uF as shown in the circuit, the roll off would be about 31Hz. This should be OK for your 82Hz signal, but I don't know the exact values you are using. If the roll off frequency using the values you are using is greater than say 60 Hz, I would choose some different values to make sure the roll off is well below 82 Hz.

If you were attenuating the signal by using too high a roll off frequency, the circuit may be more likely to take 240 ms from the start of the tone until the detection output goes high.

The software computes the response based on taking a total of 240 samples. Since you've lowered the sample rate from 4400 to 2000 Hz, it will take a total of about 120ms to take the 240 samples. The other computations that follow take a very short amout of time compared to the 120ms worth of samples. This process repeats, and the digital output is set high or low depending on the results of each 240 sample "sweep".

If the tone is applied somewhere in the middle of a sweep, the magnitude of the response may not be high enough for the output to get set high. One the next sweep, the tone is present for the entire time, and so the magnitude is great enough to get exceed the threshold. If the tone was turned on, say, only 1/4 of the way through the sweep, then perhaps that sweep would result in a great enough magnitude to generate a high output. It will also depend on the detection threshold you have selected. In the instances where it takes 240 ms to detect, the tone must have turned on when the sweep was too close to the end for the magnitude to be great enough.

So, it all depends on where the process is when the tone is first applied. This will end up being somewhat random, as the tone detection process won't be syncronized to the CTCSS tone.

I don't think that there is much that can be done to improve the situation, as the scanning process is broken into 240 sample windows, as described. I hope that this doesn't impact your application too negatively.

About This Instructable




Bio: If you've got a problem, Yo, I'll solve it ! -Robert Matthew Van Winkle
More by LargeMouthBass:Rugged R2D2 PinataAudio Delay ModuleReverse Engineering an Electric Fence Charger
Add instructable to: