⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stepi2c.asm

📁 pic得电机控制程序
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;File: stepi2c.asm
;Purpose: to drive stepper motor controlled by an i2c link to MPU
;Target processor  16c62/64/71/74
;Target speed 19.6608 Mhz
;Author M. Harrison
;Revisions:	7.4.97 added i2c slave interrupt routine that works
;					revised rate adjust section for Diff directions
;			13.5.97 revised i2c section as per i2c_int.asm to allow stop+abort condtions
;Jobs to do: re-write rate adjust on step complete bit using new switch
;			 Implement change of direction dependent on direction bit
;			 Implement turning phases off if dirn==reqd dirn && rate==0
;Last Updated: 13.5.97
;Comments: Program is not identical between versions used to drive RA on telescope
;for which the track rate & dirn is never turned off and for normal motor operation,
; which turns off when the required rate has been reached
;Assumptions:
;	default radix is decimal
;	assumes pulse counting takes less than 255 counts
;	all counters used in tracking rates are 8 bit
;	all increments between tracking rates must be less than the count value between them
;	and particularly must not allow an overflow/wraparound for the minimum/maximum values

;Program:
;Begin- Initialise ports, initial variables, port useage, clear interrupt flags
;and enable interrupts
;Jump to main body of program - a tight loop consisting of waiting for timeout flag on interval
;timer before calling stepping routine.

;Stepping routine handles step phase output to single motor. At
;completion of a full step the routine looks for adjustment of direction
;or rate status information

;i2c interrupt handler checks current direction and rate against required dirn and rate. Since the
;aim is to have smooth accelerations to achieve large stepping rates, cannot just jump from one
;rate/direction to another, must change slowly. 

;Timer interrupt handler
;Controls active timer on TMR0. LSB is set first and set to zero when timed out. After that
;MSB is decremented for overflow of TMR0 from 255 to zero. When both LSB and MSB are zero then
;the timer interrupt flag read by the main routine is set. In this way we have a 24-bit timer
;with prescaler granularity. This timer may be extended as far as required

;set processor type
TITLE "stepi2c.asm"
#define __16c62				;define constant for processor
#define RA
;#define DEC - alternative for off capability
list p=16c62,f=inhx8m, r=dec, c=80,t=off,x=on
include "p16cxx.inc"
include "p16cxxd.inc"

;File register assignment
#define I2CRAM H'20'
#define SLAVE_ADDR H'20'
include "i2c.inc"

;enable selected macros
#define SAFETY
#define DEF_TEMP
#define SAFE_ENTRY
#define SAFE_EXIT
#define RENGIEED
#define RENGIEE
#include "macros.inc"

;Equates- bit names,constants and base ram available address
;Bit names

;Interrupt pending flags
itimer_flag EQU D'6'
itimerovflw EQU D'4'

;Status bit names
reqd_dirn EQU D'7'
rateH EQU D'5'			;These two bits allow four rates:off,track,scan,slew
rateL EQU D'4'
dirn EQU D'3'

;Constants
constant uniphase=D'4'
constant biphase=D'2'
constant half_step=D'8'
constant stepmode=uniphase

;masks for stepper output port
constant mask= H'0F'

constant phases_per_step=D'10'
constant def_track_train_reps=D'4'
constant scan_train_reps=D'3'
constant slew_train_reps=D'2'
constant scan_train_reps_increment=D'1'
constant slew_train_reps_increment=D'1'

constant timeoutlowbyteval=H'50'
constant timeouthighbyteval=H'00'

;Create variables
cblock H'0c'	
	track_rate						;variable track base rate - updated	by i2c
	trn_rep_cnt                 	;counts number of trains complete
	trn_rep_rq						;holds number of trains req for phase in current step
	pulse_cnt						;counts position in fixed length pulse train 
	phase_cnt						;records phase number in step
	step_cnt						;records step in motor rotation
	step_status						;records stepper status/i2c status

	;timer timeout counters
	timeoutlb
	timeouthb

	;interrupt status buffer
	istat

endc

;Program starts here
;-------------------------------------------------------------------------
;Set up reset vector
	org H'00' 						;PIC dependent
	goto init

;Vector for interrupts. jump depending on interrupt flag
	org H'04'
	safe_entry

;Interrupt type handler switch
	btfsc INTCON,T0IF
	goto timer_dispatch
	btfsc PIR1,SSPIF
	goto i2c_int

;other alternative interrupts go here....
	safe_exit
	rengiee
    retfie

