View previous topic :: View next topic |
Author |
Message |
NEWBOY
Joined: 19 Dec 2003 Posts: 9
|
How Can i get +/- 0.1Hz Frequency Resolution |
Posted: Fri Dec 19, 2003 7:42 am |
|
|
Hello Pic C gurus,
i want you to help me answer this question and help me with my present project.
i have a project that requi 0.1res me to measure the frequency (square wave) from a sensor to -/+Hz resolution
Would this be possible with the pic16f877 @ 20mhz?
i have just immigrated from PBP and i was able to get upto +/- 0.6Hz resolution using ccp capture
i did this by measuring the period then converting it to frequency but because of floating point numbers i have finally decided to break the bank and move up to using C.
But first of all i need some practise as rome wasn't built in a day so i have decided to convert the program i wrote in pbp to C but i am having real problems with the following
1) set capture for 16th falling edge
2) turn capture on/off
Could someone kindly help with those
jan ![Razz](images/smiles/icon_razz.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Fri Dec 19, 2003 8:47 am |
|
|
Look in the manual under setup_ccp1()
To turn off:
setup_ccp1(CCP_OFF);
For 16th edge and interrupt:
setup_ccp1(CCP_CAPTURE_DIV_16 | CCP_COMPARE_INT); |
|
![](templates/subSilver/images/spacer.gif) |
NEWBOY
Joined: 19 Dec 2003 Posts: 9
|
|
Posted: Fri Dec 19, 2003 1:27 pm |
|
|
Thank you for the pointer
i just got a bit confused with the manual but its all sinking in now
by the way would it be possible to get my 0.1 Hz resolution ?
if it is , how can this be acheived
jan |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Fri Dec 19, 2003 2:16 pm |
|
|
Depends on the frequency that you are measuring. The higher the frequency, the lower the resolution. |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Fri Dec 19, 2003 5:01 pm |
|
|
Mark
The frequency would be in the range of 1Khz to 6Khz
i was thinking of using something like a frequency divider say of 10
which would then make the range 100hz to 600hz
Any ideas of a chip that does that of similar?
Jan |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Fri Dec 19, 2003 9:27 pm |
|
|
If you extend the CCP's value greater than 16 bits by counting timer1 overflows, you should be able to do what you want. You will have 2 interrupts, one for timer1 and the other for CCP1. In the timer1 int, just increment a global variable. This could be an 8 bit value which will become the high byte of the CCP value. When the CCP int occurs, the 2nd and 3rd bytes will be the CCP value. This will extend the value to 24 bits. You could make the timer1 variable 16bits which would give you a 32 bit CCP value. After you get the CCP value, be sure to reset the timer1 var to 0. Now if you are sure that the frequency will always be 1K-6KHz, you could probably work the divisors out so that you can actually ignore the timer1 var. That is, not even need it. But for now, I would try using the var. |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Sat Dec 20, 2003 12:12 pm |
|
|
Mark
i found something similar but this is based on the frequency being sampled at 1 sec intervals
Due to my knowlegde in using C i got lost trying to reduce the sampled time of 1 sec intervals to 15ms as my signal would only be avaliable for
15ms at any time using delay_ms(15) doesn't seem to work is there another way.
jan
/////////////////////////////////////////////////////////////////////////
//// EX_FREQC.C ////
//// Counts the 'zero' crossings of an input signal for 1 second, ////
//// therefore counting the frequency of the signal. The input ////
//// signal's frequency is then displayed over the serial port. ////
//// ////
//// The 1s delay is created by generating a perfect 5,000,000 ////
//// cycles (it takes 0.2us for one cycle at 20Mhz). The trick is ////
//// that conditional statements have different values of cycles ////
//// depending on a TRUE or FALSE jump. ////
//// ////
//// The input signal is to be supplied to PIN C0 ////
//// ////
//// This example will work with the PCB and PCM compilers. The ////
//// following conditional compilation lines are used to include a ////
//// valid device for each compiler. Change the device and clock ////
//// for your hardware if needed. ////
/////////////////////////////////////////////////////////////////////////
//// (C) Copyright 1996,2001 Custom Computer Services ////
//// This source code may only be used by licensed users of the CCS ////
//// C compiler. This source code may only be distributed to other ////
//// licensed users of the CCS C compiler. No other use, ////
//// reproduction or distribution is permitted without written ////
//// permission. Derivative programs created using this software ////
//// in object code form are not restricted in any way. ////
/////////////////////////////////////////////////////////////////////////
#include <16f877.h>
#fuses HS,NOWDT
#use delay(clock=20000000) //one instruction=0.2us
#use rs232(baud=9600, xmit=PIN_c6, rcv=PIN_c7)
#bit t1_overflow=0x0C.0
// #bit t1_overflow=0xF9E.0 (PIC18, Reminder)
void main() {
int cycles8, cycles;
int32 freq;
long freqc_high;
long freqc_low;
while (TRUE) {
cycles8=0;
cycles=0;
freqc_high=0;
t1_overflow=0;
set_timer1(0);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
/* ___ wait one second ___ */
while (cycles!=0xFF) { //true=3, false=4
cycles8=0; //1 cycle
//start inner loop
while (cycles8!=0xFF) { //true=3, false=4
if (t1_overflow)//true=2,false=3 //----|
{t1_overflow=0;freqc_high++;}//6 cycles // |
else // |-- 8 cycles
{delay_cycles(5);} //----|
delay_cycles(62); //x
cycles8++; //1
///2 cycles to jump to top
//math: end inner loop
//math: total inner loop=((3+8+x+1+2)*255 + 4)*255
//math: if x=62.87781 then inner loops takes 5mil instructions
//math: if x=62 then inner loop takes 4942920, have to fill 57080 cycles
}
delay_cycles(216); //y
cycles++; ///1 cycle
///2 cylces to jump to top
//math: outer=(3+1+y+1+2)*255+4=57080
//math: y=(57080-4)/255)-(3+1+0+0+1+2)
//math: if y=216.827450980392156862745098039216 then outer loop cylces is 57080
//math: if y=216 then outer loop cycles is off by 211 cycles. z=211
}
delay_cycles(211); //z
/* ___ end waiting 1 second ___ */
setup_timer_1(T1_DISABLED); //turn of counter to prevent corruption while grabbing value
if (t1_overflow) //check one last time for overflow
freqc_high++;
freqc_low=get_timer1(); //get timer1 value as the least sign. 16bits of freq counter
freq=make32(freqc_high,freqc_low); //use new make32 function to join lsb and msb
printf("%LU Hz\r\n",freq); //and print frequency
}
} |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Dec 20, 2003 1:47 pm |
|
|
Well this doesn't have anything to do with using a CCP to measure the frequency. It actually uses the timer1 as a counter being driven by the frequency that is being measured. It also doesn't allow for anything else to occur while the test is in progress. I wouldn't use this method. I would stick with using the CCP module. |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Sat Dec 20, 2003 2:31 pm |
|
|
Glad you made that clear
i would stick to the capture method
Very big thanks
Jan |
|
![](templates/subSilver/images/spacer.gif) |
|