'**************************************************************** '* Name : PWPS_Servo.INC Pulse Width Position Servo * '* Author : Darrel Taylor * '* Date : 5/1/2003 * '* Version : 1.0 * '* Notes : * '* : * '**************************************************************** DEFINE INTHAND INT_CODE ' Tell PBP Where the code starts on an interrupt wsave VAR BYTE $20 SYSTEM '$20 Save location for the W register if in bank0 wsave1 VAR BYTE $A0 SYSTEM ' Save location for the W register if in bank1 wsave2 VAR BYTE $120 SYSTEM ' Save location for the W register if in bank2 ;wsave3 VAR BYTE $1A0 SYSTEM ' Save location for the W register if in bank3 ssave VAR BYTE Bank0 SYSTEM ' Save location for the STATUS register psave VAR BYTE Bank0 SYSTEM ' Save location for the PCLATH register W1 var word ' Temporary variable y var byte ' Temporary variable PulseTicks1ms var word ' # of Ticks for 1ms TicksPeruSx100 var word ' # of Timer Ticks to = 1 us * 100 uS50Hz var word ' # of Ticks for 50 Hz with prescaler PicOSC var byte Bank0 ' OSC value, Usable in PBP OffTimePrescaler var byte ' Timer1 Prescale value during OFF period Position var word ' 0 - 900 0 = 1.05ms 900 = 1.95ms T1CONoff var byte Bank0 TMR1_ON_TICKS var word ' # of Tmr ticks for On Time TMR1_OFF_TICKS var word ' # of Tmr ticks for Off Time TMR1_ON_VAL var word Bank0 ' # to load TMR1 for On Time TMR1_OFF_VAL var word Bank0 ' # to load TMR1 for Off Time DataFlags var byte Bank0 Valid var DataFlags.0 ' 1 if Freq is valid - Set by CalcPWPS: PWPSenabled var DataFlags.1 ' shows if PWPS is running or not PWPSstate var DataFlags.2 ' Current state of PWPS output high or low GIE var INTCON.7 PEIE var INTCON.6 TMR1IE var PIE1.0 TMR1ON var T1CON.0 goto GetOsc ' ------------------------------------------------------------------------ asm INT_CODE if (CODE_SIZE <= 2) movwf wsave ; copy W to wsave register swapf STATUS,W ; swap status reg to be saved into W clrf STATUS ; change to bank 0 regardless of current bank movwf ssave ; save status reg to a bank 0 register movf PCLATH,w ; move PCLATH reg to be saved into W reg movwf psave ;6 ; save PCLATH reg to a bank 0 register endif btfss PIR1, TMR1IF ; is TMR1IF set? Timer1 Interrupt Flag GOTO NoTimerInt ; No. Bypass timer load btfss _Valid ; Is Freq valid? GOTO NoPWPS ; No. Halt PWPS btfss _PWPSenabled ; is Software PWM enabled? GOTO NoPWPS ; No. Halt PWPS ; Yes, then Set output and reload Timer1 btfss _PWPSstate ; Is Output High? GOTO TurnON ;9/15 ; No. TurnOFF bcf _PWPSpin ; Set PWPSpin Low bcf _PWPSstate ; MOVF _T1CONoff,W ; Load OFF Period Prescaler and Turn off timer MOVWF T1CON ; MOVF _TMR1_OFF_VAL,W ; 1 ADDWF TMR1L,F ; 1 reload timer with Off Period value BTFSC STATUS,C ; 1/2 INCF TMR1H,F ; 1 MOVF _TMR1_OFF_VAL+1,W ; 1 ADDWF TMR1H,F ; 1 BSF T1CON,TMR1ON ; 1 Turn it back on GOTO TimerDone ;13/28 TurnON bsf _PWPSpin ; Set PWPSpin High bsf _PWPSstate ; CLRF T1CON ; Clear Prescaler and Turn off timer MOVF _TMR1_ON_VAL,W ; 1 ADDWF TMR1L,F ; 1 reload timer with On Period value BTFSC STATUS,C ; 1/2 INCF TMR1H,F ; 1 MOVF _TMR1_ON_VAL+1,W ; 1 ADDWF TMR1H,F ; 1 bsf T1CON,TMR1ON ; 1 Turn it back on GOTO TimerDone NoPWPS bcf T1CON,TMR1ON ; Turn off timer bcf _PWPSpin ; Idle PWPSpin Low TimerDone bcf PIR1, TMR1IF ; 1/29 ; Clear Timer1 Interrupt Flag NoTimerInt Movf psave,w ; Restore the PCLATH reg Movwf PCLATH swapf ssave,w ; Restore the STATUS reg movwf STATUS swapf wsave,f swapf wsave,w ; 6/35 ; Restore W reg Retfie ; Exit the interrupt routine endasm ' ------------------------------------------------------------------------ StartPWPS: ' Set Position before calling low PWPSpin ' Set PWPSpin to Output and idle Low GIE = 1 ' Global Interrupt Enable PEIE = 1 ' Peripheral Interrupt Enable TMR1H = 255 ' Load TMR1 with 65535, First tick will cause TMR1L = 255 ' an interrupt that will load TMR1_???_VAL SetPWPS: ' Set Position before calling Position = Position min 1200 ' Make sure we don't go to far gosub CalcPWPS if Valid = 1 then PWPSenabled = 1 lookdown OffTimePrescaler,[1,2,4,8],y lookup y,[0,1,2,3],y T1CONoff = y << 4 TMR1_ON_VAL = 65535 - TMR1_ON_TICKS + 7 ' Value to load in Timer1 for ON period TMR1_OFF_VAL = 65535 - TMR1_OFF_TICKS + 7 ' Value to load in Timer1 for OFF period TMR1IE = 1 ; Enable Timer1 Interrupts T1CON = 1 ; Turn Timer1 on (no prescaler) endif return StopPWPS TMR1IE = 0 TMR1ON = 0 low PWPSpin ' Idle output Low PWPSstate = 0 PWPSenabled = 0 return CalcPWPS: ' Set Position before calling 0-900 Valid = 1 y = 99 LookDown PicOSC,[4, 8, 10, 12, 16, 20, 24, 25, 32, 33, 40],y if y = 99 then OSCnotFound ;LookUp2 y,[ 1050, 2100, 2625, 3150, 4200, 5250, 6300, 6562, 8400, 8660, 10500],PulseTicks1ms LookUp2 y,[ 900, 1800, 2250, 2700, 3600, 4500, 5400, 5625, 7200, 7425, 9000],PulseTicks1ms lookup2 y,[ 100, 200, 250, 300, 400, 500, 600, 625, 800, 825, 1000],TicksPeruSx100 lookup y,[ 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4],OffTimePrescaler Lookup2 y,[20000,40000,50000,60000,40000,50000,60000,62000,40000,41000,50000],uS50Hz W1 = TicksPeruSx100 * Position W1 = Div32 100 TMR1_ON_TICKS = W1 + PulseTicks1ms TMR1_OFF_TICKS = uS50Hz - (TMR1_ON_TICKS / OffTimePrescaler) return OSCnotFound: Valid = 0 return GetOsc: ' Retreive defined OSC value on Reset asm ifdef OSC MOVE?CB OSC, _PicOSC else MOVE?CB 4, _PicOSC endif endasm