;*************************************************************************** ; MAG1.asm Magnetic Actuator Driver ;*************************************************************************** ; Bruce Abbott bhabbott@paradise.net.nz ; ; for Microchip PIC12C5xx/12F6xx running at @ 4MHz (INT RC Clock) ; ;=========================================================================== ; Description ; ; Converts 1~2mS Servo pulse into PWM output, giving proportional control ; of a magnetic actuator. ; ; ; ========================================================================== ; Summary of Changes ; ; 2004/2/2 V0.01 - Initial release ; ; -------------------------------------------------------------------------- ; #DEFINE version 0 #DEFINE revision 1 ; PROCESSOR PIC12C508 ; PROCESSOR PIC12F675 ifdef __12C508 INCLUDE __CONFIG _MCLRE_OFF&_CP_OFF&_WDT_ON&_IntRC_OSC else INCLUDE __CONFIG _MCLRE_OFF&_CP_OFF&_WDT_ON&_BODEN_ON&_INTRC_OSC_NOCLKOUT endif radix dec errorlevel 0,-305,-302 ;#DEFINE NO_OSCCAL ; enable if OSCCAL value was erased! ; Bit definitions for the GPIO register and the TRIS register #DEFINE OUT1 1 ; pin 6 #DEFINE OUT2 2 ; pin 5 #DEFINE OUT3 4 ; pin 3 #DEFINE OUT4 5 ; pin 2 #DEFINE SERVO 3 ; pin 4 servo pulse input #DEFINE TrisBits (1<1 goto $+1 ; 2 clocks no_op_count SET no_op_count-2 ENDW IF no_op_count nop ; 1 clock ENDIF ENDM ;----------------------------------------------------------------------- ; Generate PWM output ;----------------------------------------------------------------------- ; ; Takes 12uS (including call&return) ; ; Must be called every 20uS. ; ; ; DoPWM: decfsz pwm_period ;3 end of PWM cycle ? goto pwm_step ;4(5) no, do the next PWM step movf pwm_ratio,w ;5 movwf pwm_count ;6 movlw PWMSTEPS ;7 yes, start another PWM cycle movwf pwm_period ;8 movf pwm_start,w ;9 movwf GPIO ;10 retlw 0 ;11,12 pwm_step: nop ;6 movlw 0 ;7 decf pwm_count ;8 Count down. skpnz ;9 If count=0 then ... movwf GPIO ;10 ... turn PWM output OFF. retlw 0 ;11,12 ;============================================================================ ColdStart: bcf Flags,TIMEOUT btfss STATUS,NOT_TO ; did Watchdog time out ? bsf Flags,TIMEOUT ifdef __12C508 ifdef NO_OSCCAL movlw 0x90 ; replace with value for your PIC! endif movwf OSCCAL ; set oscillator calibration else bsf STATUS,RP0 ; register bank 1 (12F629/75) call 0x3ff ; get OSCCAL value movwf OSCCAL ; set oscillator calibration bcf STATUS, RP0 ; register bank 0 endif ; Move prescaler from tmr0 to the watchdog, without causing accidental reset! clrwdt clrf TMR0 movlw OptionBits | 7 option clrwdt movlw OptionBits option clrwdt ; initialise I/O registers clrf GPIO ; all outputs low ifdef __12C508 movlw TrisBits Tris GPIO else bsf STATUS,RP0 ; register bank 1 movlw TrisBits movwf TRISIO ; set I/O pin directions ifdef ANSEL clrf ANSEL ; disable analog inputs (12F675) endif bcf STATUS,RP0 ; register bank 0 movlw b'00000111' movwf CMCON ; Comparator off endif ; CPU specific stuff done, now we can start the main program! goto Main ;--------------------------------------------------------------------------- ; Millisecond Delay Timer ;--------------------------------------------------------------------------- ; Input: W = number of milliseconds to wait x 2 (max 512mS) ; dx2k: movwf temp_1 _dx2k1: movlw (2000-2)/10 movwf temp_2 _dx2k2: clrwdt ; avoid watchdog timeout no_op 6 decfsz temp_2 goto _dx2k2 decfsz temp_1 goto _dx2k1 retlw 0 ;*************************************************************************** ; Main ;*************************************************************************** Main: btfsc Flags,TIMEOUT ; did the watchdog timeout ? goto Start ; oops! Try to recover... movlw 250 ; wait 500mS for Rx to stabilise call dx2k ; Start: clrf Flags ; clear all flags clrf pwm_ratio ; PWM off clrf pwm_start movlw 1 movwf pwm_period ; 1st DoPWM inits counter wait_low: clrwdt ;4 no_op 4 ;5~8 call DoPWM btfsc GPIO,SERVO ;1 wait for servo pulse Low goto wait_low ;2(3) nop ;3 wait_high: clrwdt ;4 no_op 4 ;5~8 call DoPWM btfss GPIO,SERVO ;1 wait for servo pulse High goto wait_high ;2(3) clrf ServoCount ;3 no_op 2 ;4,5 measure: clrwdt ;6 no_op 2 ;7,8 call DoPWM incfsz ServoCount,w ;1 incf ServoCount ;2 measure length of servo pulse btfsc GPIO,SERVO ;3 goto measure ;4(5) no_op 3 ;6~8 call DoPWM ; ; limit range to 1.1~1.9mS ; limit: movlw 1100/20 ;1 subwf ServoCount ;2 skpc ;3 clrf ServoCount ;4 1.1mS minimum no_op 2 ;5,6 ; ; wait until the next PWM cycle starts. ; wait_pwm: no_op 2 ;7,8 call DoPWM decf pwm_period,w ;1 skpnz ;2 goto last_pwm ;3(4) nop ;4 goto wait_pwm ;5,6 last_pwm: no_op 4 ;5~8 call DoPWM ; ; ; Update PWM ratio, whilst completing the current PWM cycle. ; ; split servocount into bi-directional PWM ; Do_Servo: movlw PWMSTEPS ;1 subwf ServoCount,w ;2 right or left ? skpc ;3 goto do_left ;4(5) do_right: movwf pwm_ratio ;5 PWM = 0~20 no_op 3 ;6~8 call DoPWM movlw 0 ;1 assume PWM will be OFF tstf pwm_ratio ;2 skpz ;3 PWM On time = 0 ? movlw RIGHT ;4 no, PWM will be ON movwf pwm_start ;5 nop ;6 goto new_pwm ;7,8 do_left: no_op 3 ;6~8 call DoPWM movlw PWMSTEPS ;1 movwf pwm_ratio ;2 movf ServoCount,w ;3 PWM = 20~1 subwf pwm_ratio ;4 movlw LEFT ;5 movwf pwm_start ;6 no_op 2 ;7,8 new_pwm: call DoPWM nop ;1 goto wait_low ;2,3 wait for next servo pulse ;------------------ Oscillator Calibration Subroutine ---------------------- ifdef NO_OSCCAL org 0x3ff ifdef __12F675 retlw 0x70 ; replace with osccal value for your 12F675! endif endif END