|
|
View previous topic :: View next topic |
Author |
Message |
Kova
Joined: 06 May 2007 Posts: 35
|
Pulse width |
Posted: Sat Jul 21, 2007 11:12 pm |
|
|
Hi all,
Before posting I have searched in old posts some answers, but I haven't resolved my problem
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 (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?
Thanks for the help |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 22, 2007 10:33 pm |
|
|
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
|
|
Posted: Sun Jul 22, 2007 11:09 pm |
|
|
Thanks a lot PCM Programmer for the help .
PCM, do you know a pic with 3 CCP?
Bye ;) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 22, 2007 11:12 pm |
|
|
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
|
|
Posted: Wed Oct 10, 2007 5:02 am |
|
|
Hi,
now I'm beginning the project of this thread that i have opened in July .
The wave characteristics are changes
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
|
|
Posted: Wed Oct 10, 2007 11:08 pm |
|
|
Nobody ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 12, 2007 11:46 am |
|
|
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
|
|
Posted: Fri Oct 12, 2007 12:15 pm |
|
|
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
You are so kind to everybody
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
|
|
Posted: Fri Oct 12, 2007 12:39 pm |
|
|
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
|
reception and reconstruction of a signal |
Posted: Tue Nov 09, 2010 3:39 am |
|
|
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!! : |
|
|
lasfclestat
Joined: 20 Apr 2011 Posts: 2 Location: Campinas, SP - Brazil
|
|
Posted: Wed Apr 20, 2011 7:56 am |
|
|
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
|
|
Posted: Wed Apr 20, 2011 1:25 pm |
|
|
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:
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
|
|
Posted: Wed Apr 20, 2011 2:03 pm |
|
|
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
|
|
Posted: Wed Nov 13, 2013 1:34 am |
|
|
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
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: 19513
|
|
Posted: Wed Nov 13, 2013 3:26 am |
|
|
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 |
|
|
|
|
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
|