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

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
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: 19327

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
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Wed Nov 13, 2013 8:42 am     Reply with quote

Thanks Ttelmah.
Code:
(ccp_delta *( 1/(10MHz)*(4*8*1000) ) )

Yes, It it's a remark.
In my project change use crystal 10MHZ so that I must calcualtor this constant.
Oh,I thought failure,, I'm careless when using division to change the code, because I always think division math is slower than multiplication. You pls show me way to calculate time for math operation.
Added, when i test with this code, it has return value when i disconnect pulse clock in CCP1 pin, If true, it must no return value,so that I think need to clear int_ccp1 flag?

here is my full code I changed flow your idea:

Code:

#include <16F877A.h>
#fuses HS, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=10000000)
#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 * 32) /10000 ;
      printf("%lu ms \n\r", pulse_width_ms);
     }
   delay_ms(500);

  }

}


_________________
Begin Begin Begin !!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19327

View user's profile Send private message

PostPosted: Wed Nov 13, 2013 9:22 am     Reply with quote

It's not INT_CCP1 that is causing it to display with no input. You are not clearing the flag 'got_pulse_width' when you print.
Code:

while(1)
  {
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta;
      enable_interrupts(GLOBAL);
      got_pulse_width=FALSE;   //need this or it'll keep printing....

      pulse_width_ms = (local_ccp_delta * 32) /10000 ;
      printf("%lu ms \n\r", pulse_width_ms);
     }
   delay_ms(500);
  }

On times, CCS has a table in the manual 'how much time do maths operations take', which can be scaled for different clock rates, but the simplest solution is to just use a pulse output and time the actual duration, or use the stopwatch feature in MPLAB.

There is one problem with *32/10000. The result of *32, won't fit in an int16, so for longer times, the values out the top will be lost (65mSec max). If this matters you'll need to cast to an int32.

Best Wishes
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Wed Nov 13, 2013 8:34 pm     Reply with quote

Thanks u, Ttelmah.
Well, It worked Smile
But it seem has error when i disconnect pulse in CCP1, It has return value???
And is here my code edited follow your comment:

Code:

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

int8 capture_falling_edge;
int8 got_pulse_width;
int32  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()
{
int32 pulse_width_ms;
int32 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);
     
      got_pulse_width= FALSE;

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

   delay_ms(500);

  }

}


Thanks u so much.
_________________
Begin Begin Begin !!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19327

View user's profile Send private message

PostPosted: Thu Nov 14, 2013 1:28 am     Reply with quote

No pulse = line floating (unless you have arranged a pull-up resistor). May start picking up RF/mains interference....

Best Wishes
tienchuan



Joined: 25 Aug 2009
Posts: 175

View user's profile Send private message Yahoo Messenger

PostPosted: Sat Nov 16, 2013 8:05 pm     Reply with quote

Well, I worked exactly:)
I added config in main code:
Code:
set_tris_c(0x04);


Follow instructions in datasheet:
Quote:
If the RC2/CCP1 pin is configured as an output, a write to the port can cause a Capture condition

Thanks u very much Smile
_________________
Begin Begin Begin !!!
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