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 CCS Technical Support

Pulse width
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
Kova



Joined: 06 May 2007
Posts: 35

View user's profile Send private message

Pulse width
PostPosted: Sat Jul 21, 2007 11:12 pm     Reply with quote

Hi all,
Before posting I have searched in old posts some answers, but I haven't resolved my problem Embarassed

I have 2 signals that i want to calculate the pulse width.
I'm using a 16F877 pic.
I have found in the example dir this code:

Code:

..........................................
...............................
#int_ccp2
void isr()
{
   rise = CCP_1;
   fall = CCP_2;

   pulse_width = fall - rise;     // CCP_1 is the time the pulse went high
}                                 // CCP_2 is the time the pulse went low
                                  // pulse_width/(clock/4) is the time

                                  // In order for this to work the ISR
                                  // overhead must be less than the
                                  // low time.  For this program the
                                  // overhead is 45 instructions.  The
                                  // low time must then be at least
                                  // 9 us.
...............................
..........................................


But, It uses 2 pins (CCP1 and CCP2) to calculate the width of 1 signal Confused (pulse_width = fall - rise;).
It's possibile to capture the FE and RE with an only CCPx?
I am interested to calculate only the high length signal (200ms and 300ms):



Another question: There are pic with 3 CCPx? Very Happy

Thanks for the help Wink
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 22, 2007 10:33 pm     Reply with quote

Quote:
It's possibile to capture the FE and RE with an only CCPx?
Look at these CCS example files for ideas. They use one CCP module
and they do it by switching between detecting the rising edge and then
the falling edge:
Quote:
c:\program files\picc\drivers\em4095.c
c:\program files\picc\drivers\adxl210.c
c:\program files\picc\examples\ex_react.c


Quote:

I am interested to calculate only the high length signal (200ms and 300ms):

The CCP captures the count in Timer1, which is a 16-bit counter.
It counts at 1/4 of the oscillator rate. For example, with a 4 MHz
crystal, Timer1 will be clocked at 1 MHz. (1 us clock period).
A pulse of 200 ms will take 200,000 clocks. That's much greater
than the 65535 limit of Timer1, so you need to use a pre-scaler
for the CCP. Look in the PIC data sheet or the .H file to see the
available CCP pre-scaler values. Also remember to incorporate
the pre-scaler into your equation that calculates the pulse width.
Kova



Joined: 06 May 2007
Posts: 35

View user's profile Send private message

PostPosted: Sun Jul 22, 2007 11:09 pm     Reply with quote

Thanks a lot PCM Programmer for the help Razz Razz.

PCM, do you know a pic with 3 CCP? Question

Bye ;)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 22, 2007 11:12 pm     Reply with quote

See this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=31346
It tells how to use the Parametric Search page on the Microchip site
to find the answer. It also provides a direct link to that page.
(The link is for 16F-series PICs)
Kova



Joined: 06 May 2007
Posts: 35

View user's profile Send private message

PostPosted: Wed Oct 10, 2007 5:02 am     Reply with quote

Hi,
now I'm beginning the project of this thread that i have opened in July Smile.
The wave characteristics are changes Razz
Now I must capture the width of the low signal (maximum 500msec), like this:


I'm using a PIC18F2550 and with the PIC wizard I have setted the timers 1 to be able to overflow over 500msec.
This is my code:

main.h
Code:

#include <18F2550.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES BORV20                   //Brownout reset at 2.0V
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                     //No Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES IESO                     //Internal External Switch Over mode enabled
#FUSES FCMEN                    //Fail-safe clock monitor enabled
#FUSES PBADEN                   //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES MCLR                     //Master Clear pin enabled
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES PLL1                     //No PLL PreScaler
#FUSES CPUDIV1                  //No System Clock Postscaler
#FUSES NOUSBDIV                 //USB clock source comes from primary oscillator
#FUSES NOVREGEN                 //USB voltage regulator disabled
#use delay(clock=4000000)


main.c
Code:

#include "main.h"

int16 t1, t2;
int1 waiting_for_fall;

#int_CCP1
void  CCP1_isr(void)
{
   static long last_rise;
   
   if(waiting_for_fall) {
      t1=CCP_1-last_rise;
      setup_ccp1(CCP_CAPTURE_FE);
      waiting_for_fall=FALSE;
   } else {
      t2=CCP_1-last_rise;
      last_rise=CCP_1;
      setup_ccp1(CCP_CAPTURE_RE);
      waiting_for_fall=TRUE;
   }
}

