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

Low Frequency Counter using PIN A0 from the PIC16F819
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
mitsaras



Joined: 24 Nov 2008
Posts: 9

View user's profile Send private message

Low Frequency Counter using PIN A0 from the PIC16F819
PostPosted: Tue Nov 25, 2008 9:47 am     Reply with quote

Hello all,

I am trying to calculate the frequency of a square wave signal. The input PIN is A0 and I am using the PIC16F819. I read many posts here on how to calculate the frequency but I am new to this field and I can't implement any of those codes to my circuit. So it has to be somehow specific to my needs. I am so sorry about that and I know that I set some limitations but I really need help! I need to mention that I am using the ICD2 Disk to program the PIC.

As I said the input signal is a square wave 0-5V. The frequency varies from 1 to 1000Hz. I want to calculate the frequency and then use this frequency value, to turn on or off a LED.

Below is a frame on how the code should look like.

Code:
#include <16F819.h>
#use delay (clock=8000000)
#fuses .......

******* THE CODE TO CALCUALTE THE FREQUENCY GOES HERE******


void main () {

setup_oscilator(OSC_8MHZ)

if (frequency == 16 )
do{
output_high(PIN_B4);
delay_us(500);
output_low(PIN_B4);
delay_us(500);

else

do{
output_high(PIN_B4);
delay_us(20);
output_low(PIN_B4);
delay_us(20);
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Low Frequency Counter using PIN A0 from the PIC16F819
PostPosted: Tue Nov 25, 2008 12:21 pm     Reply with quote

There are a lot of important things you do not specify, but which are essential to know before deciding how implement a frequency counter.

1. How often do you need to measure the frequency?

2. How accurate must each measurement be?

3. How much sampling time can you afford?

4. Do you need to overlap in time the measurement of frequency with any other activity?

You have made your job more difficult by insisting that the input signal is on RA0, which does not go to any CCP module or timer or interrupt. It seems your only choice is to poll RA0, which totally ties up your processor for the duration of the measurement. I guess you could poll based on a timer, but then your period measurements would only be as accurate as the timer interrupt rate. That may not be a problem at 1 Hz, but it may be a problem at 1000 Hz. Having to serve such a wide range (1 Hz to 1000 Hz) also creates problems, all of which can be solved by sufficiently relaxing the specifications, none of which you have given.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
ECACE



Joined: 24 Jul 2006
Posts: 94

View user's profile Send private message

PostPosted: Tue Nov 25, 2008 12:33 pm     Reply with quote

I agree with what RLScott said, but I noticed that you said the input signal is 0-5 volts. Do you mean it has a variable amplitude as well, or just that it has a fixed amplitude of 0 or 5 volts?

If the first were the case, then are you trying to read the ADC on A0? Sorry, just don't know enough about your application to offer more help. If you answer RL's questions and mine above, we might be able to help.

Best of luck.
_________________
A HW Engineer 'trying' to do SW !!! Run!!!
mitsaras



Joined: 24 Nov 2008
Posts: 9

View user's profile Send private message

Additional Information
PostPosted: Tue Nov 25, 2008 3:00 pm     Reply with quote

Hello, and many thanks for looking my problem. I will try to add any information which may be useful.
1. First of all, I need to measure the frequency every once cycle. Which means that if the frequency is 10 Hz then i need to measure the frequency every 0.1 sec, but if the frequency change to 100Hz then I have to measure the frequency every 0.01 sec. In my circuit the input frequency changes continuesly so if I can measure the frequency every one cycle, then it would be perfect.
2. Accurancy is not so important for me. The useful frequency range for my circuit is from 5Hz to 100Hz. Therefore if the frequency number has an interval of 0.1 then it would be ideal.
3. I am not so sure if I can answer that question but I want to say that as long as I calculate the frequency every one cycle, I do not bother about the sampling time. (I hope that is not a problem!!)
4. No, I do not need to overlap in time the measurement of frequency with any other activity.
5. I chose RA0 pin as an input because i did not have any luck when I tried the CCP before. Frankly, I do not have any problem using any PIN suitable for that, e.g. CCP. So if you think that it will work using a different pin then I have no problem with that.
6. The square wave input amplitude is fixed. So it's either 0V or 5V. Only the square wave frequency varies.

I imagined that the code will have 2 stages. The first stage will be a loop which will calculate continuesly the input frequency forever every one cycle, and it will send the value of the frequency to the second stage. The second stage will turn on and off continuesly a LED.

Again many thanks for helping me. If you need any more information please let me know and I will reply asap.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Additional Information
PostPosted: Tue Nov 25, 2008 3:23 pm     Reply with quote

mitsaras wrote:

2. Accurancy is not so important for me. The useful frequency range for my circuit is from 5Hz to 100Hz. Therefore if the frequency number has an interval of 0.1 then it would be ideal.

Are you now saying that it doesn't have to work with frequencies below 5Hz or above 100Hz? If so, that does make the job easier. So let's assume we are working with signals that are between 5Hz and 100Hz. When you say "an interval of 0.1" I assume you mean the resolution should be 0.1 Hz. Let's apply that resolution to the hardest case: 100Hz. To be able to distinguish between 100Hz and 99.9Hz, you need to measure the period (10mSec) to within 10uSec. That is possible, but very hard to do without using a CCP module. It would be easy with a CCP module in input capture mode. But if you have to poll RA0, then you must poll it every 10uSec. So if you have an interrupt that lasts for more than 10uSec, then you will miss this deadline. And you will need interrupts to flashs the LEDs (the "second stage" as you called it). You can't flash the LEDs in the main program because it is too busy polling RA0. So you would need to use a timer interrupt to flash the LEDs.
Quote:

4. No, I do not need to overlap in time the measurement of frequency with any other activity.

Well, yes you do. Flashing the LEDs is the other activity, and it must go on in parallel with polling RA0 to measure frequency.
Quote:

5. I chose RA0 pin as an input because i did not have any luck when I tried the CCP before.

Take the time to understand how Input Capture mode works and use it.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Nov 25, 2008 4:17 pm     Reply with quote

The 16F819 has a CCP module. Here is a large thread (3 pages) on
using the CCP to measure frequency, including low frequencies:
http://www.ccsinfo.com/forum/viewtopic.php?t=29963
ECACE



Joined: 24 Jul 2006
Posts: 94

View user's profile Send private message

PostPosted: Tue Nov 25, 2008 4:17 pm     Reply with quote

Best bet would be to use the CCP. Another option would to use the change on port b interrupt. You could keep track of when it was last high or low, add the two together and you have your freq. That could happen all within the interrupt. Then when you fall under or above the freq window, set a flag stating you are below or above the freq, again, within the interrupt. Then outside the interrupt you just monitor the flag to see if you should be flashing the LED's or not.

Many ways to skin the same cat.

Good luck.
_________________
A HW Engineer 'trying' to do SW !!! Run!!!
mitsaras



Joined: 24 Nov 2008
Posts: 9

View user's profile Send private message

Low frequency calculator
PostPosted: Tue Dec 09, 2008 7:41 am     Reply with quote

Hello,

I used the code that you suggested but I have a few questions:

The purpose of my project is to measure the input frequency and then send continuously a pulse in an output. The pulse that I have to send in the output is related to the input frequency.
For that reason to capture the input frequency I am using the ccp1 (PIN_8) of the PIC16f819 as an input. the input rectangular signal is provided from a function generator. I am using the internal clock @4MHz.

The code is written below:
Code:

#include <16F819.H>
#fuses XT,NOWDT, NOPROTECT, NOLVP,INTRC_IO, NOPUT, NOMCLR,NOBROWNOUT, NOCPD, NOWRT, NODEBUG
#use delay(clock=4000000)

// This global variable holds the time interval
// between two consecutive rising edges of the
// input signal.   
int16 isr_ccp_delta;

// When a rising edge occurs on the input signal,
// the CCP1 will 'capture' the value of Timer1
// at that moment.  Shortly after that, a CCP1
// interrupt is generated and the following isr
// is called.   In the isr, we read the 'captured'
// value of Timer1.  We then subtract from it the
// Timer1 value that we 'captured' in the previous
// interrupt.  The result is the time interval
// between two rising edges of the input signal.
// This time interval is then converted to a frequency
// value by code in main(). 
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

// Read the 16-bit hardware CCP1 register
current_ccp = CCP_1;  // From 16F819.H file

// Calculate the time interval between the
// previous rising edge of the input waveform
// and the current rising edge.  Put the result
// in a global variable, which can be read by
// code in main().
isr_ccp_delta = current_ccp - old_ccp;

// Save the current ccp value for the next pass.
old_ccp = current_ccp;
}


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


setup_oscillator(OSC_4MHZ);      //use internal 4MHz clock

// Setup Timer1 and CCP1 for Capture mode so that
// we can measure the input signal's frequency.
// The input signal comes from an external function 
// generator, which is connected to the CCP1 pin with a wire.


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

// Clear the CCP1 interrupt flag before we enable
// CCP1 interrupts, so that we don't get an unwanted
// immediate interrupt (which might happen).
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);


while(1)
  {

   // Get a local copy of the latest ccp delta from the isr.
   // We have to disable interrupts when we read a global
   // isr variable that is larger than a single byte.
   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);

   // To calculate the frequency of the input signal,
   // we take the number of clocks that occurred
   // between two consecutive edges of the input signal,
   // and divide that value into the number of Timer1
   // clocks per second.   Since we're using a 4 MHz
   // internal clock, the Timer1 clock is 1 MHz (Timer1 runs
   // at the instruction cycle rate, which is 1/4 of the
   // internal clock frequency).  For example, suppose the
   // the input waveform has a frequency of 244 Hz.
   // 244 Hz has a period of about 4098 usec.
   // Timer1 is clocked at 1 MHz, so between two
   // consecutive rising edges of the input signal,
   // it will count up by 4098 clocks.  To find the
   // frequency, we divide 4098 into the number of
   // clocks that occur in 1 second, which is 1000000.
   // This gives 1000000 / 4098 = 244 Hz.
   
   frequency = (int16)(1000000L / current_ccp_delta);
   // Display the calculated frequency.
   
     if (frequency == 15)   
      do {
         output_high(PIN_B4);
         delay_us(5000);
         output_low(PIN_B4);
         delay_us(5000);
         }
         while (TRUE);
else if (frequency == 16)   
      do {
         output_high(PIN_B4);
         delay_us(4000);
         output_low(PIN_B4);
         delay_us(4000);
         }
         while (TRUE);
else if (frequency == 17)   
      do {
         output_high(PIN_B4);
         delay_us(3000);
         output_low(PIN_B4);
         delay_us(3000);
         }
         while (TRUE);
else if (frequency == 18)   
      do {
         output_high(PIN_B4);
         delay_us(2000);
         output_low(PIN_B4);
         delay_us(2000);
         }
         while (TRUE);
else if (frequency == 19)   
      do {
         output_high(PIN_B4);
         delay_us(1000);
         output_low(PIN_B4);
         delay_us(1000);
         }
         while (TRUE);
else if (frequency == 20)   
      do {
         output_high(PIN_B4);
         delay_us(500);
         output_low(PIN_B4);
         delay_us(500);
         }
         while (TRUE);      
else
      
         do {
         output_high(PIN_B4);
         delay_us(10);
         output_low(PIN_B4);
         delay_us(10);
         }
         while (TRUE);
      
  }

}


