|
|
View previous topic :: View next topic |
Author |
Message |
Einly
Joined: 10 Sep 2003 Posts: 60
|
Output a pulse of 6.5us upon pin B0 interrupt |
Posted: Tue May 03, 2005 9:23 am |
|
|
Dear all,
I wish to do the following:
Whenever I receive a low to high interrupt on Pin B0, I will output a high pulse at Pin C0 and starts a timer 2 which will overflow after 6.5us. When timer 2 overflow, Pin C0 will be low again. This process repeats again when I receive another low to high interrupt. Below is my program:
#include <16f876.h>
#fuses hs,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#byte PORTA=5
#byte PORTB=6
#byte PORTC=7
#int_ext
void ads_isr()
{
output_high(PIN_C0);
setup_timer_2(T2_DIV_BY_1,32,1);
enable_interrupts(INT_TIMER2);
}
#int_timer2
timer2_isr()
{
output_low(PIN_C0);
disable_interrupts(INT_TIMER2);
}
void main()
{
set_tris_b(0x01);
set_tris_b(0);
ext_int_edge(l_to_h);
enable_interrupts(global);
enable_interrupts(int_ext);
}
1) Does this line reset the timer 2 value and recount for 6.5us?
setup_timer_2(T2_DIV_BY_1,32,1);
2) Does the program above look logical (meet the requirements)?
I might be wrong in placing this line at the wrong place
setup_timer_2(T2_DIV_BY_1,32,1);
enable_interrupts(INT_TIMER2);
Thanks a lot... _________________ Einly |
|
|
Ttelmah Guest
|
|
Posted: Tue May 03, 2005 10:31 am |
|
|
The setup line, sets the prescaler, and the 'limit'. If the timer was already running, it could contain a count already at this point, but from power up, it shouldn't. You should be setting the timer up in main, then resetting the _count_ in the interrupt, clearing the interrupt flag (since it will already have been triggered if the timer was running), then enabling the interrupt.
However, your big problem is _latency_. You cannot do what you want with an interrupt. The problem is that when the interrupt occurs, a global interrupt handler is called. This saves a number of registers, and then checks what has interrupted, and eventually calls the handler itself. All this takes time. The typical handler on the 16 family processor, will reach the interrupt routine, about 30 instruction times after the event occured. Then returning from the interrupt typically takes another 25 instruction times. So in your external interrupt, once everything is 'set', 25 instruction times occur before the code returns to the main flow. Only 7 instructions latter, the timer triggers (the first time, on latter loops, the timer interrupt will already have been triggered because the timer was still running), then another 30 instruction times pass, before the edge is generated.
Look instead at using timer1, and the CCP module. The special event setting of this, allows it to clear a pin automatically when a count is reached. This however has to use the CCP pin, not pin_c0.
With the approach you are currently using, the shortest pulse possible, would be about 11uSec, which is the time taken to exit the interrupt routine, enter again, and operate the pin...
Given that the code results in an amost immediate second interrupt, which will itself take about 13uSec to handle, you might as well use the other 'normally avoided' approach, and just operate the pin with a delay in the interrupt handler. However this will still occur some 5uSec after the actual event that triggered the interrupt...
Best Wishes
Best Wishes |
|
|
Einly
Joined: 10 Sep 2003 Posts: 60
|
CCP module? |
Posted: Mon May 09, 2005 8:38 pm |
|
|
"Look instead at using timer1, and the CCP module. The special event setting of this, allows it to clear a pin automatically when a count is reached. This however has to use the CCP pin, not pin_c0. "
I tried to look at the Microchip AN594 application note and found out that there is 2 mode associated with the CCP module, which is compare and capture. For my application, how do I use the CCP module? There will be pulses coming into a pin (external pulses with a maximum frequency of 300kHz). Upon receiving a high to low pulse, I will output a 6.5us high pulse on a pin.
May I know what should I do to achieve that? Is it possible using CCP module? Do you have any example lines of code to do that? Which pins should I use? (I need 2 pins, 1 for receiving the high to low pulse, 1 to output the 6.5us). _________________ Einly |
|
|
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
|
Posted: Tue May 10, 2005 2:10 pm |
|
|
Use a CCP module in compare mode. When external interrupt occurs, setup the compare module to a 6.5us (plus an instruction cycle needed to set the output high) value and make it so it will clear the CCP output on match. Clear the timer1. Set the CCP output to high and when the compare match occurs, the output will return low. Then use the compare interrupt to turn the CCP of until you need it again.
Like Ttalmah said, you may be better off with:
Code: | #int_ext
void ads_isr()
{
output_high(PIN_C0);
delay_us(6.5);
output_low(PIN_C0);
} |
I would then use #USE FAST_IO and setup the tris register myself so there is not time wasted while output_hi() or output_low() is setting the tris registers every time you use the functions. (tweek) _________________ -Matt |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Tue May 10, 2005 3:58 pm |
|
|
DragonPIC wrote: |
Like Ttalmah said, you may be better off with:
Code: | #int_ext
void ads_isr()
{
output_high(PIN_C0);
delay_us(6.5);
output_low(PIN_C0);
} |
I |
Can delay_us take floats?
Scott |
|
|
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
|
Posted: Wed May 11, 2005 12:38 pm |
|
|
I have used the decimal point before with the SX version with no problem. I used a constant and do not remember checking the accuracy. If needed, just use:
Code: | delay_us(6);
delay_cycles(2);//or 3 for 6.6us |
about 6.4us (since each cycle is about 200ns) is as close as your gonna get.
or
delay_cycles(32); _________________ -Matt
Last edited by DragonPIC on Wed May 11, 2005 12:49 pm; edited 1 time in total |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Wed May 11, 2005 12:48 pm |
|
|
DragonPIC wrote: | I have used the decimal point before with the SX version with no problem. I used a constant and do not remember checking the accuracy. If needed, just use:
Code: | delay_us(6);
delay_cycles(2);//or 3 for 6.6us |
about 6.4us (since each cycle is about 200ns) is as close as your gonna get. |
If the 0.1 us is really critical, you might consider jumping up to an 18F chip and doubling the clock speed
Scott |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 11, 2005 12:49 pm |
|
|
No, it can't take a float.
Compile the following program with PCM vs. 3.224:
Code: | #include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
void main()
{
delay_us(6.5);
delay_us(6);
while(1);
} |
Here is part of the .LST file. You can see clearly that it's doing
a delay of 6 us for the delay_us(6) statement, because at 4 MHz,
one NOP instruction takes 1 us. With the float, it obivously isn't
isn't doing a 6 us delay.
Code: | 0000 00348 .................... delay_us(6.5);
0038 3014 00349 MOVLW 14
0039 1283 00350 BCF 03.5
003A 00A1 00351 MOVWF 21
003B 2804 00352 GOTO 004
003C 3003 00353 MOVLW 03
003D 00A1 00354 MOVWF 21
003E 30C8 00355 MOVLW C8
003F 00A2 00356 MOVWF 22
0040 281B 00357 GOTO 01B
0041 0BA1 00358 DECFSZ 21,F
0042 283E 00359 GOTO 03E
0000 00360 ....................
0000 00361 .................... delay_us(6);
0043 0000 00362 NOP
0044 0000 00363 NOP
0045 0000 00364 NOP
0046 0000 00365 NOP
0047 0000 00366 NOP
0048 0000 00367 NOP
0000 00368 .................... |
|
|
|
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
|
Posted: Thu May 12, 2005 10:25 am |
|
|
I beleive he is running at 20MHz. Retry with 20MHz. Your probably right anyway since it doesn't look right. The compiler should have come up with an error. _________________ -Matt |
|
|
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
|
Posted: Thu May 12, 2005 10:43 am |
|
|
sseidman wrote: | DragonPIC wrote: | I have used the decimal point before with the SX version with no problem. I used a constant and do not remember checking the accuracy. If needed, just use:
Code: | delay_us(6);
delay_cycles(2);//or 3 for 6.6us |
about 6.4us (since each cycle is about 200ns) is as close as your gonna get. |
If the 0.1 us is really critical, you might consider jumping up to an 18F chip and doubling the clock speed
Scott |
Or you could check out one of the SX chips by Ubicom (marketing handled by parallax). These chips cruise at 50MHz+ and execute an instruction per cycle giving you 20ns/instruction by using a instruction pipeline. CCS makes a compiler for the SX also. _________________ -Matt |
|
|
|
|
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
|