I have a project that needs to put out a series of pulses at zero crossing of the 60hz line. I have a zero crossing detector that outputs a 350us pulse at the line rate. I have played around with the interrupts and assembly instructions to get my output pulses close (1.2usec) to the trigger, but of course you can never instantly perform an action. I think I probably violated some PIC law by not saving my pointers in the interrupt routine, but it works. Here is the working code:
Code:
' acctune.pbp Proven to work 8-21-06
' Interrupt on rising edge of beam sync using PIC16F84A-20
' Interrupts in assembly language, mixing basic between assembly
' calls. This method drasticaly improves capturing the edge of an external
' signal. Edge is captured, the interrupt is called, then some basic commands
' are performed to create the pulse structure. Total time delay
' from beam sync rising edge to PIC pulse generation is 1.2usec. Beam sync is a
' 350usec long ttl pulse that occurs at a 60hz rate.
' Interrupt on PORTB.0 (INTE) will create a tune mode pulse on PORTB.1
Define OSC 20
out var PORTB.1 ' alias for the output pin.
define INTHAND myint ' Define interrupt handler
Goto start ' Skip around interrupt handler, but always put the
' handler in the front of the program.
asm ; Assembly language interrupt handler
myint
;normally one would save all the pointers here, but I'm interested in getting
;my pulses out ASAP. It works without a save and restore of pointers. I
;guess because my code isn't changing anything important.
endasm
out = 1 'Take the pin high
PAUSEUS 200
out = 0 'Take pin low
PAUSEUS 100
out = 1
PAUSEUS 4 'results in exactly 4.2usec at 20Mhz clock.
out = 0
pauseus 100 'guarantees that we won't trigger on other edge of beam sync.
'we were triggering on a rising edge, but if noise occurs during
'falling edge it might cause a false trigger.
asm
bcf INTCON, 1 ; Clear interrupt flag
endasm
@ retfie ; Return from interrupt
start: TRISB = %11111101 ' I/O 1 is output, all others are in
OPTION_REG = %01111111 ' Enable PORTB pullups, interrupt on
' rising edge of RB0.
INTCON = %10010000 ' Enable INTE interrupt
loop: goto loop ' get stuck here to prove true interrupt capability
Now I should be satisfied with the 1.2usec delay but I'm not. I want my pulse train to output within 200nsec of line crossing. Since 60hz line crossing is a highly repetitive signal it would seem to be a simple matter to have the sync signal reset a timer and then output my pulse when the timer is at a value corresponding to 16.6666ms. So far this idea is stuck in my head and I'm not sure if it would work because the next real line crossing would reset the timer and it might not actually reach the count. So I guess I would have to toggle between two counters that get reset every other cycle. Then there's the problem of phase errors when 60hz becomes 59.9 or 60.1 hz.
Any ideas out there?
I know I can do this with straight digital logic chips, but they aren't as fun as pics. I can also use an 18F PIC with the HSPLL to get 40MHz, which would bring my pulses within 600ns with my existing code.
Are there any assembly Guru's out there that can tell me why I luck out not saving and restoring my pointers?
Bookmarks