Frequency Counter

I want to do a frequency counter to old English military radio.

It can used for radioamatereurs, but it has a broken LCD.

First I thought that I will find normal 8 or 4 bit data cables and build a new frequency display to it.

Then I got the information, that LCD has every bit controlled., so maybe 200-300 controller bits.
It has two 56 pins I2C devices PCF8575T, no LCD is any more available.

So, I decided to make a new frequency LCD display.

The radio works 5MHz - 35MHz, but I must measure receiver frequency, which is 40MHz above sending frequency,
so 45-75MHz.

I am using PIC16F886 and 2*16 LCD
It works with 20 MHz crystal.

So I need a frequency divider to the frequency input.
I found MCAC4040 IC.
It has 1:12 to 1:12 divider.
It was not like normal CD4040, but it works also with 100MHz.

I thought to use CCP interrupt, but after testing I found is does not work without

external frequency counter.

Then I tried other possible solution.

Then I need 16 bit counter Timer1 to read the frequency.
Then I need a interrupt timer1 reader, Timer2, but what time?

MATTI2.jpg

I have to made timer interrupt 20MHz/4/16/200/16 = 0.01024s

The accuracy should be about 1KHz.

I did a prototype with PIC16F886.
I did a following program.

interrupt driven frequency counter 75M-45MHz rangelue
for radioamteur tranismitter.
// it is really 35MHz- 5MHz)
// Pekka Ritamäki
// 6.8.2022
// freq.c
// frequency comes to PIN_C0
// Testing 250kHz signaal. It is 75 times slower than 75MHz
// First we measure Timer1 overflows, The timer1 goes over 65536. It is saved to timer1intcounter.
// The measured timer2 is 20MHz/4/16/200/16= 0.01024s .
// Them make a calculation to LCD, but this test is done for RS232 9600
// oscillator is 20MHz crystal

#include <16F886.h>
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use Delay(clock=20000000)
#fuses INTRC, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use Delay(clock=8000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//====================================================
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)

unsigned int16 Count=0;
unsigned int32 Frequency;
unsigned int32 timer1intcounter=0;

// timer1 overflows, but we take them to save

#INT_TIMER1
void timer1_interrupt()
{
timer1intcounter++; // her is timer1 overflow (>65536)

}

int1 RollOver = 0;
// timer2 defines timing 0.0104s Oscillator frequency/4/16/200/16) 0.0104

#int_timer2
void t2_isr(void)
{

Count += get_timer1();

count= count+ timer1intcounter *65536;
Frequency = Count; // take frequency from timer1
count=0; // zero count for next time
set_timer1(0); // zero timer for next time.
RollOver =1; // give to main program a mark

}

// then main program starts
void main(void)
{
float freqsum=0;

setup_timer_2(T2_DIV_BY_16,200,16); // mode T2_DIVICE_BY_8, Period (1-255), postscale 1…255, 20/4 MHz= 5MHz , 5MHz/4= 1.25MHz
// 1,25/250 = 5ms, 5ms /16= 0.3125ms .
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); // 20MHz / 4= 5MHz, 0.2us * 65536 =131072,5 us
enable_interrupts(INT_TIMER2); // set timer2 on
enable_interrupts(INT_TIMER1); // set timer1 on
enable_interrupts(GLOBAL); // give global interrupts on

delay_ms(100);

while(true)
{

if ( Rollover ) // timer2 interrupt has been on in every 0.01024s

{
freqsum =(float)frequency; // convert frquency to float
printf("\rFrequency1=%6lu float %6.6E ", frequency,freqsum );
printf("\rFreqsum=%6.6E MHz ", freqsum/1000000 );// - 40);
freqsum = 4*freqsum ; // remove external divider
freqsum = freqsum *97.65574137698; // correct timing
printf("\rcorrected frequency %E ",freqsum);
freqsum = freqsum -40; // degrease 40MHz
printf("\rReal frequency %E Hz",freqsum);
Frequency=0;
Rollover=0; // reset marking for next timing

}
}
}

First we count maximum frequency 75MHz
75MHz/4= 18.75MHz. This is extern frequency divider.

18.75Hz= 0.05333us. This input frequency to timer1.

0.0533333us *65536 (16 bit) = 0.003495231488s
When input frequency is taken at timing 0.01024s.

Oscillator 20MHz/dived by 4, dived by 16,dived 200 and divided by 16= 0.01024s

overflow 0.01024/0.003495231488 = 2.92970581066332289578

16bit counter will overflow 2 times+ 0.92970581066332289578 * 65536

So when timing is finished, read timer1 + add overflow * 65536.

So the data is 2*65536 + 0.92970581066332289578 *65536 =131072 +60929 = 192001Hz

Then you must multiplier it by 4, because here we must use external diver 1:4.
This cpu cant count 75MHz.

192001Hz * 4= 768004Hz

This is 75MHz, but it must multiplied with timing correction multiplier 75000000Hz/768004Hz= 97.65574137698
Then we must see how it works 97.65574137698 * 768004Hz = 75000000Hz

Then you must decrease 40MHz
75000000Hz - 4000000MHz= 35000000MHz

The final frequency in the display is 35.000MHz.
===

Then we count minimum frequency 45MHz
45MHz/4=11.25MHz
1/11.25MHz= 0.088888uS.This input frequency to timer1

0.088888uS* 65536= 0.00525482222s
Timing frequency was 0.01024s
Overflow 0.01024s/0.00525482222s= 1.75781425
So the overflow go only 1 times + 0.75781425 * 65536 = 115200Hz

115200Hz *4= 46800Hz
No we must use correction timer 97.65574137698
46800Hz *97.65574137698= 44,999756Hz or 45MHz
Then we degrees 40Mhz 44,999756Hz- 4000000MZ= 4.999756756MHz

bottomPCB.jpg

Here is the real PCB ( bottom)

Here is testing with 250kHz signal.

ohjelmantestaus.jpg

It is done without external 1:4 divider.
So it shows 100kHz signal

Here is PCB

MATTi2PCB.jpg

The device needs also how much is transceiver input oscillator higher than the real frequency.
How is that adjusted?
Here is how I did that

Deselect.jpg

Pekka OH3GDO

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License