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

Need Help with Capture Module!!!

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

Need Help with Capture Module!!!
PostPosted: Mon Apr 23, 2007 5:22 pm     Reply with quote

Greetings All,

I am having a difficult time getting the capture module to work. All I'm trying to do is measure the frequency/period and duty cycle of a square wave tied into the CCP1 port. Please help! It works for most of the time but when I get past a certain frequency I get invalid values.

Does anyone know the basics of the capture module and anything I need to be aware of? Oscillator speed, max capture frequency, etc.???

Please Help!

Thanks!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Apr 23, 2007 5:39 pm     Reply with quote

Post the details.

1. Post the input frequency which causes a problem.

2. Post the PIC's oscillator frequency.

3. Post the CCP prescaler that you're using.

4. Post the Timer1 prescaler.
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 9:17 am     Reply with quote

Thanks for the response PCM programmer, here is the info:

1.) After 22KHz problem starts to arise.

2.) PIC oscillator frequency: 8MHz

3.) CCP Prescaler: 1

4.) TIMER1 prescaler: 1

5.) CCP1 is set to capture first rising edge.
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 1:48 pm     Reply with quote

You are probably running into interrupt processing time problems.
At 22kHz the period is 45uS, and the interrupt latency and processing time (saving and restoring context as well as the actual code) will be close to that.

Instead of counting over one period, count over 16 cycles.

setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_ccp1(CCP_CAPTURE_RE|CCP_CAPTURE_DIV_16);

This will also provide an averaging effect.

Also, a faster method is not to use interrupts at all, just test the CCP1IF flag bit in the hardware (the capture will happen regardless of what the
processor is doing). Leave timer 1 to free run and take two captures - the measurement is the difference between the two captured values.

For a 16F
#byte PIR1 = 0x0C
#bit CCP1IF = PIR1.2

Code:

int16 new_t1count;
int16 old_t1count;
int16 delta_count;

CCP1IF = 0;
while (!CCP1IF);
old_t1count = CCP_1;
CCP1IF = 0;
while (!CCP1IF);
new_t1count = CCP_1;
delta_count = new_t1count - old_t1count;


There will be a lower input frequency limit. The difference between successive captures needs to be less than the 16 bit width of timer 1.


Last edited by Kenny on Tue Apr 24, 2007 11:19 pm; edited 1 time in total
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 2:51 pm     Reply with quote

OMG.....it works!!! Thank you very much Kenny. I had a feeling my interrupt might have been taking up too much time between captures. I no longer have any ISRs in my code, I just follow the flag bit like you suggested.

Thanks again and your suggestion was very much appreciated.
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

PostPosted: Wed Apr 25, 2007 3:55 pm     Reply with quote

Ok so...upon calculating the difference between the 1st and 2nd capture, I can easily call that the PR2 value. Hence, it can be loaded into the "period" parameter of setup_timer_2(mode, period, postscale) function, for the PWM module. What about the duty cycle? I cannot find a way to retrieve the duty cycle and come up with a value to store onto the set_pwmx_duty(value) function. PLease help!!!

Thanks.
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Thu Apr 26, 2007 3:55 am     Reply with quote

Your question on an earlier thread suggested that you wanted the pwm out from the third CCP to be the same frequency and duty cycle as the input. That didn't make sense because the input signal is already what you need and explains why there were no replies.

Do you mean "I want a pwm out from the third CCP at a fixed frequency of about ....Hz, and the duty cycle to be the same as that of the input. The input frequency can vary from ....Hz to ....Hz "?
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

PostPosted: Thu Apr 26, 2007 8:52 am     Reply with quote

No...I want to REPLICATE a signal going into the CCP1 pin or CCP2 (both in capture mode) and output that same signal on the CCP3 pin (PWM mode). This means that the output PWM will vay depending on what signal is coming in the CCP1 pin; the same signal coming in is the same signal coming out.

I know the input is all I need. So I capture the period and duty cycle of the input signal (from CCP1 or CCP2). That same period and duty cycle has to be present on the output signal as well (CCP3).

As of right now, the input signal period is successfuly measured and replicated on the output signal. Now, I am having problems successfuly measuring the duty cycle of the input signal and replicating it on the output signal.

Thanks for all your help.
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

PostPosted: Thu Apr 26, 2007 11:43 am     Reply with quote