My questions are:
1. can i use this code for frequencies between 5 and 50 Hz or I have to change something?
2. What do i have to change in order to make use of the 4MHz crystal provided by the PICDEM2 Plus board.
3. What do I have to change in the "if" section so that any frequency e.g between 16.5 - 17.4 to be considered as 17 and anything between 17.5 - 18.4 to be considered as 18 and so on.
4. So far the results are not what I expect, could you please help me with that?

Thank you very much
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Re: Low frequency calculator
PostPosted: Tue Dec 09, 2008 9:08 am     Reply with quote

Quote:

1. can i use this code for frequencies between 5 and 50 Hz or I have to change something?

Look at 5 Hz. The time between rising edges is 200 msec. That is 200,000 usec. Timer 1 is counting in usec (4 MHz osc. divided by 4). So Timer 1 will count 200,000 counts from one capture to the next. But Timer 1 is just a 16-bit timer, so it overflows at 65,535. It will overflow 3 times by the time you get another capture. So you would have to change a lot to measure down to 5 Hz. But 16 Hz might be OK, if you use unsigned arithmetic with your capture values.

Quote:

2. What do i have to change in order to make use of the 4MHz crystal provided by the PICDEM2 Plus board.

I don't know the PICDEM2 Plus board, but whatever it is, you should do it because the internal 4 MHz oscillator is a poor reference for any frequency measuring application.
Quote:

