View previous topic :: View next topic |
Author |
Message |
amereshadow
Joined: 16 May 2008 Posts: 5
|
measuring time between 2 events |
Posted: Fri May 16, 2008 3:52 pm |
|
|
hi, i always found an answer to my questions here in this forum, but not for this one, a problem with my final project at university. here's the problem:
i have to determine the speed of a motorbike using the space/time old way, where i know space and time is the problem. i have built two laser sensors that view the motor passing (using interferometry) and outputs a semi-squared pulse (of about 4 volt); the duration is proportional to the speed of object passing throught the laser, and for an object at 250-300 km/h is between 2 and 3 msec.
so i have 2 pulse from 2 laser and with a DAQ, a pc and Labview the system works great and i have a maximum error of 0.5% on the speed.
now it's time to eliminate computer using a pic. now i'm testing on a 16f877a, but probably i'll use a 18f4458 to use the usb functionality...
my idea is to use the 2 ccp input setted to compare, each one connected to a laser. on the ccp1 interrupt i set timer1 to zero, and on #int_ccp2 i read the value of timer1 and convert it to time interval.
is this approach correct? now i'm working on the code but i've some doubts... the operations i'm doing at the timer1 interrupt will cause some loss of time, making the time-determination less accurate? it's also possible that the lenght of the pulse is wider, say dozens of ms, how can i have a longer timer1 interrupt-time?
i'm now running a 16f777 (no crystal at home now ) @8MHz
timer1 with a 8_prescaler implies a counter period of 4us and an overflow after 262.144us
Code: |
#include <16f777.h>
#fuses NOMCLR, NOPUT, NOWDT
#use delay(8000000,internal)
#use rs232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7)
int num_over=0;
#INT_TIMER1
void isr3(){
num_over++;
//printf("\r\n%u",num_over);
}
#int_ccp2
void isr2(){
int16 valore;
valore=get_timer1();
//
}
#int_ccp1
void isr(){
set_timer1(0);
//printf("\n\r rilevato impulso su ccp1");
}
void main(){
output_high(PIN_B5); //initial blink
delay_ms(500);
output_low(PIN_B5);
setup_port_a( ALL_ANALOG ); //used by a side routine
setup_adc( ADC_CLOCK_INTERNAL );
set_adc_channel( 2 );
delay_ms(1);
setup_uart(9600); //initialize serial
printf("\r\n-------------------Inizio-------------------\r\n");
setup_timer_1(T1_INTERNAL| T1_DIV_BY_8); //timer1 initialization
setup_ccp1(CCP_CAPTURE_RE); //setting ccp and #int
setup_ccp2(CCP_CAPTURE_RE);
enable_interrupts(INT_CCP1);
enable_interrupts(INT_CCP2);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while (TRUE){
printf("\r\n - wainting");
delay_ms(1000);
}
}
|
anyone sees errors? maybe a big big one, now i'm like blinded after 8 hours three stairs under the surface of earth testing this beast...
tnx in advance
pietro |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 16, 2008 3:59 pm |
|
|
Quote: |
and outputs a semi-squared pulse (of about 4 volt);
the duration is proportional to the speed of object passing
|
CCS has an example of using two CCP's to measure the width of
a single pulse. See this file:
Quote: | c:\Program Files\picc\Examples\Ex_ccpmp.c |
|
|
|
amereshadow
Joined: 16 May 2008 Posts: 5
|
|
Posted: Fri May 16, 2008 4:04 pm |
|
|
already tried to adapt it to fit my directives but nothing usefull... :(
I've to measure the time between the rising edges of two independent pulses (=over two different wires) whose duration varies, just to say, from 1 to 10ms... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 16, 2008 4:14 pm |
|
|
I think the CCS example should still be able to work.
Do these changes:
1. In the CCS example, the CCP1 and CCP2 pins are connected
together. Don't do that. Put the pulse the occurs first on the CCP1 pin,
and put the pulse that occurs last on the CCP2 pin.
2. In the CCS example, CCP2 is set to use the Falling Edge.
Change the CCP2 edge to the rising edge. You have already done this.
3. Get rid of the timer interrupt routine, and the don't enable interrupts
for it.
4. Get rid of the CCP1 isr in your code. (Also the interrupt enable).
5. Only use the CCP2 isr, as in the CCS example. Use the CCS code
to put inside the isr. |
|
|
amereshadow
Joined: 16 May 2008 Posts: 5
|
|
Posted: Sun May 18, 2008 4:19 am |
|
|
i tried the example as is. connecting ccp1 and ccp2 together to a source of a 1ms pulse and the program doesn't work correctly.
i tried then to capture only a rising edge event on ccp1 and i had problems: the interrupt event has never been triggered.
here's the code
Code: | #include <16f777.h>
#use delay(clock=8000000,internal)
#fuses NOPUT, NOWDT, NOMCLR
#use rs232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7)
#INT_CCP1
void isr1(){
printf("\r\nASD -> CCP_1= %Lu",CCP_1);
}
void main(){
CCP_1=0;
CCP_2=0;
setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while (TRUE){ //exit if pin D1 is grounded
delay_ms(500);
if(input(PIN_D1)==0){
break;
}
}
printf("\r\nFINE");
} |
|
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sun May 18, 2008 7:11 am |
|
|
It is never good practice to put a printf in an isr which is time critical. Most isr's will be time critical that's why they are interrupts so the best practice is to never put a printf in an isr. Set a flag and test the flag in main and do the printf there if the flag is set. |
|
|
amereshadow
Joined: 16 May 2008 Posts: 5
|
|
Posted: Sun May 18, 2008 11:59 am |
|
|
tried to set only an int1 flag in the int function and to read it periodically from the main... same result. int_ccp1 never triggered... |
|
|
|