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

Determining square-wave frequency input into pic
Goto page Previous  1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Fri Oct 17, 2008 1:09 pm     Reply with quote

PCM programmer wrote:
Here's the answer to your question:

To make the tachometer example work with a 1 Hz input signal while the
PIC is running at 48 MHz, you need to extend Timer1 to 24 bits (currently
it's only 16 bits wide).


Hi,

I noticed that the Driver display wrong values when we use low ones (under 20Hz) and Freq values-1 if upper (for example 74hz instead of 75hz) I replaced CCP1 with CCP2 and I omitted the Comparison part.

here is my code, am I wrong ?:

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, bits=8)

 
int16 isr_ccp_delta;


#int_ccp2
void ccp2_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;


current_ccp = CCP_2;  // From 16F877.H file


isr_ccp_delta = current_ccp - old_ccp;


old_ccp = current_ccp;
}


//=======================
void main()
{


int16 current_ccp_delta;
int16 frequency;





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

clear_interrupt(INT_CCP2);
enable_interrupts(INT_CCP2);
enable_interrupts(GLOBAL);


while(1)
  {


   
   // Now calculate the frequency.

   disable_interrupts(GLOBAL);
   current_ccp_delta = isr_ccp_delta;
   enable_interrupts(GLOBAL);

   
   frequency = (int16)(1000000L / current_ccp_delta);

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

   delay_ms(500);
  }

}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 17, 2008 3:06 pm     Reply with quote

Quote:

[it displays] Freq values-1 if upper (for example 74hz instead of 75hz

This problem occurs because the equation is not rounding off the result.
To fix it, use this equation instead:
Code:
frequency = (int16)((1000000L + (int32)(current_ccp_delta >> 1))/ current_ccp_delta);



Quote:
I noticed that the Driver display wrong values when we use low ones (under 20Hz)

Actually I think it works down to about 16 Hz. To make it work with
lower input frequencies, you need to use a prescaler on the Timer1
clock. Also adjust the equation for the prescaler. A prescaler of 8
allows it to work down to about 2 Hz input signal, as shown in bold:
Quote:
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);

Adjust the numerator in the freq equation, as shown in bold:
Quote:
frequency = (125000L + (int32)(current_ccp_delta >>1)) / current_ccp_delta;
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Sun Oct 19, 2008 12:52 am     Reply with quote

dear PCM Programmer,

your code works fine ! Smile

but due to my applications , the PIC should run at 20Mhz, hence would the best (probably the unique ?) solution to keep correct the display of frequeuency be to extend the Timer1 to 20bits (keep DIV_BY_8)* or 24 bits (change to DIV_BY_1)** ????


*: Number of Timer 1 Clocks between two captured edges = 625 000 (1 000 000*5/8) /// 20bits= 1 048 575

**:Number of Timer 1 Clocks between two captured edges = 5 000 000 (1 000 000*5) /// 24bits= 16 777 215


what do you think about?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 19, 2008 1:26 am     Reply with quote

There is already code for the 24-bit Timer. It's either in this thread or
elsewhere in the forum.
soulraven



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

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

PostPosted: Mon Feb 09, 2009 10:22 am     Reply with quote

Hi, I tried and I use the code below, but go, show me 0hz, you can help me with what was wrong? plus I do not want to use the PWM output and reserved for dimmer light.
Below is the code and the part parents project

Code:
#include <16f877A.h>
#device *=16
#device adc=8 
//#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP, NOCPD
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
//#use delay (clock=4000000,restart_wdt) //8.00 MHz
#use delay(clock=48000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#include <1wire.h>
#include <math.h>
#include <1wire.c>
#include <ds1820.c>
#include <flex_lcd.c>


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

// 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;
int32 g32_ccp_delta;
int16 frequency;
gc_capture_flag == FALSE;

lcd_init(); //LCD start
lcd_putc("\f");

// 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_64); // Divisor for 48 MHz oscillator
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 = g32_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.
   
   if(gc_capture_flag == TRUE)
  {
   frequency = (int16)(12000000L / current_ccp_delta);
   
   // Display the calculated frequency.
lcd_gotoxy(1,1);   
printf(lcd_putc,"%lu Hz    \n\r", frequency);
   gc_capture_flag = FALSE;
  }
else
  {
   printf(lcd_putc,"No signal\n\r", frequency);
  }
}
}

http://img49.imageshack.us/my.php?image=calculatortm2.jpg[img][/img]
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 09, 2009 11:12 am     Reply with quote

Quote:
#include <16f877A.h>
#device *=16
#device adc=8
//#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP, NOCPD
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
//#use delay (clock=4000000,restart_wdt) //8.00 MHz
#use delay(clock=48000000)

16F877A does not work at 48 MHz. The maximum is 20 MHz and it
requires the HS fuse. Are you running this test in real hardware or is
this a simulator project ?
soulraven



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

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

PostPosted: Mon Feb 09, 2009 11:27 am     Reply with quote

simulated, proteus......
how to switch on the input to AN0, and eliminate the CCP1 and CCP2, because i want to use this output for dimmer the light and the display
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 09, 2009 11:54 am     Reply with quote

This thread is about using the CCP to find the frequency. If you want to
ask about finding the frequency without using the CCP, you should start
a new thread.
Newbie1
Guest







PostPosted: Mon Jun 29, 2009 6:49 pm     Reply with quote

Hi all,
I found this code and it seems like it's exactly what I want to do.... ( I will have to try to modify it though). I am trying to get it to work. I copied it exactly, and changed only inputs ie AN2 instead of AN0. CCP1 and CCP2 remain the same. I have a simulator working and it doesn't seem to like to fire the CCP1 interrupt. I have had this same problem with a smaller "sample" test code I was trying aswell. The simulator can debug, and it says that CCP1 is enabled, then microseconds later, the debugger says that CCP1 is disabled. I have not been able to get interrupts working with the CCP1, and I'm thinking it's because they are not enabled properly. However, I am using your code exactly and it seems like something is causingit to disable the instant after its enabled. Maybe my fuses? I'm not sure.
Thanks for the help!
I really appreciate it.
Newbie1.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 29, 2009 7:54 pm     Reply with quote

Your simulator may have bugs. The code works in real hardware.
There's nothing I can do about your simulator.
Guest








PostPosted: Mon Jun 29, 2009 10:59 pm     Reply with quote

Hi thanks for the reply!
I tried a real hardware setup. I tested to make sure I have the ADC configured properly. So it is in fact reading an ADC properly. And I connected the CCP2 to the CCP1 directly. My lcd only displays no signal. No matter what. I tried simpler programs with CCP1. and it didn't work either! I know I should maybe post this elsewhere. But since we know this code is right, I figured I could maybe solve it here. What else could I be doing wrong? The sim, so far has been pretty accurate to what is happening with my chip... not saying that your program has errors. I certainly believe you that it works! In the sim, it shows CCP1 enabled, and then the very next instruction it has been disabled. The only thing that differs in my code from yours is the beginning here.

Code:

#include <16F887.h>
#device adc=10
#fuses INTRC_IO,NOWDT,PUT,NOMCLR,NOPROTECT,NOCPD,NOBROWNOUT,NOIESO,NOFCMEN,NOLVP,NODEBUG
//#fuses INTRC_IO,NOWDT,NOMCLR,
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#include <lcd16x2.c>

I didn't include the math.h files also, but it still managed to compile.
Thanks for the help!
Newbie1!
Guest








PostPosted: Mon Jun 29, 2009 11:00 pm     Reply with quote

oops! nevermind that //#fuses!!!!
Thanks!
Newbie1!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 29, 2009 11:12 pm     Reply with quote

Start a new thread, and begin with a simple LED blinking program.
deperkin



Joined: 04 Feb 2009
Posts: 83
Location: PA

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

500 KHz clock...
PostPosted: Thu Sep 09, 2010 7:34 am     Reply with quote

PCM programmer,

First of all I would like to say thank you for posting this. It seems helpful to alot of people.

I am using an 18F4550 and a dc motor with an open collector tachometer. I have converted this using a 2n3906 to get a ttl signal to the pic.

I had started to approach it by using an interrupt for this tachometer, but would like to incorporate this code, as I feel it would work better.

I am using a RTCC for other parts of the code, and timer 2 for pwm.
I have connected now the tachometer output to the CCP1.
I have my clock set at 500 kHz however.

I would like to read RPM's from 4000 to ~0... at low frequencies I will just display zero however.

In order to incorporate this code you have generously provided, would I just keep the prescaler to divide by 1 and set the frequency to 125000L/... ??

I am not sure if using #ocs 500 kHz is not allowing this added programming to work, or not. The 500 kHz seems to be the best for the rest of my programming however.

It seems to work, but I get RPM's bouncing from 500 to 9000 when i am at full speed (which should be about 4000).


Thank you again for all of your help.
deperkin



Joined: 04 Feb 2009
Posts: 83
Location: PA

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

solution
PostPosted: Thu Sep 09, 2010 6:04 pm     Reply with quote

Thank you...

I got it to work like a charm.

I used 125000L in the frequency formula... with a divide_by_8 for timer 1.

The problem ended up being in my tachometer signal... I checked it with a scope and I noticed some odd blips which were causing the issue.

After getting rid of the 2N3906 that I was using, and exchanging it for a simple pull-up resistor it worked like a charm.

Thanks again PCM programmer... good job as always.
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, 3, 4  Next
Page 3 of 4

 
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