emufambirwi
Member
Thank you so much, there is so much to learnSome 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. ;