void main()
{

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_ccp1(CCP_CAPTURE_FE);
   setup_vref(FALSE);
   enable_interrupts(INT_CCP1);
   enable_interrupts(GLOBAL);
   set_tris_a(0);
   output_low(PIN_A0);
   delay_ms(100); //Un pò di pausa
   
   while(true)
   {
   
      if(t1>=??????)
         {
         output_high(PIN_A0);
         delay_ms(2000);
         output_low(PIN_A0);
         }
   }

}


I dont understand the value of t1.
I want that when T1 is >= 500msec than the led at RA0 goes high!
Please help me.
Thanks a lot and sorry for my english.
Bye ;)
Kova



Joined: 06 May 2007
Posts: 35

View user's profile Send private message

PostPosted: Wed Oct 10, 2007 11:08 pm     Reply with quote

Nobody Crying or Very sad Crying or Very sad Crying or Very sad ?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 12, 2007 11:46 am     Reply with quote

The problem with using CCP1 is that with an input pulse of 500ms
you are near the maximum pulse width that the hardware can
capture (with a 4 MHz oscillator). If you have an input pulse of say,
550 ms, or 600 ms, it won't work.

Suppose you use the maximum Timer1 prescaler value of 8.
Timer1 can count up to 65535.

This is the equation to calculate the pulse width in ms.
Code:

                              CCP delta
pulse width in ms =  -----------------------------------------
                     Osc Freq / ( 4 * Timer1 prescaler * 1000)


Plug the maximum numbers into it:
Code:
                            65535
max pulse width  =  ----------------------- = 524 ms
                    4 MHz  / (4 * 8 * 1000)


You could capture a longer pulse, but you would have to extend Timer1
to 24 or 32 bits. I don't want to do that right now. I don't have the
time.

This code will capture a positive pulse of 1 to 524 ms.
Code:

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

int8 capture_rising_edge;
int8 got_pulse_width;
int16  ccp_delta;


#int_ccp1
void ccp1_isr(void)
{
static int16 t1_rising_edge;

// If current interrupt is for rising edge.
if(capture_rising_edge)
  {
   setup_ccp1(CCP_CAPTURE_FE);
   capture_rising_edge = FALSE;
   t1_rising_edge = CCP_1;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_rising_edge = TRUE;
   ccp_delta = CCP_1 - t1_rising_edge;
   got_pulse_width = TRUE;
  }

}

//====================================
main()
{
int16 pulse_width_ms;
int16 local_ccp_delta;

got_pulse_width = FALSE;
capture_rising_edge = TRUE;

setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
      enable_interrupts(GLOBAL);

      pulse_width_ms = local_ccp_delta / 125;
      printf("%lu ms \n\r", pulse_width_ms);
      got_pulse_width = FALSE;
     }

  }

}


-----
Edited to disable interrupts while loading the ccp_delta into a local variable.


Last edited by PCM programmer on Fri Oct 12, 2007 1:51 pm; edited 1 time in total
Kova



Joined: 06 May 2007
Posts: 35

View user's profile Send private message

PostPosted: Fri Oct 12, 2007 12:15 pm     Reply with quote

PCM programmer wrote:

CUT
This code will capture a positive pulse of 1 to 524 ms.
CUT


Ohhh thanks a lot PCM programmer for the help Razz
You are so kind to everybody Embarassed Embarassed
An ultimate thing: If I want to to capture a negative pulse I must invert all the setup_ccp1 ?

At limit I can use a bjt to invert the pulse in positive ;)

Thanks another time for your time and for the code.
Bye ;)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 12, 2007 12:39 pm     Reply with quote

To capture a negative pulse width, you just flip everything.
Also, I've improved the loop code, so that it loads the ccp delta
value into a local variable before using it.

Here is the negative pulse program:
Code:
#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

int8 capture_falling_edge;
int8 got_pulse_width;
int16  ccp_delta;


#int_ccp1
void ccp1_isr(void)
{
static int16 t1_falling_edge;

// If current interrupt is for falling edge.
if(capture_falling_edge)
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_falling_edge = FALSE;
   t1_falling_edge = CCP_1;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_FE);
   capture_falling_edge = TRUE;
   ccp_delta = CCP_1 - t1_falling_edge;
   got_pulse_width = TRUE;
  }

}