Here's some code for you to look at and review:

#include <16F737.h>

#fuses NOWDT, NOPROTECT, INTRC_IO, PUT, NOBROWNOUT, MCLR, CCP2C1, DEBUG, NOFCMEN, NOIESO, NOBORSEN
#byte PIR1 = 0x0C
#byte PIR2 = 0x0C
#bit CCP1IF = PIR1.2
#bit CCP2IF = PIR2.2

int16 period_capture, old_capture, duty_capture;
int16 duty_cycle;
int8 PR2_val, change_osc = FALSE;

/***********************************************************************/
/****************************Main***************************************/
/***********************************************************************/
void main()
{
set_tris_C(0xFF); // set C port as input
set_tris_B(0xDF); // RB5 as output

setup_adc(ADC_OFF); // turn off ADC
setup_comparator(NC_NC_NC_NC); // turn off comparator
setup_oscillator(OSC_31KHZ); // change oscillator speed

setup_ccp1(CCP_CAPTURE_RE | CCP_CAPTURE_DIV_16); // Configure CCP1 to capture rising edge
setup_ccp2(CCP_CAPTURE_FE | CCP_CAPTURE_DIV_16); // Configure CCP2 to capture falling edge
setup_ccp3(CCP_PWM); // Configure CCP3 as PWM
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); // Set timer1 to run at (system_clk/4)

while(1)
{
CCP1IF = 0;
while (!CCP1IF);
old_capture = CCP_1; //Capture first rising edge

CCP1IF = 0;
while (!CCP1IF);
period_capture = CCP_1; //Capture second rising edge
PR2_val = ((period_capture - old_capture) >> 4); //Calculate PR2 (period) value

CCP1IF = 0;
while (!CCP1IF);
old_capture = CCP_1; //Capture first rising edge

CCP2IF = 0;
while (!CCP1IF);
duty_capture = CCP_2; //Capture next falling edge
duty_cycle = ((duty_capture - old_capture) >> 4); //Calculate duty cycle

if(PR2_val < 5 || PR2_val > 250) //Check if oscillator needs change
change_osc = TRUE; //Speed up oscillator

setup_timer_2(T2_DIV_BY_1, PR2_val, 1); //Load period into TIMER2 for PWM
set_pwm3_duty(duty_cycle); //Set duty cycle for PWM
}
}

Note: I have a signal generator going into the CCP1 & CCP2 pins.
I am reading the CCP3 pin signal through an o-scope.
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Thu Apr 26, 2007 2:30 pm     Reply with quote

Edited: Cleaned up the post in an attempt to make the meaning clearer.
OK, here is a way of measuring the duty cycle of the input. As a ratio it will be the number representing 16 times the ‘on’ time for one cycle of the input divided by the number representing the time taken for 16 cycles of the input obtained earlier. The duty cycle measurement can be done after the period measurement assuming that the input frequency is not changing during the measurements.

The measurement of 16 times the ‘on’ time of the input cannot be measured over 16 cycles in the same way that the period was measured.
Instead, get the timer 1 count difference for the time between the rising and falling edges of one pulse, do this 16 times, adding the new value to a variable that holds the sum.

For a PIC16
#byte PIR2 = 0x0D
#bit CCP2IF = PIR2.0
setup_ccp2(CCP_CAPTURE_FE); // Note that there is no post scaler possible for falling edge capture

Loop the following 16 times.

1. Clear CCP1IF.
2. Wait for CCP1IF to go high.
3. Clear CCP2IF.
4. Get the captured timer 1 count from CCP_1.
5. Wait for CCP2IF to go high (may have already done so!).
6. Get the new captured timer 1 count from CCP_2.
7. Subtract the old one from it and add the result to sum variable

CCP1IF will occur every 16 cycles of the input, so there should be enough time to do the above in the time in between them for each time around the loop.

Edited: Back from a break. Added results of a test:
With a 16MHz crystal was able to measure down to about 2uS pulse width and get a number for 16 'on' times. The input pulse width needs to be greater than 2uS.
dacenrie



Joined: 02 Mar 2006
Posts: 16

View user's profile Send private message

PostPosted: Mon May 21, 2007 11:28 am     Reply with quote

The frequency read is working, but I still can't quite get the duty cycle read working. Here is my current code and hopefully you can find something I don't. Thanks.

