View previous topic :: View next topic |
Author |
Message |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
Measuring pulse width using CCP |
Posted: Mon Mar 24, 2014 12:32 pm |
|
|
I have used a sample code by "PCM PROGRAMMER" to fit my requirement but I am stuck and the code is not functioning properly. My requirement is that I have a incoming pulse that is 2.6ms high and 7.0 ms low, period of 9.6 ms. I simply want to measure the pulse and if the pulse matches the requirement (with some tolerance ) then turn on the LED. I want to use only CCP1 to do this task. Once i get this part working i have another incoming pulse that i will use the CCP2 for.
Using MPLAB IDE V8.70
Code: |
#include <16F886.h>
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
int8 capture_rising_edge;
int8 got_pulse_width;
int16 ccp_delta;
#int_ccp1 //Interrupt Name
void isr_ccp1() //Interrupt Function
{
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;
}
}
//+++++++++++++++++
void main() ///
{
int16 local_ccp_delta;
int16 pulse_width_ms;
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;
if(pulse_width_ms)
{
(=>2)&&(=<3); //is the measured pulse greater then 2 and less than 3, If yes than turn on LED at C5
output_high(pin_c5);
}
else
{
output_low(pin_c5);
}
got_pulse_width = FALSE;
}
}
}
|
[img] file:///C:/Users/ppala/Desktop/sim.png [/img]
[/code]
Last edited by Aragon on Mon Mar 24, 2014 1:33 pm; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Mon Mar 24, 2014 1:02 pm |
|
|
You are creating no friends by using Proteus - read the sticky at the top of the forum. Proteus's simulation of PIC's is fundamentally poor.
However you main problem is a syntax error:
Code: |
if(pulse_width_ms==2)
{
output_high(pin_c5);
}
else
{
output_low(pin_c5);
}
|
The statement immediately after the 'if' is what is evaluated for true/false - nothing else.
Then pulse_width_ms value is an integer, so your description in the 'comment': "is the measured pulse greater then 2 and less than 3, If yes than turn on LED at C5"
Can never be true. I've just shown it being tested for being 2.
Better really to test for:
if (local_ccp_delta>250 && local_ccp_delta<375)
Which will give the range you talk about in the comment.
To make it friendly:
Code: |
#define MS_2 (250)
#define MS_3 (375)
if (local_ccp_delta>MS_2 && local_ccp_delta<MS_3)
|
|
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Mon Mar 24, 2014 1:03 pm |
|
|
Thanks Ttelmah. I will change my code accordingly. |
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Mon Mar 24, 2014 2:30 pm |
|
|
I tested the chip on a circuit board. The LED turns ON as soon as I provide the PWM signal. However when I turn off the input Pulse the LED stays ON for several seconds before it turns off. It seems that I have to play with the prescaler? so that when signal is not there the LED turns off. Am I right with changing the prescaler? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Mon Mar 24, 2014 3:01 pm |
|
|
No....
The interrupt only triggers when there is a pulse. As it stands, it won't detect the lack of a pulse. It detects pulses of different lengths. There has to be a pulse.
What you could do, is add a software timeout to the loop, so if a pulse is _not_ seen, it switches to a required state. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Tue Mar 25, 2014 5:47 am |
|
|
Thanks for the great advice guys. I will implement the "no input" with a software timer. ![Smile](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Wed Oct 08, 2014 10:37 am |
|
|
Hello,
Sorry to Re-Vamp this post. This has been a side project that I am working on. The code worked properly using CCP1 and Timer1. However when I tried to use CCP2 and Timer0 in parallel with CCP1 and Timer1, The CCP2 was not working. I will post the code later in the evening when I get home.
The question I have is, Can I use both CCP1 and CCP2 simultaneous with different timers to measure two different pulses coming in?
Thanks. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Wed Oct 08, 2014 2:32 pm |
|
|
With your chip, you can't.
The data sheet is your friend. Table 11-1, and 11-2
Capture, and compare modes, _only_ use timer1.
Several of the later chips with timer3, allow this to be used as an alternative, but on your chip, only one timer can be used. |
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Wed Oct 08, 2014 4:20 pm |
|
|
Thanks for the reply. I have to start looking for a different chip now. |
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Wed Oct 15, 2014 8:48 am |
|
|
Hello,
The PIC i found is PIC18F2550. The code is working for 16F886 but when i use the same code for 18F2550 it doesnt work. For now I only want the Timer1 to work first so its the same code as 16F886. I had a look at the timer 1 control register for both the pics and only register 6 and 7 are different.
for 18F2550 I guess, I have to enable the 16 bit operation for bit7? and for bit 6 user timer1 oscillator? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Wed Oct 15, 2014 11:10 am |
|
|
The CCP stuff is basically the same, except for the added commands to use timer3. It defaults to timer1. Have you actually checked the chip is running, and running at the speed you expect?. The old 'flash an LED' test. The thing that is a lot more complex on this chip, is the clock setup. Timer1, only works as a 16bit timer. The only timer that can switch between 8bit and 16bit, is Timer0. The bit you are looking at controls how it is _accessed_, not how it runs. Don't touch this bit. The setting for bit 6, is the same as for the 16 chip. Controlled by whether you select T1_INTERNAL or EXTERNAL (you want INTERNAL). |
|
![](templates/subSilver/images/spacer.gif) |
Aragon
Joined: 19 Mar 2014 Posts: 20
|
|
Posted: Wed Oct 15, 2014 12:06 pm |
|
|
Code: |
#include <18F2550.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_edge1;
int8 got_pulse_width1;
int16 ccp_delta1;
#define MS_2 250
#define MS_3 375
#int_ccp1 //Interrupt Name
void isr_ccp1() //Interrupt Function
{
static int16 t1_rising_edge;
//If current interrupt is for rising edge.
if(capture_rising_edge1)
{
setup_ccp1(CCP_CAPTURE_FE);
capture_rising_edge1 = FALSE;
t1_rising_edge = CCP_1;
}
else
{
setup_CCP1(CCP_CAPTURE_RE);
capture_rising_edge1 = TRUE;
ccp_delta1 = CCP_1 - t1_rising_edge;
got_pulse_width1 = true;
}
}
//+++++++++++++++++
void main() ///
{
int16 local_ccp_delta;
int16 pulse_width_ms;
got_pulse_width1 = FALSE;
capture_rising_edge1 = 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_width1)
{
disable_interrupts(GLOBAL);
local_ccp_delta = ccp_delta1;
enable_interrupts(GLOBAL);
pulse_width_ms = local_ccp_delta/125;
printf("%lu ms \n\r", pulse_width_ms);
got_pulse_width1 = FALSE;
}
if(local_ccp_delta>MS_2 && local_ccp_delta<MS_3)
{
output_high(pin_c5);
}
else
{
output_low(pin_c5);
}
delay_ms(500);
}
}
|
I have attached the code. I have checked the chip and it's running ok. I did a small test. Enabled "high" on some ports and it seemed to work. I am using the internal clock for now. any errors in my code? Thanks |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Oct 15, 2014 1:28 pm |
|
|
Quote: | Enabled "high" on some ports and it seemed to work. |
You're not using "some ports". You're using pin C5. Blink an LED on
that one. It's the one you're using, so it's the logical choice for the test.
If it doesn't work, then look at the pin descriptions in the PIC data sheet. |
|
![](templates/subSilver/images/spacer.gif) |
|