CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Frequency meter with Pic 16F877
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Dec 31, 2010 3:37 pm     Reply with quote

Quote:

how can we print int32 with printf command
& can we get frequency upto 1MHz with this code

This version of the code will accept a 1 MHz input. The displayed
frequency resolution is +/- 0.6 %. You will not get 1000001 Hz or
1000002 Hz, etc., with this program. It's more like 1000000 Hz and
the next step is 1006289 Hz. The code below displays the int32 result.
Also note that a 10 MHz crystal is used, and the 4x PLL is enabled with
the H4 fuse to give a 40 MHz oscillator frequency for the PIC.
(After programming, the power to the PIC board must be turned off and
then on again, to enable the PLL with an 18F452). The input signal must
have +5v CMOS logic levels. The high level voltage of the input signal
(Vih) must be at least 4.0 volts. This is required for the CCP input,
according to the 18F452 data sheet.
Code:

#include <18F452.h>
#fuses H4,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=40M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

int16 isr_ccp_delta;

#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

current_ccp = CCP_1;   

isr_ccp_delta = current_ccp - old_ccp;

old_ccp = current_ccp;
}

//=======================
void main()
{
int16 current_ccp_delta;
int32 frequency;

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); 
setup_ccp1(CCP_CAPTURE_DIV_16);   

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);
   
   frequency = (int32)(160000000L / current_ccp_delta);

   printf("%lu Hz\n\r", frequency);

   delay_ms(500);
  }

}
MAKInnovation



Joined: 16 Nov 2010
Posts: 61

View user's profile Send private message

PostPosted: Fri Dec 31, 2010 11:31 pm     Reply with quote

Thanks alot for your kind help
jruibarroso



Joined: 07 Jan 2006
Posts: 64
Location: Braga

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Fri Jun 29, 2012 10:41 am     Reply with quote

I'm using this code to build a digital tachometer (KM/h) but when frequency drops down 9Hz, strange values keep showing on display.
Is there any way to disable counting under 9Hz ?

I realized that current_ccp_delta only counts till 65535, that's the value near 9Hz input, if I down input freq., current_ccp_delta starts over 0 and is this that is generating errors on calculations.

Thank you
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 29, 2012 11:44 am     Reply with quote

Quote:
I realized that current_ccp_delta only counts till 65535

Add the Timer1 interrupt code to extend the timer to 32 bits:
http://www.ccsinfo.com/forum/viewtopic.php?t=33153&start=30
c0de



Joined: 14 May 2007
Posts: 14

View user's profile Send private message

PostPosted: Tue Jul 03, 2012 2:31 am     Reply with quote

Quote:
This version of the code will accept a 1 MHz input. The displayed
frequency resolution is +/- 0.6 %. You will not get 1000001 Hz or
1000002 Hz, etc., with this program. It's more like 1000000 Hz and
the next step is 1006289 Hz. The code below displays the int32 result.
Also note that a 10 MHz crystal is used, and the 4x PLL is enabled with
the H4 fuse to give a 40 MHz oscillator frequency for the PIC.
(After programming, the power to the PIC board must be turned off and
then on again, to enable the PLL with an 18F452). The input signal must
have +5v CMOS logic levels. The high level voltage of the input signal
(Vih) must be at least 4.0 volts. This is required for the CCP input,


How can I set this for a PIC16F876 (reading and displaying up to 1MHz)?
Currently I have this setup:
Code:
#include <16F876.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000) //20Mhz external crystal
#include <flex_lcd.c>


Code:

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_ccp1(CCP_CAPTURE_RE);   


and for frequency:
Code:

if(gc_capture_flag == TRUE)
  {
      frequency = (int16)((5000000L + (int32)(current_ccp_delta >> 1))/ current_ccp_delta);
      display_value(frequency);
      gc_capture_flag = FALSE;
  }

The "display_value" function prints the value on a LCD.
I'm using this circuit for generating a square wave, but with different values for the RC part:
http://bos.hack.org:8080/hacks/electronics/311.png
For example, if I use a 15pF capacitor and a 100kohm R1, the frequency should be about 415KHz. The readings in this case are erroneous (~60kHz)

The compiler version is 4.038
Thank you
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Jul 03, 2012 7:41 am     Reply with quote

So, your frequency meter reads ~60kHz.

Where is the problem?

(1) Is the oscillator running at ~60kHz, and the meter reading ~60kHz?
(2) Is the oscillator running at your expected ~400kHz and the meter reading ~60kHz?
(3) Have you probed with a 'scope?
(4) How have you built the oscillator? (PCB, white board, tag board etc)

Mike
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Tue Jul 03, 2012 8:56 am     Reply with quote

I suspect the keywords are 'should be'. Suggests no real testing.

I'd guess he is extrapolating from slower results with larger capacitors, and expecting linear behaviour. Ignoring the capacitances of the inputs, and if built on something like white board, the capacitances the rails in this have, and the slew limits of the chip (running off 5v, you will be hard pushed to get this circuit to get to the sort of frequency that is 'expected'....).

Best Wishes
c0de



Joined: 14 May 2007
Posts: 14

View user's profile Send private message

PostPosted: Tue Jul 03, 2012 10:47 am     Reply with quote

Mike Walne wrote:
So, your frequency meter reads ~60kHz.

Where is the problem?

(1) Is the oscillator running at ~60kHz, and the meter reading ~60kHz?
(2) Is the oscillator running at your expected ~400kHz and the meter reading ~60kHz?
(3) Have you probed with a 'scope?
(4) How have you built the oscillator? (PCB, white board, tag board etc)

Mike

The oscillator is running at ~400KHz but the meter (pic) reads ~60KHz. The oscillator is built on a test board (white board) but the PIC is on PCB. I have not tested yet with a scope (will do it tomorrow). As Ttelmah said, the frequency is influenced by the rails, but still the readings are wrong (according to the theory of this circuit and the values of the used components). Meanwhile is managed to modify the code and I get quite close readings.

This is the code I use now (based on an example found on this thread posted by PCM programmer):

Code:

void main() {
   
   int16 current_ccp_delta;
   int32 frequency;

   set_timer1(0);           
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   setup_ccp1(CCP_CAPTURE_DIV_16);   

   clear_interrupt(INT_CCP1);
   enable_interrupts(INT_CCP1);
   enable_interrupts(GLOBAL);
   
   lcd_init();
   delay_ms(50);

   do{
   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);
   
   frequency = (int32)(80000000L / current_ccp_delta);
   display_value(frequency);
   

   delay_ms(200);
  } while (TRUE);
}


The maximum frequency is 1250000 (I dont know if it;s ok). Anyway, I cant measure frequencies under ~120Hz.

Thanks
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Tue Jul 03, 2012 3:18 pm     Reply with quote

Quote:
The oscillator is running at ~400KHz but the meter (pic) reads ~60KHz.
How do you KNOW?

Quote:
The maximum frequency is 1250000 (I dont know if it;s ok). Anyway, I cant measure frequencies under ~120Hz.

Back in February 2012, I showed maria100 the bones of a frequency meter which operates into the 10's MHz, with 10Hz resolution. There should be no problem adapting it to 1Hz resolution.

Mike

http://www.ccsinfo.com/forum/viewtopic.php?t=47375
c0de



Joined: 14 May 2007
Posts: 14

View user's profile Send private message

PostPosted: Wed Jul 04, 2012 5:28 am     Reply with quote

Thanks Mike, I will take a look at that timing gate example...
I haven't tested yet the circuit on a scope but I have made some modifications on the code.
As far as I understand, the CCP1 value is taken from the timer1. Considering that the timer1 counts to 65535 and the overflows an starts from 0, if the event (i.e rising edge) on CPP1 occurs after the timer1 overflow then the values are erroneous. Therefore, I considered this scenario:
- enable both CCP1 and Timer1 interrupt;
- on timer1 interrupt, increment a variable which is initially = 0;
- on CCP1 interrupt, calculate the time between last and current event like this: delta = overflow_count*65535 + current_ccp, make overflow_count=0 and set timer1 to 0.
The code looks like this:
Code:

#int_ccp1
void ccp1_isr(void)
{
   int16 current_ccp;
   //static int16 old_ccp = 0; //I think this is useless
   current_ccp = CCP_1;   
   isr_ccp_delta = overflow*65536+current_ccp;
   overflow=0;
   set_timer1(0);
}
#int_timer1
void timer1_isr(void)
{
   overflow++;
}


In the main() I have the following setup:
Code:

   set_timer1(0);           
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   setup_ccp1(CCP_CAPTURE_DIV_16);   
   clear_interrupt(INT_CCP1);
   enable_interrupts(INT_CCP1);
   enable_interrupts (INT_TIMER1);//
   enable_interrupts(GLOBAL);