3. What do I have to change in the "if" section so that any frequency e.g between 16.5 - 17.4 to be considered as 17 and anything between 17.5 - 18.4 to be considered as 18 and so on.

There are several ways you could handle this. One is to replace the "==" with the logical combination:
Code:

if (frequency > 17.5 && frequency < 18.4)

Another way that is faster is to convert the floating point frequency to a rounded integer version just once and then use that integer version for all your comparisons:
Code:

  IntFreq = (int16)(frequency + 0.5);
   . . .
  if(IntFreq == 17)

The reason you must add 0.5 is that the conversion to integer does not round, it truncates.
Quote:

4. So far the results are not what I expect, could you please help me with that?

Maybe, if you said what you expect and what you are getting.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 09, 2008 12:41 pm     Reply with quote

That thread discusses the changes required to capture various frequency
ranges. It also has code to do the rounding operation (on the last page).
http://www.ccsinfo.com/forum/viewtopic.php?t=29963
mitsaras



Joined: 24 Nov 2008
Posts: 9

View user's profile Send private message

A low frequency calculator using PIC16F819
PostPosted: Wed Dec 17, 2008 8:54 am     Reply with quote

Hello,

first of all I would like to say many thanks to the people that helped me so far. It is really good to know that there is somebody to help you when you stuck and there is no way to continue, so once again many thanks

