;****** ************************************************************************ ; ; LiniStepper v2 ; PIC 16F84 / 16F628 / 16F628A code (updated 628A June 2007) ; Copyright Aug 2002 - Nov 2009 - Roman Black www.romanblack.com ; ; PIC assembler code for the LiniStepper stepper motor driver board. ; 200/400/1200/3600 steps ; ; v2.0 New version 2.0; 2nd Nov 2009. ; * modified v1 source to work with new Lini v2 PCB. ; * STEP and DIR are the same, but POWER is now "ENABLE" (active LOW) ; (so the POWER pin function is inverted in Lini v2) ; v2.1 Updated 16th Nov 2010. ; Now incorporates update suggested by Brian D Freeman; improves ; performance by skipping the current calculation on the hi-lo ; transition of the step input. ; ; (set mplab TABS to 5 for best viewing this .asm file) ;****************************************************************************** ;============================================================================== ; mplab settings ERRORLEVEL -224 ; suppress annoying message because of option/tris ERRORLEVEL -302 ; suppress message because of bank select in setup ports LIST b=5, n=97, t=ON, st=OFF ; ; absolute listing tabs=5, lines=97, trim long lines=ON, symbol table=OFF ;============================================================================== ; processor defined ;include ;include include ; processor config IFDEF __16F84A __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC ENDIF IFDEF __16F628 __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF ENDIF IFDEF __16F628A __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _MCLRE_ON & _BODEN_OFF & _LVP_OFF ENDIF ;============================================================================== ; Variables here ;------------------------------------------------- IFDEF __16F84A #define RAM_START 0x0C #define RAM_END RAM_START+d'68' ; 16F84 has only 68 ram ENDIF IFDEF __16F628 #define RAM_START 0x20 #define RAM_END RAM_START+d'96' ; F628 has 96 ram ENDIF IFDEF __16F628A #define RAM_START 0x20 #define RAM_END RAM_START+d'96' ; F628A has 96 ram ENDIF ;------------------------------------------------- CBLOCK RAM_START status_temp ; used for int servicing w_temp ; used for int servicing step ; (0-71) ustep position! steptemp ; for calcs phase ; stores the 4 motor phase pins 0000xxxx current1 ; for current tween pwm current2 ; for current tween pwm inputs ; stores new input pins inputs_last ; stores last states of input pins ENDC ;------------------------------------------------- ; PIC input pins for porta #define STEP 0 ; / = move 1 step, \=do nothing #define DIR 1 ; lo= cw, hi=ccw #define POWER 2 ; lo=full power, hi=half power ; (Note! POWER pin was inverted for v2 !!!) ;------------------------------------------------- ; Custom instructions! #define skpwne skpnz ; after subxx, uses zero #define skpweq skpz ; after subxx, uses zero #define skpwle skpc ; after subxx, uses carry #define skpwgt skpnc ; after subxx, uses carry ;============================================================================== ; CODE GOES HERE org 0x0000 ; Set program memory base at reset vector 0x00 reset goto main ; ;============================================================================== ; INTERRUPT vector here org 0x0004 ; interrupt routine must start here int_routine ;------------------------------------------------- ; first we preserve w and status register movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register ;------------------------------------------------- ; we get here every 256 timer0 ticks 3900Hz ; int body code here if you want ;------------------------------------------------- ; finally we restore w and status registers and ; clear TMRO int flag now we are finished. int_exit bcf INTCON,T0IF ; reset the tmr0 interrupt flag movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt ;------------------------------------------------- ;============================================================================== ;****************************************************************************** ; MOVE MOTOR sets 8 portb output pins to control motor ;****************************************************************************** ; NOTE!! var step is used for sequencing the 0-71 steps ; uses tables! so keep it first in the code and set PCLATH to page 0 ;------------------ move_motor ; goto label ;------------------ ;------------------------------------------------- ; this code controls the phase sequencing and current ; settings for the motor. ; there are always 72 steps (0-71) ; we can split the main table into 2 halves, each have identical ; current sequencing. That is only 12 entries for hardware current. ; Then can x3 the table to get 36 table entries which cover all 72 steps. ; the 36 entries jump to 36 code pieces, which set the current values ; for the 2 possible tween steps... We need 2 current values, one ; for the x2 value and one for the x1 value. ;------------------------------------------------- ; PHASE SEQUENCING (switch the 4 coils) ; there are 4 possible combinations for the phase switching: ; each have 18 steps, total 72 steps: ; A+ B+ range 0 step 0-17 ; A- B+ range 1 18-35 ; A- B- range 2 36-53 ; A+ B- range 3 54-71 ;------------------------------------------------- ; find which of the 4 ranges we are in movf step,w ; get step movwf steptemp ; store as working temp movf steptemp,w ; sublw d'35' ; sub to test skpwle ; goto half_hi ; wgt, steptemp is 36-71 (upper half) ;------------------------- half_low ; wle, steptemp is 0-35 movf steptemp,w ; sublw d'17' ; sub to test skpwle ; goto range1 ; wgt range0 ; wle movlw b'00000101' ; 0101 = A+ B+ goto phase_done ; range1 movlw b'00001001' ; 1001 = A- B+ goto phase_done ; ;------------------------- half_hi ; steptemp is 36-71 ; NOTE! must subtract 36 from steptemp, so it ; will become 0-35 and ok with table later! movlw d'36' ; subtract 36 from steptemp, subwf steptemp,f ; (now steptemp is 0-35) ; now find the range movf steptemp,w ; sublw d'17' ; sub to test skpwle ; goto range3 ; wgt range2 ; wle movlw b'00001010' ; 1010 = A- B- goto phase_done ; range3 movlw b'00000110' ; 0110 = A+ B- phase_done ; note! steptemp is always 0-35 by here movwf phase ; store phase values ;------------------------------------------------- ; at this point we have the phasing done and stored as the last ; 4 bits in var phase; 0000xxxx ; now we have 36 possible current combinations, which we can do ; by separate code fragments, from a jump table. ; as we have 2 power modes; full and low power, we ; need 2 tables. ;------------------------------------------------- btfsc inputs,POWER ; select table to use goto table_lowpower ; ;------------------------------------------------- ; HIGH POWER TABLE ;------------------------------------------------- table_highpower ; movf steptemp,w ; add steptemp to the PCL addwf PCL,f ; ; here are the 36 possible values; ;------------------------- goto st00 ; * (hardware 6th steps) goto st01 ; (pwm tween steps) goto st02 ; (pwm tween steps) goto st03 ; * goto st04 ; goto st05 ; goto st06 ; * goto st07 ; goto st08 ; goto st09 ; * goto st10 ; goto st11 ; goto st12 ; * goto st13 ; goto st14 ; goto st15 ; * goto st16 ; goto st17 ; goto st18 ; * goto st19 ; goto st20 ; goto st21 ; * goto st22 ; goto st23 ; goto st24 ; * goto st25 ; goto st26 ; goto st27 ; * goto st28 ; goto st29 ; goto st30 ; * goto st31 ; goto st32 ; goto st33 ; * goto st34 ; goto st35 ; ;------------------------------------------------- ; LOW POWER TABLE ;------------------------------------------------- ; as low power mode is for wait periods we don't need to ; maintain the full step precision and can wait on the ; half-step (400 steps/rev). This means much easier code tables. ; The nature of the board electronics is not really suited ; for LOW power microstepping, but it could be programmed here ; if needed. ; NOTE!! uses my hi-torque half stepping, not normal half step. ; doing half stepping with the 55,25 current values gives; ; 55+25 = 80 ; max current 100+100 = 200 ; typical (high) current 100+50 = 150 ; so low power is about 1/2 the current of high power mode, ; giving about 1/4 the motor heating and half the driver heating. ; for now it uses only half-steps or 8 separate current modes. ; we only have to use 4 actual current modes as ; the table is doubled like the table_highpower is. ; NOTE!! I have left the table full sized so it can be modified ; to 1200 or 3600 steps if needed. ;------------------------------------------------- table_lowpower ; movf steptemp,w ; add steptemp to the PCL addwf PCL,f ; ; here are the 36 possible values; ;------------------------- ; A+ B+ (A- B-) goto lp00 ; goto lp00 ; goto lp00 ; goto lp00 ; goto lp00 ; 55,25 (100,45) current low (high) goto lp00 ; goto lp00 ; goto lp00 ; goto lp00 ; goto lp09 ; goto lp09 ; goto lp09 ; goto lp09 ; goto lp09 ; 25,55 (45,100) goto lp09 ; goto lp09 ; goto lp09 ; goto lp09 ; ;------------------------- ; A- B+ (A+ B-) goto lp18 ; goto lp18 ; goto lp18 ; goto lp18 ; goto lp18 ; 25,55 (45,100) goto lp18 ; goto lp18 ; goto lp18 ; goto lp18 ; goto lp27 ; goto lp27 ; goto lp27 ; goto lp27 ; goto lp27 ; 55,25 (100,45) goto lp27 ; goto lp27 ; goto lp27 ; goto lp27 ; ;------------------------------------------------- ; all tables done, no more tables after this point! ;------------------------------------------------- ; next are the 36 code fragments for the high power table. ; CURRENT INFO. ; hardware requires that we send the entire 8 bits to the motor ; at one time, to keep pwm fast. ; ----xxxx, where xxxx is the coils on/off phasing (done) ; xxxx----, where xxxx is the current settings for the A and B phases; ; xx------, where xx is current for A phase ; --xx----, where xx is current for B phase ; hardware currents for 6th stepping have 4 possible values; ; 00 = 0% current ; 01 = 25% current ; 10 = 55% current ; 11 = 100% current ;------------------------------------------------- ; PWM INFO. ; hardware gives us 6th steps, or 1200 steps/rev. ; to get 3600 steps/rev we need TWO more ; "tween" steps between every proper hardware 6th step. ; to do this we set 2 currents, current1 and current2. ; then we do FAST pwm, with 2 time units at current2, ; and 1 time unit at current1. ; this gives a current which is between the two currents, ; proportionally closer to current2. (2/3 obviously) ; this gives the ability to get 2 evenly spaced "tween" currents ; between our hardware 6th step currents, and go from 1200 to 3600. ; the next 36 code fragments set the 2 currents desired, then ; we goto a fast-pwm loop (same loop used for all currents) ; which modulates between the 2 currents and gives final ; output current. ;------------------------------------------------- st00 ; (6th step) movf phase,w ; get coil phasing (is 0000xxxx) iorlw b'11000000' ; set currents; 100,0 movwf current2 ; movwf current1 ; goto pwm ; st01 ; (tween step) movf phase,w ; get coil phasing iorlw b'11000000' ; set 100,0 movwf current2 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current1 ; goto pwm ; st02 ; (tween step) movf phase,w ; get coil phasing iorlw b'11010000' ; set 100,25 movwf current2 ; movf phase,w ; iorlw b'11000000' ; set 100,0 movwf current1 ; goto pwm ; ;------------------------- st03 ; (6th step) movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current2 ; movwf current1 ; goto pwm ; st04 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current2 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current1 ; goto pwm ; st05 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current2 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current1 ; goto pwm ; ;------------------------- st06 ; (6th step) movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current2 ; movwf current1 ; goto pwm ; st07 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current2 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current1 ; goto pwm ; st08 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current2 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current1 ; goto pwm ; ;------------------------- st09 ; (6th step) movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current2 ; movwf current1 ; goto pwm ; st10 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current2 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current1 ; goto pwm ; st11 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current2 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current1 ; goto pwm ; ;------------------------- st12 ; (6th step) movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current2 ; movwf current1 ; goto pwm ; st13 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current2 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current1 ; goto pwm ; st14 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current2 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current1 ; goto pwm ; ;------------------------- st15 ; (6th step) movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current2 ; movwf current1 ; goto pwm ; st16 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current2 ; movf phase,w ; iorlw b'00110000' ; set 0,100 movwf current1 ; goto pwm ; st17 ; movf phase,w ; iorlw b'00110000' ; set 0,100 movwf current2 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current1 ; goto pwm ; ;------------------------- ;------------------------- st18 ; (6th step) movf phase,w ; iorlw b'00110000' ; set 0,100 movwf current2 ; movwf current1 ; goto pwm ; st19 ; movf phase,w ; iorlw b'00110000' ; set 0,100 movwf current2 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current1 ; goto pwm ; st20 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current2 ; movf phase,w ; iorlw b'00110000' ; set 0,100 movwf current1 ; goto pwm ; ;------------------------- st21 ; (6th step) movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current2 ; movwf current1 ; goto pwm ; st22 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current2 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current1 ; goto pwm ; st23 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current2 ; movf phase,w ; iorlw b'01110000' ; set 25,100 movwf current1 ; goto pwm ; ;------------------------- st24 ; (6th step) movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current2 ; movwf current1 ; goto pwm ; st25 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current2 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current1 ; goto pwm ; st26 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current2 ; movf phase,w ; iorlw b'10110000' ; set 55,100 movwf current1 ; goto pwm ; ;------------------------- st27 ; (6th step) movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current2 ; movwf current1 ; goto pwm ; st28 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current2 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current1 ; goto pwm ; st29 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current2 ; movf phase,w ; iorlw b'11110000' ; set 100,100 movwf current1 ; goto pwm ; ;------------------------- st30 ; (6th step) movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current2 ; movwf current1 ; goto pwm ; st31 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current2 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current1 ; goto pwm ; st32 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current2 ; movf phase,w ; iorlw b'11100000' ; set 100,55 movwf current1 ; goto pwm ; ;------------------------- st33 ; (6th step) movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current2 ; movwf current1 ; goto pwm ; st34 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current2 ; movf phase,w ; iorlw b'11000000' ; set 100,0 movwf current1 ; goto pwm ; st35 ; movf phase,w ; iorlw b'11000000' ; set 100,0 movwf current2 ; movf phase,w ; iorlw b'11010000' ; set 100,25 movwf current1 ; goto pwm ; ; high power table done! ;------------------------------------------------- ; next are the 4 code fragments for the low power table. ; (no PWM is used) ;------------------------------------------------- lp00 ; movf phase,w ; iorlw b'10010000' ; set 55,25 movwf current2 ; movwf current1 ; goto pwm ; lp09 ; movf phase,w ; iorlw b'01100000' ; set 25,55 movwf current2 ; movwf current1 ; goto pwm ; lp18 ; movf phase,w ; iorlw b'01100000' ; set 25,55 movwf current2 ; movwf current1 ; goto pwm ; lp27 ; movf phase,w ; iorlw b'10010000' ; set 55,25 movwf current2 ; movwf current1 ; goto pwm ; ;------------------------------------------------- ;------------------------------------------------------------------------------ ;****************************************************************************** ; Main ;****************************************************************************** ; ;------------------ main ; goto label ;------------------ ;--------------------------------------------- ; do initial setup for ports and ints and stuff call setup ; this is our only proper call... ; it is called only once, and does not really need ; to be a function. ;--------------------------------------------- ; main operating loop is here. ;--------------------------------------------- goto move_motor ; will set the motor to step 0, ; and loop permanently from there ;--------------------------------------------- goto main ; safe loop, should never get here anyway. ;============================================================================== ;****************************************************************************** ; NEW INPUTS input change was detected ;****************************************************************************** ; ;------------------ new_inputs ; goto tag ;------------------ ;------------------------------------------------- ; when we enter here: ; * one or more PORTA inputs have just changed ; * inputs_last contains last PORTA inputs values ; * inputs contains new PORTA inputs values ;------------------------------------------------- ; must first detect which input pins changed. ; ---x---- RA4 * mode bit1 ( 00=200 step 01=400 step ; ----x--- RA3 * mode bit0 10=1200 step 11=3600 step ) ; -----x-- RA2 * power (Lini v2; now 0 = full power!) ; ------x- RA1 * direction ; -------x RA0 * step ; if step went hi, we move the step (step++ or step--) ; if step went low, ignore ; ignore change in direction pin ; ignore change in power pin ; ignore change in mode pins ; (all pins besides step are handled automatically in move_motor) ;------------------------------------------------- movf inputs,w ; xor to compare new inputs with last values xorwf inputs_last,f ; now inputs_last has the diff. btfss inputs_last,STEP ; test if step input changed goto ni_end ; ; step input changed! btfsc inputs,STEP ; test if change was lo-hi or hi-lo goto trans_hi ; lo-hi, so process a step! ; hi-lo, so ignore this transition bcf inputs_last,STEP ; record new state of step pin goto pwm ; fast exit back to pwm() ;------------------------------------------------- ; step input changed lo-hi! ; now must make a step forward or back, based ; on the state of the dir pin. ; here it gets complex as we have 4 operating modes, ; determined by the state of the 2 input pins RA4 and RA3; ; ---00--- 200 steps ; ---01--- 400 steps ; ---10--- 1200 steps ; ---11--- 3600 steps ; there are 4 separate code systems to handle stepping ; in the 4 modes; ;------------------------------------------------- trans_hi ; find which of the 4 modes we are in btfss inputs,4 ; test hi bit goto mode_lo ; mode_hi ; must be 1200 or 3600 btfss inputs,3 ; test lo bit goto mode_1200 ; ;------------------------------------------------- mode_3600 ; 3600 mode (72/1) ; each step is 1 btfss inputs,DIR ; test direction input goto m36_up ; m36_down decf step,f ; step-- btfss step,7 ; test for roll under <0 goto ni_end ; ok ; rolled under! movlw d'71' ; force to top step (72-1) movwf step ; goto ni_end ; m36_up incf step,f ; step++ movf step,w ; test for roll over >71 sublw d'71' ; sub to test skpwle ; clrf step ; wgt, rolled over so force to step 0 goto ni_end ; ;------------------------------------------------- mode_1200 ; 1200 mode (72/3) ; each step is mod 3 (0,3,6,9,12 - 66, 69 etc) btfss inputs,DIR ; test direction input goto m12_up ; m12_down movlw d'3' ; amount to subtract subwf step,f ; step-=3 btfss step,7 ; test for roll under <0 goto ni_end ; ok ; rolled under! movlw d'69' ; force to top step (72-3) movwf step ; goto ni_end ; m12_up movlw d'3' ; amount to add addwf step,f ; step+=3 ; movf step,w ; test for roll over >69 sublw d'69' ; sub to test skpwle ; clrf step ; wgt, rolled over so force to step 0 goto ni_end ; ;------------------------------------------------- mode_lo ; must be 200 or 400 btfss inputs,3 ; test lo bit goto mode_200 ; ;------------------------------------------------- mode_400 ; 400 mode (72/9) ; note! we do special half stepping here. ; there are ONLY 8 valid steps: ; 4, 13, 22, 31, 40, 49, 58, 67 ; these steps give 100,45 and 35,100 combos, good ; enough for now. (should average 100,41) btfss inputs,DIR ; test direction input goto m4_up ; m4_down movlw d'9' ; amount to subtract subwf step,f ; step-=9 btfss step,7 ; test for roll under <0 goto ni_end ; ok ; rolled under! movlw d'67' ; force to top (full) step movwf step ; goto ni_end ; m4_up movlw d'9' ; amount to add addwf step,f ; step+=9 ; movf step,w ; test for roll over sublw d'67' ; sub to test skpwgt ; goto ni_end ; wle, is ok movlw d'4' ; wgt, rolled over so force to bottom step 5 movwf step ; goto ni_end ; ;------------------------------------------------- mode_200 ; 200 mode (72/18) ; NOTE!! this has special needs as we can't use ; step 0, we need to stay on the "2 steps on" steps. ; there are ONLY 4 valid steps; 9, 27, 45, 63 btfss inputs,DIR ; test direction input goto m2_up ; m2_down movlw d'18' ; amount to subtract subwf step,f ; step-=18 btfss step,7 ; test for roll under <0 goto ni_end ; ok ; rolled under! movlw d'63' ; force to top (full) step (72-(18/2)) movwf step ; goto ni_end ; m2_up movlw d'18' ; amount to add addwf step,f ; step+=18 ; movf step,w ; test for roll over sublw d'63' ; sub to test skpwgt ; goto ni_end ; wle, is ok movlw d'9' ; wgt, rolled over so force to bottom step 9 movwf step ; goto ni_end ; ;------------------------------------------------- ni_end movf inputs,w ; save a copy of the inputs movwf inputs_last ; goto move_motor ; go and make it all happen ;------------------------------------------------------------------------------ ;****************************************************************************** ; PWM is the fast pwm loop ;****************************************************************************** ; NOTE!! we enter the code in the middle of the loop! ;------------------------------------------------- ; the 2 target currents were set in the move_motor code. ; what this function does is spend 2 time units at current2, ; and 1 time unit at current1. ; actual is 8 clocks at current2 ; and 4 clocks at current 1 ; total 12 cycles, so 333 kHz with 16MHz resonator. ; this gives an average pwm current of 2/3 the way between ; current2 and current1. ; the routine is kept short to keep pwm frequency high, so it ; is easy to smooth in hardware by the ramping caps. ; IMPORTANT! is timed by clock cycles, don't change this code! ; it also checks for any change in input pins here ; the 8/4 code seen here was supplied by Eric Bohlman (thanks!) ;------------------------------------------------- pwm_loop ; first output current1 to motor movf current1,w ; get currents and phase switching movwf PORTB ; send to motor! nop ; timing delay nop ; ; (4 cycles) ;------------------------- pwm ; main entry! ; better to enter at current2 for motor power. ; now output current2 movf current2,w ; movwf PORTB ; send to motor! nop ; safe wait 250nS ; now test input pins movf PORTA,w ; get pin values from port xorwf inputs_last,w ; xor to compare new inputs with last values skpnz goto pwm_loop ; z, inputs not changed, so keep looping ; (8 cycles) ;------------------------------------------------- ; nz, one or more input pins have changed! xorwf inputs_last,w ; restore xored value back to the orig inputs value movwf inputs ; goto new_inputs ; ;------------------------------------------------- ;------------------------------------------------------------------------------ ;****************************************************************************** ; SETUP sets port directions and interrupt stuff etc, ;****************************************************************************** ; NOTE!! is the only proper funtion, is done before other activity ;------------------ setup ; routine tag ;------------------ ;------------------------------------------------- ; Note! there are added bits for the 16F628! ; here we set up peripherals and port directions. ; this will need to be changed for different PICs. ;------------------------------------------------- ; OPTION setup movlw b'10000010' ; ; x------- ; 7, 0=enable, 1=disable, portb pullups ; -x------ ; 6, 1=/, int edge select bit ; --x----- ; 5, timer0 source, 0=internal clock, 1=ext pin. ; ---x---- ; 4, timer0 ext edge, 1=\ ; ----x--- ; 3, prescaler assign, 1=wdt, 0=timer0 ; -----x-- ; 2,1,0, timer0 prescaler rate select ; ------x- ; 000=2, 001=4, 010=8, 011=16, etc. ; -------x ; ; banksel OPTION_REG ; go proper reg bank movwf OPTION_REG ; load data into OPTION_REG banksel 0 ; ;------------------------------------------------- ; note! check for 16F628 (and A) and do extra setup for it. IFDEF __16F628 banksel VRCON ; do bank 1 stuff clrf VRCON ; disable Vref clrf PIE1 ; disable pi etc banksel 0 ; clrf T1CON ; disable timer1 clrf T2CON ; disable timer2 clrf CCP1CON ; disable CCP module movlw b'00000111' ; disable comparators movwf CMCON ; ENDIF IFDEF __16F628A banksel VRCON ; do bank 1 stuff clrf VRCON ; disable Vref clrf PIE1 ; disable pi etc banksel 0 ; clrf T1CON ; disable timer1 clrf T2CON ; disable timer2 clrf CCP1CON ; disable CCP module movlw b'00000111' ; disable comparators movwf CMCON ; ENDIF ;------------------------------------------------- ; PORTB pins direction setup ; 1=input, 0=output clrf PORTB ; ; movlw b'00000000' ; all 8 portb are outputs ; banksel TRISB ; go proper reg bank movwf TRISB ; send mask to portb banksel 0 ; ;------------------------------------------------- ; PORTA pins direction setup ; 1=input, 0=output clrf PORTA ; ; NOTE!! all 5 PORTA pins are inputs movlw b'00011111' ; ; ---x---- ; RA4 ; ----x--- ; RA3 ; -----x-- ; RA2 ; ------x- ; RA1 ; -------x ; RA0 banksel TRISA ; go proper reg bank movwf TRISA ; send mask to porta banksel 0 ; ;------------------------------------------------- movlw 0x00 ; set up PCLATH for all jump tables on page 0 movwf PCLATH ; (all tables are in move_motor) ;------------------------------------------------- ; CLEAR RAM! for lower bank movlw RAM_START ; first byte of ram movwf FSR ; load pointer ram_clear_loop clrf INDF ; clear the ram we pointed to incf FSR,f ; inc pointer to next ram byte movf FSR,w ; get copy of pointer to w sublw RAM_END ; test if PAST the last byte now skpweq ; goto ram_clear_loop ; ;------------------------------------------------- ; here we can set the user variables and output pins movlw 0x00 ; for step 0 of 0-71 movwf step ; loaded ready for jump table movf PORTA,w ; get initial value for inputs movwf inputs ; movwf inputs_last ; ;------------------------------------------------- ; set up INTCON register last movlw b'00000000' ; set the bit value ; x------- ; bit7 GIE global int enable, 1=enabled ; -x------ ; bit6 EE write complete enable, 1=en ; --x----- ; bit5 TMR0 overflow int enable, 1=en ; ---x---- ; bit4 RB0/INT enable, 1=en ; ----x--- ; bit3 RB port change int enable, 1=en ; -----x-- ; bit2 TMR0 int flag bit, 1=did overflow and get int ; ------x- ; bit1 RB0/INT flag bit, 1=did get int ; -------x ; bit0 RB port int flag bit, 1=did get int movwf INTCON ; put in INTCON register ;------------------------------------------------- return ; ;------------------------------------------------------------------------------ ;============================================================================== ; this code is only to display 1k of the memory usage chart ; in the absolute listing! ; page 0 256 byte block-------------------- ;org 0x40-2 ;nop ;org 0x80-1 ;nop ;org 0xC0-1 ;nop ;org 0x100-1 ;nop ; page 1 256 byte block-------------------- ;org 0x140-2 ;nop ;org 0x180-1 ;nop ;org 0x1C0-1 ;nop ;org 0x200-1 ;nop ; page 2 256 byte block-------------------- org 0x240-2 nop org 0x280-1 nop org 0x2C0-1 nop org 0x300-1 nop ; page 3 256 byte block-------------------- org 0x340-2 nop org 0x380-1 nop org 0x3C0-1 nop org 0x400-1 nop IFDEF __16F628A ; page 4 256 byte block-------------------- org 0x440-2 nop org 0x480-1 nop org 0x4C0-1 nop org 0x500-1 nop ; page 5 256 byte block-------------------- org 0x540-2 nop org 0x580-1 nop org 0x5C0-1 nop org 0x600-1 nop ; page 6 256 byte block-------------------- org 0x640-2 nop org 0x680-1 nop org 0x6C0-1 nop org 0x700-1 nop ; page 7 256 byte block-------------------- org 0x740-2 nop org 0x780-1 nop org 0x7C0-1 nop org 0x800-1 nop ENDIF ;------------------------------------------------------------------------- end ;------------------------------------------------------------------------- ;============================================================================== ;============================================================================== ;============================================================================== ;------------------------------------------------- ; NOTE!! example! below is the original (non-pwm) table for the ; 24x hardware 6th steps. ; this will be useful to code a minimum-rom microstepper ; if you don't need 3600 and can make do with 1200 steps. ; same system as the main code; ; ----xxxx are the phase sequencing ; xxxx---- are the current values ; (this code table has been used and tested!) ;------------------------------------------------- ; COMMENTED OUT! ;movlw b'11000101' ; 0, 100,0 A+ B+ 00=0 01=25 ;movlw b'11010101' ; 1, 100,25 A+ B+ 10=55 11=100 ;movlw b'11100101' ; 2, 100,55 A+ B+ ;movlw b'11110101' ; 3, 100,100 A+ B+ ;movlw b'10110101' ; 4, 55,100 A+ B+ ;movlw b'01110101' ; 5, 25,100 A+ B+ ;------------------------- ;movlw b'00111001' ; 6, 0,100 A- B+ ;movlw b'01111001' ; 7, 25,100 A- B+ ;movlw b'10111001' ; 8, 55,100 A- B+ ;movlw b'11111001' ; 9, 100,100 A- B+ ;movlw b'11101001' ; 10, 100,55 A- B+ ;movlw b'11011001' ; 11, 100,25 A- B+ ;------------------------- ;movlw b'11001010' ; 12, 100,0 A- B- ;movlw b'11011010' ; 13, 100,25 A- B- ;movlw b'11101010' ; 14, 100,55 A- B- ;movlw b'11111010' ; 15, 100,100 A- B- ;movlw b'10111010' ; 16, 55,100 A- B- ;movlw b'01111010' ; 17, 25,100 A- B- ;------------------------- ;movlw b'00110110' ; 18, 0,100 A+ B- ;movlw b'01110110' ; 19, 25,100 A+ B- ;movlw b'10110110' ; 20, 55,100 A+ B- ;movlw b'11110110' ; 21, 100,100 A+ B- ;movlw b'11100110' ; 22, 100,55 A+ B- ;movlw b'11010110' ; 23, 100,25 A+ B- EXAMPLE! full table example here, 0-71 steps showing every step... ;------------------------- 0 100,0 A+ B+ 1 100,8 (pwm tween) 2 100,17 (pwm tween) 3 100,25 A+ B+ 4 100,35 (pwm tween) 5 100,45 (pwm tween) 6 100,55 A+ B+ 7 100,70 (pwm tween) 8 100,85 (pwm tween) 9 100,100 A+ B+ (rest of table is same, tweens not shown) 10 11 12 55,100 A+ B+ 13 14 15 25,100 A+ B+ 16 17 ;------------------------- 18 0,100 A- B+ 19 20 21 25,100 A- B+ 22 23 24 55,100 A- B+ 25 26 27 100,100 A- B+ 28 29 30 100,55 A- B+ 31 32 33 100,25 A- B+ 34 35 ;------------------------- 36 100,0 A- B- 37 38 39 100,25 A- B- 40 41 42 100,55 A- B- 43 44 45 100,100 A- B- 46 47 48 55,100 A- B- 49 50 51 25,100 A- B- 52 53 ;------------------------- 54 0,100 A+ B- 55 56 57 25,100 A+ B- 58 59 60 55,100 A+ B- 61 62 63 100,100 A+ B- 64 65 66 100,55 A+ B- 67 68 69 100,25 A+ B- 70 71 ;-------------------------------------------------