I have also used a float variable for the frequency:
Code:
 frequency = (float)(80000000.0 / (float)current_ccp_delta);


The circuit has the following components (measured):
R1 - 100.51Kohm, R2 - 99.68K, R3 - 99.6K, R4 - 100.1K, R5 - 0.98K
For different values of the capacitor I've got the following results:
Read frequency (Hz) \\ Calculated frequency (Hz) \\ Cap value
0.331 \\ 0.282 \\ 22uF
0.648 \\ 0.620 \\ 10uF
6.854 \\ 6.202 \\ 1uF
28.065 \\ 28.191 \\ 220nF
66.037 \\ 62.020 \\ 100nF
459,770.095 \\ 413,465.715 \\ 15pF
370,370.355 \\ 413,465.715 \\ 15pF (other type)

Regarding the code above, I'm not sure if I'm missing or not some cycles due to the interrupt execution... maybe someone more experienced can tell. Anyway, the most important thing is to have the real frequency of the circuit (I will test it on the scope as soon as possible).
Thank you

P.S: for higher values of the capacitor (over 1uF) it takes some time until the frequency remains constant... the first readings are erroneous.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Thu Jul 05, 2012 2:44 am     Reply with quote

Quote:
P.S: for higher values of the capacitor (over 1uF) it takes some time until the frequency remains constant... the first readings are erroneous.
The oscillator circuit your showing SHOULD be stable after the first oscillation cycle.

Quote:
For different values of the capacitor I've got the following results:
Read frequency (Hz) \\ Calculated frequency (Hz) \\ Cap value
.
.
.
459,770.095 \\ 413,465.715 \\ 15pF
370,370.355 \\ 413,465.715 \\ 15pF (other type)
You need to round off. There's a ~20% difference between your two 15pF caps. These figures don't tally with your previous ~60kHz measured, ~400kHz expected.

As you move to lower value capacitors you can expect the discrepancy between calculated and measured values to increase. This is due to parasitic capacitances and propagation delays. With 15pF caps the parasitics introduce significant error. You cannot assume that the quoted propagation delay from input to output always applies. The quoted value is for large input overdrive. In your circuit the overdrive is small, leading to longer delays.

Why not stand back a little while.

Suppose you have a 1MHz reference clock, and want to measure pulses of unknown frequency to 0.1%, updated once per second.

There are at least two ways to measure the frequency of incoming pulses:-

(1) Gate the incoming pulses for one second whilst counting the pulses. I.e. divide the 1MHz reference by 1^6 to generate the gate period.
(2) Measure the interpulse interval and then calculate the frequency from the period. I.e. use the incoming pulses to gate the 1MHz reference.

With either method you are always going to get counting errors of +/- 1 count.

Method (1)

(a) Above 1kHz +/- 1 count gives <0.1% error. OK
(b) Below 1kHz +/- 1 count gives >0.1% error.
(c) Below 10Hz +/- 1 count gives >10% error!

Method (2)

(a) Above 1kHz +/- 1 count gives >0.1% error.
(b) Below 1kHz +/- 1 count gives <0.1% error. OK
(c) Below 10Hz +/- 1 count gives <10ppm error. OK

Mike
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Thu Jul 05, 2012 8:58 am     Reply with quote

As Mike points out, depending on the frequency, you get better results sometimes counting pulses and at other times measuring period. What you have to be very careful with when measuring period is that your front end handles the signal correctly and actually measures from the same spots on the waveform. Noise on the signal can really screw up that measurement causing it to trigger on different points in the waveform. There is a third way that *can* give better results at low frequency and that is to use a phaselock loop to synch to the input signal then measure the phase lock although that opens a whole new box of problems, a phase lock can extract a signal from a noisy environment.

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 05, 2012 2:25 pm     Reply with quote

Quote:
I haven't tested yet the circuit on a scope

For all the posts in this thread, I don't think you have ever told us this
information:

1. The exact, measured frequencies that you are applying to the PIC's
CCP pin.

2. The voltage levels of the incoming signal.

3. The shape of the waveform and duty cycle.

4. The frequency range of the signals you want to measure.

All of these things require an oscilloscope, frequency counter, etc.
Until you do that, there's really no point in doing anything else.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group