As I said so far I need a c-code to calculate the input frequency and based on that frequency a square-wave in the output is then produced.

The code for that is given below:
Code:

#include <16F819.H>
#fuses NOWDT, NOPROTECT, NOLVP,INTRC_IO, NOPUT, NOMCLR,NOBROWNOUT, NOCPD, NOWRT, NODEBUG
#use delay(clock=4000000)

// This global variable holds the time interval
// between two consecutive rising edges of the
// input signal.   
int16 isr_ccp_delta;

// When a rising edge occurs on the input signal,
// the CCP1 will 'capture' the value of Timer1
// at that moment.  Shortly after that, a CCP1
// interrupt is generated and the following isr
// is called.   In the isr, we read the 'captured'
// value of Timer1.  We then subtract from it the
// Timer1 value that we 'captured' in the previous
// interrupt.  The result is the time interval
// between two rising edges of the input signal.
// This time interval is then converted to a frequency
// value by code in main(). 
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

// Read the 16-bit hardware CCP1 register
current_ccp = CCP_1;  // From 16F819.H file

// Calculate the time interval between the
// previous rising edge of the input waveform
// and the current rising edge.  Put the result
// in a global variable, which can be read by
// code in main().
isr_ccp_delta = current_ccp - old_ccp;

// Save the current ccp value for the next pass.
old_ccp = current_ccp;
}


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

setup_oscillator(OSC_4MHZ);      //use internal 4MHz clock

// Setup Timer1 and CCP1 for Capture mode so that
// we can measure the input signal's frequency.
// The input signal comes from an external function 
// generator, which is connected to the CCP1 pin with a wire.


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

// Clear the CCP1 interrupt flag before we enable
// CCP1 interrupts, so that we don't get an unwanted
// immediate interrupt (which might happen).
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);


while(1)
  {

   // Get a local copy of the latest ccp delta from the isr.
   // We have to disable interrupts when we read a global
   // isr variable that is larger than a single byte.
   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);
   
   //The output pin is pin number 10, PIN_RB4
   //Once we know the time (period) between two rising edges (current_ccp_delta)
   //then in the output a square wave is produced.
   //the square wave in the ouput has Ton and Toff time related to the period
   //So if the period is e.g. 0.05s or in 16-bit -> 50000 then the
   // Ton = Toff = 10000us
if (current_ccp_delta > 60975 && current_ccp_delta < 64516)   
      do {
         output_high(PIN_B4);
         delay_us(25000);
         output_low(PIN_B4);
         delay_us(25000);
         }
         while (TRUE);
else if (current_ccp_delta > 57142 && current_ccp_delta < 60975)   
      do {
         output_high(PIN_B4);
         delay_us(20000);
         output_low(PIN_B4);
         delay_us(20000);
         }
         while (TRUE);
