Introduction: Frequency Detector Using PIC 12F683 Processor

About: If you've got a problem, Yo, I'll solve it ! -Robert Matthew Van Winkle
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 http://www.melabs.com.

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 http://www.goldwave.com. This program allows you to create *.wav files containing specific tones, sweeps, etc. very easily.

Step 2: 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

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:

Vout=VDD*[R4/(R3+R4)]

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

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:

Vout=VDD*[R6/(R5+R6)]

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.

01002,08394,06528,06506,X1,11063,

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

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

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

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

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.