Some PIC assembly fragments of code to do PLL based mains sync and 255-level output phase control.
I wrote this for a 16C73 about 20 years ago.. Most later stuff is in C rather than assembly.
[Using a 20MHz clock; timing based on that].
All main product and customer-specific code removed..
Put the control value in "outphase".
You need a few other memory locations like "clockref", "phase", "mainsref", "stat_temp" etc.
The timing reference input looks to have been a direct pickup from AC via a resistor to a port A pin (hz).
It uses each transition either way and compares against the last input state at each interrupt.
You need to change the mains00 / main10 parts if you use a different type of sync input, eg. trigger on the negative [high to low] transition only and bypass the routine [exitint] (but still set the image flag high) on low to high, with the full-wave opto setup.
mainsref,7 is the bit that the normal program loop monitors to count cycles & do low speed timing, read it and reset when seen in that.
(Also used by the PLL phase comparison, so be careful if you change that).
PORTB,s_oe is the triac trigger ouput.
PORTB,mref is a spare pin to monitor the program zero detection.
[Edit - typos & clarification].
Some initialisation stuff..
Code:
;
; PAGE 0 Register setup ***
;
bcf STATUS,RP0 ; Select page 0
movlw 000 ; Set port B to
movwf PORTB ; $00 = all o/p off.
movlw D'001' ; Init. timer
movwf TMR0 ; to avoid w/d
;
; Clear workspace
;
movlw 021 ; Clear RAM
movwf FSR ; Set indirect ptr
movlw 05E ; Byte Count
movwf iomode ; Save Count
;
begin2 clrf INDF ; Clear ram via indirect
incf FSR,f ; next addr
decfsz iomode,f ; Loop till done
goto begin2 ;
clrf iomode ;
;
; All ram clear.
;
; Set o/p on phase
; (Higher value = shorter firing pulse)
;
movlw d'160' ; Triac firing pulses turned off
movwf outphase ; at ??/256 from end of each half cycle.
;
; Set master Timer value
;
movlw D'050' ; 256 - 50 = 200 Cycles
movwf clockref ;
movwf TMR0 ; Reset Timer
bcf INTCON,2 ; Reset int flag.
;
; Enable Interrupts.
;
bsf INTCON,T0IE ; Enable timer int
bsf INTCON,GIE ; & global int.
The interrupt routine that does all the work:
Code:
;
;
; Interrupt driven routines
;
; Executed at interval of (200nS * 200) = approx. 40uS
;
intrpt movwf w_temp ; Save W
swapf STATUS,w ; Save context
bcf STATUS,5 ; Bank 0
movwf stat_temp ;
movf PCLATH,w ; Get latch
movwf pcl_temp ; save it
;
;Timer counts UP, Int at rollover 255->0
;
movf clockref,w ; Get timer value
movwf TMR0 ; reload timer
bcf INTCON,2 ; reset ctr int flg
;
; Shift Phase counter
;
decf phase,f ; Next step
;
; Do Phase Control outputs
;
outangle movf phase,w ; Get Phase
subwf outphase,w ; Compare to o/p value
btfsc STATUS,C ; Negative result?
goto out_off ; No, turn OFF
out_on bcf PORTB,s_oe ; Yes, turn ON
goto endphase ;
out_off bsf PORTB,s_oe ; Set outputs OFF
;
; Do mains Zero-Crossing detection ;
;
;endphase movf phase,w ; Look at phase
; subwf D'64' ; 3/4 way through?
; btfsc STATUS,Z ;
; bsf mainsref,7 ; Show zero crossing occurred for async. program.
;
endphase btfsc mainsref,0 ; Look at present value
goto mains10 ;
;
; Last was 0, has it changed?
;
mains00 btfss PORTA,hz ; Still 0?
goto exitint ; Yes.
bsf mainsref,0 ; Update flag,
; bsf PORTB,mref ;
goto mainsx ;
;
; Last was 1, has it changed?
;
mains10 btfsc PORTA,hz ; Still 1?
goto exitint ; yes.
bcf mainsref,0 ;
; bcf PORTB,mref ;
;
; Zero crossing occurred.
;
; Update phase values from output values.
;
; Look at Phase counter (counts down from 255 - 0).
; Adjust master clock to get as near 255 counts as possible per sequence.
;
;
; Do clock timing.
;
mainsx movf phase,w ; Look at count
btfsc STATUS,Z ; Is it Zero?
goto mainsnul ; Yes, no change.
btfsc phase,7 ; Look at phase counter
goto mainsdec ;
;
; Phase has not overflowed, shorten timer interval.
;
mainsinc incf clockref,f ; Clock will run faster.
goto mainsnul ;
;
; Phase has overflowed, lengthen timer interval.
;
mainsdec decf clockref,f ; Clock will run slower.
;
mainsnul movlw 0FE ; Start just below 255, so 100% on possible.
movwf phase ; Restart phase counter
bcf clockref,7 ; Ensure clock can't get too fast...
;
bsf mainsref,7 ; Show zero crossing occurred for async. program.
;
;
; Restore context & return
;
exitint movf pcl_temp,w ; Restore saved regs.
movwf PCLATH ;
swapf stat_temp,w ;
movwf STATUS ;
swapf w_temp,f ;
swapf w_temp,w ;
retfie ; Back to prog.
;
; End of base program.
;