;============================================================ ;== Full cycle multichannel ELC and heater controller == ;== by Manfred Mornhinweg, october 2008, may 2009 == ;============================================================ ;50Hz AC sample (one volt is OK) connected between RA1 and RA2. ;PortB 0..3, priority 0..3. PortB 5..7 and PortA.0, all priority 4. '============================== User constants ================================================ Period con 20000 ;timer cycles per AC cycle. 20000us on 4MHz clock Pgain con 8 ; proportional gain, from counts error to 15bit variable Idiv con 1 ; integral division ratio, 1/gain '=============================================================================================== '============================== Pin definitions ============== ACin var CMCON.7 Led var porta.3 ;pin 2 for lock LED '============================ variables ====================== ACstat var bit Pvalue var word Ivalue var word PIvalue var word TimCount var word PeriodError var word LoadN var word FracAcc var word debint var byte ;debug interval counter WhichTriac var byte ;next bit to be set in TRIACs register TRIACs var byte ;shadow for port register Istate var word Ichange var word CMCON=5 ;enable comparator 2 TRISB=0 ;set port B to output. Bit 4 will not work, PROG! TRISA.0=0 ;set pin 17 to output, to use instead of portb.4 TRISA.3=0 ;set pin 2 to output, for lock LED WhichTriac=16 ;initialize Mainloop:if ACin<>ACstat then 'every half cycle PORTB=TRIACs 'put out info of previous measurement. PORTA.0=TRIACs.4 pauseus 1000 '1ms pulse for triggering TRIACs PORTB=0 PORTA.0=0 Toggle ACstat 'toggle, not =ACin, to prevent noise problems! if ACstat=0 then 'at 1ms after beginning of full cycle T1CON=0 'stop timer TimCount.highbyte=TMR1H 'read timer TimCount.lowbyte=TMR1L TMR1H=0 'reset timer TMR1L=18 'preload to compensate for processing time T1CON=1 'restart timer '============= PI function ============================================================= PeriodError= Period - TimCount 'centered on zero Ichange= (PeriodError+32768)/Idiv - 32768/Idiv Istate=Istate+Ichange Istate=Istate MIN 49151 Istate=Istate MAX 16384 TimCount=TimCount MIN (Period + 16384/Pgain) TimCount=TimCount MAX (Period - 16384/Pgain) Pvalue= (Period-TimCount) * Pgain 'centered on zero, +/-16384 max PIvalue= Istate + Pvalue 'Spans 0 to 65535 PIvalue=Pivalue MAX 16384 'cut down range PIvalue=PIvalue MIN 49151 PIvalue=Pivalue - 16384 'Range is now 0 to 32767 '============================================================================================= if PIvalue=0 or PIvalue=32767 then 'unlocked Led=0 else Led=1 'locked endif LoadN=Pivalue >> 12 'Integer number of loads now ready, 0-7 PIvalue= PIvalue & %0000111111111111 'keep only fraction FracAcc=FracAcc + PIvalue 'add fraction if FracAcc.12 = 1 then LoadN=LoadN+1 'switch on additional load if overflow FracAcc=FracAcc & %0000111111111111 'reset overflow, not really necessary! endif if LoadN=0 then TRIACs=0 'set priority channels if LoadN=1 then TRIACs=1 if LoadN=2 then TRIACs=3 if LoadN=3 then TRIACs=7 if LoadN>3 then TRIACs=15 if LoadN>4 then 'heaters LoadN=LoadN-4 SwTRIACs: TRIACs=TRIACs | WhichTriac 'set bit WhichTriac=WhichTriac << 1 if WhichTriac=0 then WhichTriac=16 'convert shift into rotate through 4 MSBs! LoadN=LoadN-1 if LoadN>0 then goto SwTRIACs endif endif endif goto Mainloop