else if (current_ccp_delta > 54347 && current_ccp_delta < 57142)   
      do {
         output_high(PIN_B4);
         delay_us(15000);
         output_low(PIN_B4);
         delay_us(15000);
         }
         while (TRUE);
else if (current_ccp_delta > 51282 && current_ccp_delta < 54347)   
      do {
         output_high(PIN_B4);
         delay_us(12000);
         output_low(PIN_B4);
         delay_us(12000);
         }
         while (TRUE);
else if (current_ccp_delta > 49019 && current_ccp_delta < 51282)   
      do {
         output_high(PIN_B4);
         delay_us(10000);
         output_low(PIN_B4);
         delay_us(10000);
         }
         while (TRUE);
else if (current_ccp_delta > 46511 && current_ccp_delta < 49019)   
      do {
         output_high(PIN_B4);
         delay_us(8000);
         output_low(PIN_B4);
         delay_us(8000);
         }
         while (TRUE);      

else if (current_ccp_delta < 46511)   
      do {
         output_high(PIN_B4);
         delay_us(100);
         output_low(PIN_B4);
         delay_us(100);
         }
         while (TRUE);
            
  }

}

The code calculates the time between the two rising edges of the input signal (period) and then on pin 10 or PIN_RB4 a square wave is produced.
the Ton and Toff time is the same and related to the period or the time between the two rising edges.

To test that code I used as an input a 20Hz square-wave signal produced from an analog function generator. Nevertheless, no matter what frequency I use the output square wave have Ton and Toff fixed to 100us. Is it possible to have a look at that?


Also I am using PIC16F819. Could you please tell me if the input signal goes to pin 8 or pin 9 ?
mitsaras



Joined: 24 Nov 2008
Posts: 9

View user's profile Send private message

Low frequency calculator
PostPosted: Fri Mar 13, 2009 6:20 am     Reply with quote

Hello PCM Programmer,

I have a question regarding your code. At the moment the code is able to read frequencies as low as 15Hz. Is it possible to make a few changes to the code, so that it can read lower frequencies e.g. down to 5Hz?

I know that somebody else had the same question !!!!!, but he was using high clock frequency (48MHz). Sorry but my lack of knowledge on programming makes it difficult for me to understand it.

So, keeping the same code, and the same clock speed 4MHz is it possible to change the code so that it can read from minimum of 5Hz up to 100 Hz or even more (I do not bother about high frequency!!)
Code:

#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

// This global variable holds the time interval
// between two consecutive rising edges of the
// input signal.   
int16 isr_ccp_delta;

// When a rising edge occurs on the input signal,
// the CCP1 will 'capture' the value of Timer1
// at that moment.  Shortly after that, a CCP1
// interrupt is generated and the following isr
// is called.   In the isr, we read the 'captured'
// value of Timer1.  We then subtract from it the
// Timer1 value that we 'captured' in the previous
// interrupt.  The result is the time interval
// between two rising edges of the input signal.
// This time interval is then converted to a frequency
// value by code in main(). 
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

// Read the 16-bit hardware CCP1 register
current_ccp = CCP_1;  // From 16F877.H file

// Calculate the time interval between the
// previous rising edge of the input waveform
// and the current rising edge.  Put the result
// in a global variable, which can be read by
// code in main().
isr_ccp_delta = current_ccp - old_ccp;

// Save the current ccp value for the next pass.
old_ccp = current_ccp;
}


//=======================
void main()
{
int8 duty;
int8 pr2_value;
int16 current_ccp_delta;
int16 frequency;


// Setup the ADC so we can read a value from 0 to 255
// as we turn a trimpot which is connected to pin A0.
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_8);  // Divisor for 4 MHz crystal
set_adc_channel(0); 
delay_us(20);

// The CCP2 will be used in PWM mode to output a test
// signal that will be connected to the CCP1 pin.
// The test signal can be varied from 244 Hz to 2016 Hz
// by turning the trimpot on pin A0.
setup_ccp2(CCP_PWM);

// Setup Timer1 and CCP1 for Capture mode so that
// we can measure the input signal's frequency.
// The input signal comes from the CCP2 pin, which
// is connected to the CCP1 pin with a wire.
set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); 
setup_ccp1(CCP_CAPTURE_RE);   