init:
;---------------------------------------------------
;Initialise timer,step states on io port and i2c external interrupt
;Keyboard interrupt can be removed if state is latched/cleared in external h/w
;Timer should always be internal
;Timer can be RTCC/WDT if not an interrupt. This prog deals only with an interrupt

;initialise variables
;Turn off interrupts, dont care about s & w 
	rengied

;Initialise movement variables
    movlw phases_per_step
    movwf pulse_cnt
    movwf phase_cnt

    movlw def_track_train_reps
    movwf trn_rep_cnt
    movwf trn_rep_rq
	movwf track_rate
	
    movlw D'1'
    movwf step_cnt
    
    movlw b'10011000'   			;direction- forward, rate- track,no keyboard pending
    movwf step_status
				
;initialise timer variables
    movlw timeoutlowbyteval
    movwf timeoutlb
    movlw timeouthighbyteval
    movwf timeouthb

ifdef __16c71
;Setup port analogue or digital if required p54 beginners guide
    clrf PORTA
	clrf PORTB
	bsf STATUS,RP0
	movlw b'00000011'
	movwf ADCON1
	movlw H'00'
	movwf TRISA						;4 pins out
	bcf STATUS,RP0
else
	clrf PORTA
	clrf PORTB
	bsf STATUS,RP0
	clrw
	movwf TRISA
	bcf STATUS,RP0
endif

;Setup initial motor output signals on porta lower 4 bits 
porta_init
	movf step_cnt,w
	call step_table
	movwf PORTA

i2c_init:
	clrf PORTC				;Set SDA & SCL low when not is tri-state
	clrw					;
	iorlw I2C7S				;7-bit adddress slave mode
	bsf W,CKP
	movwf SSPCON			;mode set
	
;Operations requiring bank 1 addresses
	bsf STATUS,RP0			;select bank 1
	movlw h'c0'
	movwf TRISB				;set PORTB to input on on  6& 7 only
	bsf PIE1,SSPIE			;Enable SSP interupt
	movlw SLAVE_ADDR		;slave address
	movwf SSPADD
	clrf TRISC
	bsf TRISC,3				;Set SCL high
	bsf TRISC,4				;set SDA high 
	bcf STATUS,RP0
	bcf PIR1,SSPIF			;clear SSP interrupt flag
	
;assign prescaler to timer and setup options: divisor- 4, interrupt on rising edges and TMR0 Q clock
	bsf STATUS,RP0
	movlw b'01000001'
	movwf OPTION_REG
	bcf STATUS,RP0

;clear stepper interrupt flags
    clrf iflag_stat    

;pre-load timer with timer lsb. NB-Timer counts up 
	movlw .255-timeoutlowbyteval
	movwf TMR0

;Enable interrupts for timer0 and i2c
	clrf INTCON
	bsf INTCON,T0IE		
	bsf INTCON,PEIE
	clrf PIR1

;enable global interrupts - start timer
    rengiee
    goto main 

main:
;---------------------------------------------------------
;wait on timer loop - main body of program!
	btfsc iflag_stat,T0IF
	swapf step_status,W
	xorlw .7
	btfsc STATUS,Z
	call step_on_timer			;Call stepper if (rate!=0) OR (dirn!=reqd)
								;This needs modofying to put stepper in
								;zero phase output pattern
	goto main

;-------------------------------------------------------
;i2c SLAVE interrupt handler - requires slave hardware
;Last revised 13.5.97
;Schema:
;Uses w,INDF,FSR,BUFFER,STATUS,SSPBUFF,SSPSTAT,CNTR
;Notes: BF is cleared by *reading* SSPBUF
;		SSPOV is cleared in software
;Get status information
;if (stop bit)
; 	On a transaction if CMD-RST-read then stop bit indicates end of read- no action rqd
;		if CMD-write then stop indicates end of write so handle data written (MASTER pov)
;	if(write) ie BF set
;		handle command
;		end
;	else(read) -- buffer count should be 0 on read+STOP - if not likely cause is MASTER abort
;		reset buffers due to read abort 
;		end	
;	end
;check direction of data/address
;if (write)
;	if (address)
;		read & discard data
;		reset buffer
;		return
;	else
;		read data to a buffer
;		increment buffer
;		return
;else (read)
;	if (address match) 
;		if(buffer !empty) 			;must be command data 
;			interpret command & setup output data buffer- - 4micro-secs max ?
;			output first byte
;		else (buffer empty)
;			output STATUS data - allow direct reading of <something>
;	else (!address match)
;		if(buffer !empty)
;			output byte
;		else (buffer empty)
;			error condition! - no more data to output
;int_reset:
;	clear interrupt flag
;	return