I'm throwing the same square wave signal into CCP1 and CCP2. I then output PWM to CCP3, after I've established frequency/period and duty cycle measurements.

#include <16F737.h>

#fuses NOWDT, NOPROTECT, INTRC_IO, PUT, NOBROWNOUT, MCLR, CCP2C1, DEBUG, NOFCMEN, NOIESO, NOBORSEN
#byte PIR1 = 0x0C
#byte PIR2 = 0x0D
#bit CCP1IF = PIR1.2
#bit CCP2IF = PIR2.0

int16 period_capture, old_capture, duty_capture;
int16 duty_cycle;
int8 PR2_val, change_osc = FALSE;

/***********************************************************************/
/****************************Main***************************************/
/***********************************************************************/
void main()
{
set_tris_C(0xFF); // set C port as input
set_tris_B(0xDF); // RB5 as output

setup_adc(ADC_OFF); // turn off ADC
setup_comparator(NC_NC_NC_NC); // turn off comparator
setup_oscillator(OSC_500KHZ); // change oscillator speed

setup_ccp1(CCP_CAPTURE_RE | CCP_CAPTURE_DIV_16); // Configure CCP1 to capture rising edge
setup_ccp2(CCP_CAPTURE_FE); // Configure CCP2 to capture falling edge


setup_ccp3(CCP_PWM); // Configure CCP3 as PWM
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); // Set timer1 to run at (system_clk/4)

while(1)
{
int x;

CCP1IF = 0;
while (!CCP1IF);
old_capture = CCP_1; //Capture first rising edge

CCP1IF = 0;
while (!CCP1IF);
period_capture = CCP_1; //Capture second rising edge
PR2_val = ((period_capture - old_capture) >> 4); //Calculate PR2 value

if(PR2_val < 5 || PR2_val > 250) //Check if oscillator needs change
change_osc = TRUE; //Speed up oscillator

for (x=0; x<16; x++)
{
CCP1IF = 0;
while (!CCP1IF);
CCP2IF = 0;
old_capture = CCP_1;
while (!CCP2IF);
duty_cycle += (CCP_2-old_capture);
}

setup_timer_2(T2_DIV_BY_1, PR2_val, 1); //Load period into TIMER2 for PWM
set_pwm3_duty(duty_cycle); //Set duty cycle for PWM

}
}
Kenny



Joined: 07 Sep 2003
Posts: 173
Location: Australia

View user's profile Send private message

PostPosted: Mon May 21, 2007 7:45 pm     Reply with quote

Add the following line before the looping, otherwise the variable will keep incrementing each time around the main loop.
duty_cycle = 0;
Ideally for these measurements it is better to use a more stable clock source than the internal one, and at the highest clock speed for the pic, 20MHz. But I understand that you will be adjusting the pwm frequency by altering the internal clock frequency in stages.

I should have posted my test code:

Code:

#include <16F876.h>
#fuses HS,NOWDT,PUT,NOLVP,NOPROTECT,BROWNOUT
#use delay(clock=16000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,ERRORS)

#byte PIR1 = 0x0C
#bit CCP1IF = PIR1.2

#byte PIR2 = 0x0D
#bit CCP2IF = PIR2.0

void main()
{
   int16 new_t1count;
   int16 old_t1count;
   int16 delta_count;
   int16 period;
   int16 duty;
   int8 i;

   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
   setup_ccp1(CCP_CAPTURE_RE|CCP_CAPTURE_DIV_16);
   setup_ccp2(CCP_CAPTURE_FE);

   while(1)
   {
      // Period
     
      CCP1IF = 0;
      while (!CCP1IF);
      old_t1count = CCP_1;
      CCP1IF = 0;
      while (!CCP1IF);
      new_t1count = CCP_1;
      period = new_t1count - old_t1count;

      // Duty
     
      duty = 0;

      for (i=0;i<16;i++)
      {
         CCP1IF = 0;
         while (!CCP1IF);
         CCP2IF = 0;
         old_t1count = CCP_1;
         while (!CCP2IF);
         new_t1count = CCP_2;
         delta_count = new_t1count - old_t1count;
         duty += delta_count;
      }

      printf("period=%5lu duty=%5lu\n\r",period,duty);
      delay_ms(1000);
   }
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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