// Clear the CCP1 interrupt flag before we enable
// CCP1 interrupts, so that we don't get an unwanted
// immediate interrupt (which might happen).
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);


while(1)
  {

   // Read the A/D value from the trimpot.
   // This is a value from 0 to 255.  We limit
   // it to a minimum of 30 for the purposes
   // of this test program.  This will limit the
   // test signal to 2016 Hz maximum frequency.
   pr2_value = read_adc();
   if(pr2_value < 30)
      pr2_value = 30;

   // Configure CCP2 to put out a rectangular
   // waveform with approximately a 50% duty
   // cycle.  The setting of the trimpot controls
   // the frequency of this waveform.
   setup_timer_2(T2_DIV_BY_16, pr2_value, 1);
   duty = pr2_value / 2;
   set_pwm2_duty(duty);

   
   // Now calculate the frequency. 

   // Get a local copy of the latest ccp delta from the isr.
   // We have to disable interrupts when we read a global
   // isr variable that is larger than a single byte.
   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);

   // To calculate the frequency of the input signal,
   // we take the number of clocks that occurred
   // between two consecutive edges of the input signal,
   // and divide that value into the number of Timer1
   // clocks per second.   Since we're using a 4 MHz
   // crystal, the Timer1 clock is 1 MHz (Timer1 runs
   // at the instruction cycle rate, which is 1/4 of the
   // crystal frequency).  For example, suppose the
   // the input waveform has a frequency of 244 Hz.
   // 244 Hz has a period of about 4098 usec.
   // Timer1 is clocked at 1 MHz, so between two
   // consecutive rising edges of the input signal,
   // it will count up by 4098 clocks.  To find the
   // frequency, we divide 4098 into the number of
   // clocks that occur in 1 second, which is 1000000.
   // This gives 1000000 / 4098 = 244 Hz.
   
   frequency = (int16)(1000000L / current_ccp_delta);

   // Display the calculated frequency.
   printf("%lu Hz\n\r", frequency);

   delay_ms(500);
  }

}

Thank you
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 13, 2009 1:11 pm     Reply with quote

To make it work at a lower frequency, you need to reduce the clock
speed of Timer1. For example, with a 1 MHz Timer1 clock and a 5 Hz
input signal, you have 200,000 counts between edges of the input signal.
(That's from 1 MHz / 5 Hz = 200,000). But 200K exceeds the size of
Timer1, which can only count up to 65,535. The solution is to reduce
the speed of the Timer1 clock. We can use a divisor 4, and reduce it
to 250 KHz. This is done with the T1_DIV_BY_4 value from the 16F877.h
file.

The equation becomes 250 KHz / 5 Hz = 50,000 counts for Timer1. Now
we won't overflow past the Timer1 count limit of 65,535. It will work.

Here are the changes to the code. Change the Timer1 clock divisor
to the value shown in bold below:
Quote:
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
setup_ccp1(CCP_CAPTURE_RE);


Next change the frequency calculation to use the new, lower value of
250 KHz for the Timer1 clock frequency:
Quote:
frequency = (int16)(250000L / current_ccp_delta);


Also, the program that you posted was a self-contained demo for the
PicDem2-Plus board. It uses CCP2 in PWM mode to act as a frequency
generator. You're supposed to put a jumper on the board between the
CCP1 and CCP2 pins. But the frequency generator only goes down to
244 Hz, as the minimum frequency.

I assume you know this, and in fact, you are not using the frequency
generator portion of the code. You're only interested in the tachometer
portion of it.
soulraven



Joined: 08 Feb 2009
Posts: 72
Location: campulung muscel

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

PostPosted: Fri Mar 13, 2009 1:30 pm     Reply with quote

and for a 20Mhz, how i calculate?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 13, 2009 1:36 pm     Reply with quote

With a 20 MHz oscillator, the basic Timer1 clock will be 5 MHz.
The largest divisor that is available is T1_DIV_BY_8. This gives a
Timer 1 clock of 625 KHz (from 5 MHz / 8). With that clock, you
can capture a frequency down to about 10 Hz. The changes would be:
Quote:
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
setup_ccp1(CCP_CAPTURE_RE);

Quote:
frequency = (int16)(625000L / current_ccp_delta);
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 1, 2  Next
Page 1 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