//====================================
main()
{
int16 pulse_width_ms;
int16 local_ccp_delta;

got_pulse_width = FALSE;
capture_falling_edge = TRUE;

setup_ccp1(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
      enable_interrupts(GLOBAL);

      pulse_width_ms = local_ccp_delta / 125;
      printf("%lu ms \n\r", pulse_width_ms);
     }

   delay_ms(500);

  }

}
ghadabeydoun



Joined: 09 Nov 2010
Posts: 1

View user's profile Send private message

reception and reconstruction of a signal
PostPosted: Tue Nov 09, 2010 3:39 am     Reply with quote

hello everybody,

I am trying to write a program using CCP that receives a signal and measures the pulse width (negative and positive) and then using this information I will reconstruct the signal at the output of the program. Any help!! : Confused
lasfclestat



Joined: 20 Apr 2011
Posts: 2
Location: Campinas, SP - Brazil

View user's profile Send private message Yahoo Messenger MSN Messenger

PostPosted: Wed Apr 20, 2011 7:56 am     Reply with quote

hello ...

Using the example posted earlier I tried to follow the example below, I can generate a square wave with period of 26ms, but I am not able to generate the CCP1 interrupt, you are missing something in code?

Thanks

Code:


#include <16F877A.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=20000000,RESTART_WDT)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

int8 capture_rising_edge;
int8 got_pulse_width;
int16  ccp_delta;
int flag = 0;

#INT_TIMER2
void  TIMER2_isr(void)  //timer2 interrupt
{
   if (flag)
   {
      output_high(pin_c0);
      flag = 0;
   } else
   {
      flag = 1;
      output_low(pin_c0);   
   }
   clear_interrupt(int_timer2);// clear timer2 interrupt's flag   
}

#int_ccp1
void ccp1_isr(void)
{
static int16 t1_rising_edge;

// If current interrupt is for rising edge.
if(capture_rising_edge)
  {
   setup_ccp1(CCP_CAPTURE_FE);
   capture_rising_edge = FALSE;
   t1_rising_edge = CCP_1;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_rising_edge = TRUE;
   ccp_delta = CCP_1 - t1_rising_edge;
   got_pulse_width = TRUE;
  }

}

//====================================
main()
{
int16 pulse_width_ms;
int16 local_ccp_delta;

got_pulse_width = FALSE;
capture_rising_edge = TRUE;

setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );
setup_timer_2(T2_DIV_BY_16,255,16);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
      enable_interrupts(GLOBAL);

      pulse_width_ms = local_ccp_delta / 125;
      printf("%lu ms \n\r", pulse_width_ms);
      got_pulse_width = FALSE;
     }

  }

}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Apr 20, 2011 1:25 pm     Reply with quote

I made it work. Here's what I did:

1. Your generated signal on pin C0 is actually running at approx. 38 Hz.
The Timer2 interrupts are occurring at a 76 Hz rate. A half-cycle of the
waveform on pin C0 takes about 13 ms. This is the pulse width that you
are trying to measure.

2. You must have a wire connecting pin C0 to pin C2 on your PIC.
This connects the 38 Hz squarewave to the CCP1 input. Do you have it ?

3. You get a compiler warning about main() not returning a value.
Fix that by declaring main() as void. Example:
Quote:
void main()


4. You're using a 20 MHz crystal. The example uses a 4 MHz crystal.
The pulse width equation must be adjusted for this. Timer1 will count
up 5x faster with a 20 MHz crystal, compared to a 4 MHz crystal.
Therefore, you need to divide the CCP value by 5, to compensate for
the faster crystal, as shown below in bold:
Quote:

pulse_width_ms = local_ccp_delta / (125 * 5);


5. Your update speed on the terminal window is too fast. It scrolls the
terminal too fast. Add a delay to the main loop to slow it down, as shown
in bold below:
Quote:

