📄 stepi2c.asm
字号:
pto_lsb: ;premature lsb timeout
movwf scratch ;save timeout time
movf timeouthb,f
btfsc STATUS,Z ;look for msb to decrement
goto too_fast ;if there is no msb to decrement then interval is too short for code!
movf scratch,w ;restore timeout time
movwf TMR0
decf timeouthb,f
bcf INTCON,T0IF
bsf iflag_stat,T0IF
retfie ;end with success
too_fast:
sleep ;in lieu of something useful
retfie
step:
;-----------------------------------------------------------
;Stepping proc occurs every time timer interrupt flag is set
;Mode of operation:
;A step of the motor is broken doWn into a number of phases. The number
;of phases is a measure of the motor current control resolution. Each phase is
;repeated for a length of time governed by the train repetition count.
;A train is a fixed-length series of pulses off and on output to the motor.
;The relative number of pulses off and on in a train govern
;the average output current for that phase to the motor.
;After the train has repeated a number of times, governed by the speed
;required - fast has a loW repeat count, sloW high repeat count- the
;motor current changes to the next phase. After all the phases in a step
;have been completed the next step pattern is loaded and all counts are
;reset.
;The number of train repeat counts is governed by the i2c input to
;alloW control of the motor speed. This input is checked at the end of
;every step and the required number for that step is stored for use.
step_on_timer:
set_phase:
ifdef uniphase
;if( pulse_cnt lt _phase_count)
; current step is high
movf pulse_cnt,W
bsf STATUS,C ;C is not affected by a-b=0 so set prior to test
subWf phase_cnt,W ;W-> phase_cnt- pulse_cnt
btfsc STATUS,C ;if pulse <= phase carry is set - use current step mask
goto mask_no_change ;step bit is independent of direction if mask bit is on
btfss step_status, dirn
goto reverse
forwards:
bsf STATUS,C ;preset C for test of >=
movf step_cnt,W ;get number of current step output format
sublW stepmode-1 ;check for Wraparound of phase number
btfsc STATUS,C
goto forWard_load ;no carry so no Wrap-around yet
movlW D'1' ;Wrapped around to first phase
goto get_mask
forward_load:
incf step_cnt,W
goto get_mask
reverse:
decf step_cnt,W
btfss STATUS,Z ;at zero phase?
goto get_mask ;yes
movlW stepmode ;set neW
goto get_mask
mask_no_change:
movf step_cnt,W ;get current phase mask from step table
get_mask:
call step_table ;value returned in W
dirn_end:
movWf PORTA ;output on PORTA
endif
;max number of pulses in a pulse train is also equal to phases_per_step
;if ( pulse_cnt EQ 0) then
; pulse_cnt= phases_per_step
; trn_rp_cnt--
decfsz pulse_cnt,F
goto no_rollover ;if no rollover at all can go to the end
movlw phases_per_step ;have end of train rep loop
movwf pulse_cnt
; train_reps_per_phase is the step rate determinant - controlling how many times
;the same pwm pulse train is repeated before the next phase starts
;if ( trn_rp_cnt EQ 0) then
; trn_rp_cnt=train_reps_req
; phase_cnt--
decfsz trn_rp_cnt,F
goto no_rollover
movf trn_reps_rq,W ;have end of phase loop so reset value
movwf trn_rp_cnt
;phase_count measures Which phase in a step We are up to
;if( phase_cnt EQ 0)
; phase_cnt= phases_per_step
decfsz phase_cnt,F
goto no_rollover
movlw phases_per_step ;have step transition
movwf phase_cnt ;reset phase couner
;Check direction.
btfsc Actual_dirn,dirn ;If direction = forward
goto step_forwards
;decrement step_counter and watch for rollover at 1-> stepmode
step_reverse:
decf step_cnt,F ;decrement step count for reverse motion
btfss STATUS,Z ;check for zero, min phase is 1
goto rate_adjust ;not zero yet
movlw stepmode ;zero found so reset count to stepmode
movwf step_cnt
goto rate_adjust
;increment step counter and Watch for rollover at stepmode->1
step_forwards:
movlw stepmode
subwf step_cnt,W ;W-> step_cnt-stepmode
btfsc STATUS,C ;carry is set if no rollover
goto forward_roll ;rollover found
incf step_cnt,F ;no rollover so increment count
goto rate_adjust
forward_roll
movlw D'1'
movwf step_cnt
;If there is a change required handle it. Could insert change detection
into idle loop and use a flag to indicate
check_rate:
ifndef dbg _excludekeybd
;compare required direction and rate with actual
;if no difference then finish
;else call adjust_rate
endif
no_rollover:
bcf iflag_stat,T0IF ;re-enable timer interrupt
return
;------------------------------------------------------
;stepper phase jump table
;phase number supplied in W on entry- minimum value is 1, max 'stepmode'
;phase format returned in W on exit
if stepmode==uniphase
step_table:
andwf H'07' ;safety mask
addwf PCL,f ;PCL-> PCL + W
nop
retlW b'00000101'
retlW b'00001001'
retlW b'00001010'
retlW b'00000110'
retlW b'00000101'
retlW b'00001001'
retlW b'00001010'
endif
if stepmode == biphase
;etc
endif
rate_adjust:
;=---------------------------------------------------
;Procedure for smooth adjustment of rate between steps
;To avoid cogging and jerking, the rate of motion, including direction changes,
;is ramped. Because of this we need to look for changes in rate and direction and on/off.
;The direction may only be changed when the stepper is moving at the slowest rate and
;so this must be achieved by ramping down the rate prior to reversing the direction
;and then ramping up the rate to that required in that direction.
;Similarly when the stepper is turned off, the stepping motion must not come to an
;abrupt stop but achieve the slowest rate (track) prior to being turned off
;-----------------------------------------------------
;Insert 'off' test here
dirn_test:
swapf step_status,W ;swap nibbles of step_status byte into W
xorwf step_status,W ;xor to see if reqd and actual directions agree
andlw b'11000000' ;mask off other bits
btfsc W, dirn ;clear means reqd and set dirns are different
goto Same ;c->1 -> same
goto Diff ;c->0 -> different
;DIFFERING DIRECTIONS: Diff
;1, If rate is higher than track then reduce to track
;2, if rate is lower than track then set to track
;3, If rate = track then change direction
Diff:
movf trn_reps_rq,W ;test for current == track
sublw track_train_reps ;W->current-track
btfsc STATUS,Z
goto D_track ;rates are equal
btfsc STATUS,C
goto D_scan ;current is faster than track
D_track_high:
movlw track_train_reps
movwf trn_reps_rq ;set value to track
goto Xdirn
D_track:
movlw track_train_reps ;set initial track value
movWf trn_reps_rq
Xdirn:
clrw
bsf W,dirn
xorwf step_status,F ;toggle dirn flag
goto Dend_adjust
D_scan:
bsf STATUS,C
movf trn_reps_rq,W ;test for current < scan
sublw track_train_reps ;W->current-scan
btfss STATUS,C
goto D_slew ;current < scan
movlw scan_train_reps_increment
addwf trn_reps_rq,F
goto Dend_adjust ;end
D_slew:
movlw slew_train_reps_increment
addwf trn_reps_rq,F
Dend_adjust:
swapf step_status,W
xorlw .3
btfss STAUS,Z
retlw .0
;Dirn_changed
;Anything more required doing? - dirn only changes at step completion
retlw D'1'
;SAME DIRECTIONS: Same
;When going the same dirn, need to do different things for different keyboard presses
Same:
swapf step_status,W ;jump table based on rate input
andlW b'00000011'
addWf PCL,F
ifdefined RA
goto S_track ;track set
else
goto S_stop ;set off -error condition
endif
goto S_track ;track set
goto S_scan ;scan set
goto S_sleW ;sleW set
S_track:
movlw track_train_reps ;test for current == track
subwf trn_reps_rq,W ;W-> current - track
btfsc STATUS,Z
goto S_track_end_adjust ;no changes required - end
S_track_high:
btfss STATUS,C ;test for current > track
goto S_track_slew
movlw track_train_reps ;set current to track
movWf trn_reps_rq
goto S_track_end_adjust ;end
S_track_slew:
movlw scan_train_reps ;test for count < scan
subwf trn_reps_rq,W ;W->current - scan
btfsc STATUS,C ;C=1, current > scan
goto S_track_scan
movlw slew_train_reps_increment
addwf trn_reps_rq,f
goto S_track_end_adjust ;end
S_track_scan:
movlw scan_train_reps_increment
addwf trn_reps_rq,F
goto S_track_end_adjust ;end
S_track_end_adjust:
retlw D'1'
S_scan: ;section
movlw scan_train_reps ;test if count > scan
subwf trn_reps_rq,W ;W->count - scan
btfss STATUS,Z ;if z->1 count=scan
goto S_scan_end_adjust
btfss STATUS,C ;c=1 if count>scan
goto S_scan_low
S_scan_high:
movlw scan_train_reps_increment
addwf trn_reps_rq,f
goto S_scan_end_adjust
S_scan_low:
movlw slew_train_reps_increment
addWf trn_reps_rq,F
goto S_scan_end_adjust
S_scan_end_adjust:
retlw .1
S_slew
movlw slew_train_reps ;test if count=sleW
subwf trn_reps_rq,W ;W->count-sleW
btfsc STATUS,Z ;if z->1 count=sleW
goto S_sleW_end_adjust ;end
btfsc STATUS,C
goto S_slew_scan ;count > sleW
movlw slew_train_reps_increment
addwf trn_reps_rq,F
goto S_slew_end_adjust
S_slew_scan:
movlw scan_train_reps ;test if count=scan
subwf trn_reps_rq,W ;W->count-scan
btfsc STATUS,C
goto S_slew_high ;count > scan
S_sleW_low:
movlw scan_train_reps_increment ;c->0: decrease count by scan increment
subwf trn_reps_rq,F
goto S_slew_end_adjust
S_slew_high:
movlw slew_train_reps_increment ;count < scan :decrease by sleW increment
addwf trn_reps_rq,F
goto S_slew_end_adjust
S_slew_end_adjust:
retlw D'1'
cmd_wr_interpret:
;------------------------------------------------
;command interpreter and dispatch functions for data update
;uses W to pass error numbers - 0 is ok
;Uses FSR, CNTR, W & Z
movf BUFFER,W
xorlw .00
btfsc STATUS,Z
goto cmd_wr_track
; xorlw .01^.00
; btfsc STATUS,Z
; goto cmd_set_move
retlw .1
cmd_rd_interpret:
;------------------------------------------------
;command interpreter and dispatch functions for data request
;uses W to pass error numbers - 0 is ok
;Uses FSR, CNTR, W & Z to setup output data buffer
movf BUFFER,W
xorlw .00
btfsc STATUS,Z
goto cmd_rd_track
; xorlw .01^.00
; btfsc STATUS,Z
; goto cmd_set_move
movlw BUFFER
movwf FSR
movlw .0
movwf CNTR
retlw .1
cmd_rd_move:
movf train_rep_req,W
movwf BUFFER
movlw .1
movwf CNTR
retlw .0
cmd_wr_track
movf BUFFER,W
movwf track_rate
clrf CNTR
retlw 0
;command to control type of movement required of stepper
cmd_wr_move:
movf BUFFER,W
cmd0:
xorlw .00
btfss STATUS,Z
goto cmd1
movf track_rate,W
movwf train_rep_req
bcf step_status,rateH
bsf step_status,rateL
bsf step_status,reqd_dirn
retlw .0
cmd1:
xorlw .01^.00
btfss STATUS,Z
goto cmd2
bsf step_status,rateH
bcf step_status,rateL
bcf step_status,reqd_dirn
retlw .0
cmd2:
xorlw .02^.01
btfss STATUS,Z
goto cmd3
bsf step_status,rateH
bcf step_status,rateL
bsf step_status,reqd_dirn
retlw .0
cmd3:
xorlw .03^.02
btfss STATUS,Z
goto cmd4
bsf step_status,rateH
bsf step_status,rateL
bcf step_status,reqd_dirn
retlw .0
cmd4:
xorlw .04^.03
btfss STATUS,Z
retlw .1
bsf step_status,rateH
bsf step_status,rateL
bsf step_status,reqd_dirn
retlw .0
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -