![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
pilt1 Guest
|
Best Way of doing something |
Posted: Thu May 18, 2006 7:16 pm |
|
|
Hi im trying to work out the best way of doing something.
I am using a PIC16f877a
I use CCP1 to measure the time between falling edges of a pulse train.
This falling edge is used to generate a signal from the uP which is started 64us after the incoming falling edge.
The output pulse is of variable length from 500-1500us
I am wondering which is the best and easiest way to implement this.
This was one option, just simply using the delay_us in the interrupt although this is a messy way of doing it
Code: |
#int_ccp1
void isr()
{
delay_us(50); //Should give 64us delay
output_high(PIN_C3); //Turn on output
delay_us(pulse); // pulse delay
output_low(PIN_C3); //Turn off output
}
|
The other posibility i looked at was using the other CCP module in compare mode to generate the output, however i looked into this and it does not seem you can assosiate the second CCP module with timer3 which is what i had planned to do. Is it possible?
The third option is to use a timer overflow interrupt and just put the inverse (well sorta) of the values into the timer and letting it overflow and generate an interrupt, then loading it with the pulse variable in the timer interrupt
The 64us delay does not have to be that accurate but the pulse width output should be
Which way do u think is best and why?
Cheers
Pilt |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Fri May 19, 2006 3:04 am |
|
|
What other chip resources are you using?.
There is no 'point' in using the CCP, to trigger the start of the pulse, if the external interrupt is available.
What timers are you using for other things?.
As written, the code has several problems. The first is simply that you can't have a variable delay over 255uSec, using the delay_us functon. The second is that doing it this way, brings the big problem that you will be stuck inside this interrupt handler for a long time, and other handwre events may/will be missed. Also, using the delay function, implies that interrupts will be disabled in delays outside the interrupt handler, which makes the initial latency more likely to vary...
If you only want the pulse, not the timing, I'd consider a different approach:
1) Use 'int_ext' to trigger the start of the pulse. Program this to interrupt on the falling edge of the incoming signal.
2) Have timer1, programed to count in the 'units'required for your pulse width (uSec?).
3) In the handler for int_ext, wait for the initial pause, then set the output pin for CCP1 (or 2, whichever you want to use), clear timer1, and set CCP1, to the pulse time required. Have it programmed to 'compare mode, reset on match'. Exit the handler.
The CCP module, will _clear_ it's output, the programmed count latter, with high accuracy, without you having to do anything else. This gives the required pulse precision.
Also, use the 'trick', of having a seperate #use delay statement for the interrupt handler code, so that the short delay needed at the start of the interrupt handler, does not result in interrupts being disabled in external delays.
Now, if you do need to use CCP1, to measure the time between the pulses, generate the output pulse using CCP2 instead, starting it in the CCP1 interrupt as you show, and rather than clearing timer1 (which would give errors for the width timings), set CCP2, to the value read from timer1, plus the time delay rquired. This is probably what you will need to do.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
pilt1 Guest
|
|
Posted: Fri May 19, 2006 6:22 am |
|
|
Hi, these are the only interrupts i am using, the other timers are not being used for anything
Hi thanks for that, has given me ideas for how to do it
Here is my revised code
Code: |
#use delay(clock=20000000,restart_wdt)
#int_ccp1 //
void isr()
{
current = CCP_1;
comp_count = (last+65536) - current; //comp_count is a int32
last = get_timer1();
delay_us(50); //Should give 64us delay
output_high(CCP2_PIN); //Wotever pin it is
pulse = last + width; //pulse is a 16bit value so will overflow
//in accordance with timer 1 to get correct value
CCP_2 = pulse;
setup_ccp2(CCP_COMPARE_CLR_ON_MATCH);
if(!TMR1IF) //If timer 1 has not overflowed subtract 65536 to value
{
comp_count -= 65536;
}
if(TMR1IF) //If timer 1 has overflowed reset the flag
TMR1IF = 0;
}
#int_ccp1
{
setup_ccp2(CCP_OFF);
}
|
Ok here goes
The time meausred between the falling edges of the incoming signal can be from about 3ms up to 150ms so i used timer 1 set to overflow at 104ms . By checking if an overflow has occured between two falling edges i can effectiverly mesaure 204ms.
Now i never reset the timer1 value so i need the last value (from last falling edge) to calculate the duration, at the top i add 65,536 to this because i just assume that the timer has overflowed as i did not want to put the if statement to check for this till the end of the interrupt.
After the delay i simply set the CCP2 pin high then load the CCP2 register and then setup the CCP2 module to go low when it reaches the value.
Int the CCP2 int the module is disabled. (mainly i think i may need to do this because the output_high(CCP2_PIN); wont work if the CCP is enabled?)
Does this look like it will work, i dont have a scope about at the moment to check any of this which is why i want to try get the code correct first.
Just wondering also if i need to perform the measurement at the top of the code, i did it this way as i want to calculate the last value ASAP and not add the delay to it.
Cheers for all your help!
Thanks
Pilt |
|
![](templates/subSilver/images/spacer.gif) |
pilt1 Guest
|
|
Posted: Fri May 19, 2006 6:50 am |
|
|
Bottom bit should be
Code: |
#int_ccp2
void ccp2int()
{
setup_ccp2(CCP_OFF);
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Fri May 19, 2006 8:17 am |
|
|
Are you using 'delays' for anything in the main code?.
If so, add a seperate #use delay statement, in front of the interrupt code.
Lok through the forum for examples of how to do this. I think it was originally posted by PCM_programmer as a solution for this problem.
This will result in a seperate 'set' of delay code being generated for the interrupt code, and the main stuff, and avoid the problem which will otherwise occur with interrupts being disabled inside the delays in the non nterrupt code.
I'd leave CCP2 'running'. It shouldn't matter that it keeps resetting the pin, and you don't need an interrupt handler for it then (saves code, and the time involved in checking for another interrupt source).
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
pilt1 Guest
|
|
Posted: Fri May 19, 2006 8:35 am |
|
|
Ttelmah wrote: | Are you using 'delays' for anything in the main code?.
If so, add a seperate #use delay statement, in front of the interrupt code.
|
Yes i am, but i did add a seperate delay statement in front of the interrupt like you said
Code: |
#use delay(clock=20000000,restart_wdt)
#int_ccp1 //
........
|
Is this correct.
Thanks for all your help Ttelmah
Pilt |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|