while(1)
{
if(got_pulse_width)
{
disable_interrupts(GLOBAL);
local_ccp_delta = ccp_delta;
enable_interrupts(GLOBAL);

pulse_width_ms = local_ccp_delta / (125 * 5);
printf("%lu ms \n\r", pulse_width_ms);
got_pulse_width = FALSE;
delay_ms(500);
}


I did all that and it works. I get this output in the TeraTerm window:
Quote:

13 ms
13 ms
13 ms
13 ms
13 ms
13 ms
13 ms
13 ms


This was tested with compiler version 4.119 on a PicDem2-Plus board.
lasfclestat



Joined: 20 Apr 2011
Posts: 2
Location: Campinas, SP - Brazil

View user's profile Send private message Yahoo Messenger MSN Messenger

PostPosted: Wed Apr 20, 2011 2:03 pm     Reply with quote

Okay, I understand ...

Yes I'm connected the Pin C0 to C2

I'll make the changes, and test again, then I submit the result.

Thanks
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Wed Nov 13, 2013 1:34 am     Reply with quote

PCM programmer wrote:
To capture a negative pulse width, you just flip everything.
Also, I've improved the loop code, so that it loads the ccp delta
value into a local variable before using it.

Here is the negative pulse program:
Code:
#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

int8 capture_falling_edge;
int8 got_pulse_width;
int16  ccp_delta;


#int_ccp1
void ccp1_isr(void)
{
static int16 t1_falling_edge;

// If current interrupt is for falling edge.
if(capture_falling_edge)
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_falling_edge = FALSE;
   t1_falling_edge = CCP_1;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_FE);
   capture_falling_edge = TRUE;
   ccp_delta = CCP_1 - t1_falling_edge;
   got_pulse_width = TRUE;
  }

}

//====================================
main()
{
int16 pulse_width_ms;
int16 local_ccp_delta;

got_pulse_width = FALSE;
capture_falling_edge = TRUE;

setup_ccp1(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(1)
  {
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
      enable_interrupts(GLOBAL);

      pulse_width_ms = local_ccp_delta / 125;
      printf("%lu ms \n\r", pulse_width_ms);
     }

   delay_ms(500);

  }

}


Hi all Smile
I tried this code to test capture pulse by used IC555 pulse generator(40ms) .
In my project, I used crystal 10MHz, so that I edit:

In fuse config
Code:

#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=10000000)


In main code:

Code:

pulse_width_ms = local_ccp_delta * 0.0032; (ccp_delta *( 1/(10MHz)*(4*8*1000)    )   )


But the result always change and failure.

Code:

12 ms
13 ms
14 ms
12 ms
14 ms
9 ms
12 ms
12 ms
32 ms
34 ms
50 ms
11 ms
10 ms
33 ms
33 ms
50 ms
33 ms
50 ms
10 ms
31 ms
33 ms
50 ms
10 ms
30 ms
10 ms
10 ms
33 ms
33 ms
10 ms
10 ms
33 ms
33 ms
33 ms
50 ms
10 ms
10 ms
33 ms
50 ms
10 ms
30 ms
10 ms
32 ms
33 ms
50 ms
10 ms
32 ms
33 ms
50 ms
33 ms
33 ms
50 ms
32 ms
32 ms
10 ms
32 ms
33 ms
33 ms
50 ms
33 ms
30 ms
10 ms
10 ms
31 ms
33 ms
33 ms
36 ms
31 ms
10 ms
32 ms
33 ms
10 ms
10 ms
33 ms
50 ms
34 ms
50 ms
10 ms
33 ms
33 ms
10 ms
30 ms
33 ms
10 ms
33 ms
33 ms
33 ms
50 ms
33 ms
33 ms
33 ms
50 ms
10 ms
33 ms
30 ms
10 ms
10 ms
33 ms
33 ms
33 ms
32 ms
33 ms
33 ms
10 ms
10 ms
33 ms
33 ms
35 ms
50 ms
10 ms
...
10 ms

Pls show me way to fix it.
Thanks all
_________________
Begin Begin Begin !!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Wed Nov 13, 2013 3:26 am     Reply with quote

First, you are copying ccp_delta, to local_ccp_delta, with the interrupts disabled, as shown in the code?.

Second, what is this?:
(ccp_delta *( 1/(10MHz)*(4*8*1000) ) )

If it's a remark, it needs // in front

Then you are making a fundamental change to how the code works. /125, forces an integer division, and uses integer maths, to give an integer result. Total time about 140uSec. Multiplying by 0.0032, forces the integer to be converted to float, and then fp maths, and then the result to be converted back to integer. Total time about 500uSec...
Use /500. Though division is slower for a given maths type than multiplication, an int16 division is a lot faster than floating point multiplication, and two lots of conversion.

Best Wishes
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