i2c_int:
i2c_entry:
	bsf STATUS,RP0			;Get status information
	movf SSPSTAT,W
	bcf STATUS,RP0
	btfss W,P				;test for stop found
	goto i2c_action			;not stop	
	movf CNTR,F
	btfsc STATUS,Z			;Test for buffer empty
	goto eo_i2c				;stop bit found & buffer empty - no action
							;This should only happen after wr/restart/read opns
	call cmd_wr_interpret	;buffer !empty - operate on write CMD & data
	goto eo_i2c				;This should only happen after direct write opn

i2c_action:					;There is a transaction to handle
	btfss W,BF				;BF set - data written to SLAVE
	goto i2c_read			;read found
	btfsc W,I2C_DATA		;test for address match
	goto i2c_write 			;data found

							;address match && write - initialise
	movf SSPBUF,W			;Clear BF flag
	bcf SSPCON,SSPOV		;clear overflow flag
	movlw BUFFER			
	movwf FSR
	movlw 0
	movwf CNTR
	goto eo_i2c

i2c_write:
	movf SSPBUF,W
	movwf INDF
	incf FSR,F
	incf CNTR,F
	goto eo_i2c

i2c_read:					;W Still contains status info
	btfsc W,I2C_DATA		;test for start/restart by detecting address match
	goto I2C_DATA
	movf CNTR,F				;Address Match: 
	btfsc STATUS,Z			;test for data in buffer for interpretation
	goto i2c_stat_out		;buffer empty
	call cmd_rd_interpret	;interpret buffer contents as cmd & fill with data to be read
	goto i2c_out

i2c_stat_out:				;status read outputs current <> value
	movf enc_lb,W
	movwf BUFFER
	movlw BUFFER
	movwf FSR
	movlw 1
	movwf CNTR
	goto i2c_out

i2c_data:
	movf CNTR,f				;Data read so data should be present
	btfsc STATUS,Z			;test for data in buffer ready for tx
	goto i2c_rd_error	
	goto i2c_out			;otherwise put data out 

i2c_rd_error:
	movlw BUFFER
	movwf FSR
	movlw H'FF'				;error code <for now>
	movwf BUFFER
	movlw 1
	movwf CNTR

i2c_out:					;output data pointed to by FSR to i2c
	movf INDF,W				;Buffer !empty: load SSPBUF and transmit
	movwf SSPBUF		
	bsf SSPCON,CKP
	decf FSR,F
	decf CNTR,F

eo_i2c:
	bcf SSPCON,WCOL
	bcf SSPCON,SSPOV
	bcf PIR1,SSPIF			;clear interrupt flag 
	retfie

timer:
;--------------------------------------------------------
;Timer interrupt handler - only get here when interrupt has gone off
;Function: timer for pic series using TMR0 channel
;Method:Load initial lsb, timeout. decrement msb.
;load lsb of 255 and on every timeout decrement msb until msb reaches zero.
;note: even during an interrupt, TMR0 continues to decrement => no need to
;reload with 255 on each lsb timeout.
;pragma:
;lsb has timed out, interrupt gone off, arrive here
;check to see if there are any more msb to decrement
;if there are do so, clear interrupt and return.
;if not, load restart values and check that lsb has not already been
;used up by code time
;if not load remaining time into TMR0, set stepper int and return
;if lsb already used up then check to see if there is a msb to decrement
timer_dispatch:
to_lsb:								;lsb timeout
	movf timeouthb,f			
	btfsc STATUS,Z					;check whether msb has reached zero
	goto restart					
	decf timeouthb,f				;if not decrement msb. TMR0 has carried on
									;meanwhile so doesn't require loading
	bcf INTCON, T0IF				;clear interrupt flag
	retfie                  		;end
;msb has reached zero
restart:
	movlw timeouthighbyteval		;no need to reset lsb since never changed in
									;program 
	movwf timeouthb
	movf TMR0,w
	addlw d'12'						;w->w+12 compensation factor for code time
	subwf timeoutlb,w      			;check whether already exceeded lsb time
	btfss STATUS,C			
	goto pto_lsb					;lsb time exceeded- check to see if there is
									;a msb to decrement
	sublw d'255'					;TMR0 counts upwards => 255-lsb = timeout count
	movwf TMR0						;place remaining time from lsb in TMR0
	bcf INTCON,T0IF					;clear interrupt flag
	bsf iflag_stat,T0IF				;flag stepper interrupt
	retfie                			;end with success

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -