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

📄 motor.asm

📁 pic得电机控制程序
💻 ASM
字号:
; - Homepage: http://www.xraw.de                          -

	list	p=16f874
	include <p16f874.inc>


; --==*[ CONSTANTS ]*==--
#define		COMMAND_2	'B'
#define		COMMAND_3	'C'
#define		COMMAND_4	'D'


; --==*[ VARIABLES ]*==--
cmdNum		equ	0x20			; command number. 0xFF for invalid command
recByte		equ	0x21			; received byte

motorL		equ	0x22			; motor data - low byte
motorH		equ	0x23			; motor data - high byte

byteCnt		equ	0x24			; internal counter for byte counting during reception

tickL		equ	0x25			; ticks: low byte
tickH		equ	0x26			; ticks: high byte
result1L	equ	0x27			; result: this one is needed for storage of ticks
result1H	equ	0x28

winkelL		equ	0x29			; winkel: tick counter without overflow check etc.
winkelH		equ	0x30

quad		equ	0x31			; quadrature signal, for direction storage
oldb		equ	0x32			; old value of PORTB
newb		equ	0x33			; new value of PORTB

tmr0o0		equ	0x34			; tmr0 overflow counter 0
tmr0o1		equ	0x35			; tmr0 overflow counter 1

wtemp1		equ	0x60			; storage for the W register (rbif)
wtemp2		equ	0x61			; storage for the W register (ccp2if)
wtemp3		equ	0x62			; storage for the W register (rcif)
wtemp4		equ	0x63			; storage for the W register (usart error routines)


	org	0x00				; --==*[ RESET VECTOR ]*==--
	b	main

	org	0x04				; --==*[ INT VECTOR ]*==--
	b	int_handler

	org	0x05				; --==*[ MAIN PROGRAM ]*==--
main:
	; --==*[ VARIABLES - initialize ]*==--
	movlw	0xFF
	movwf	cmdNum
	clrf	motorL
	clrf	motorH
	clrf	tickL
	clrf	tickH
	clrf	result1L
	clrf	result1H
	clrf	winkelL
	clrf	winkelH
	clrf	quad
	clrf	oldb
	clrf	newb
	clrf	tmr0o0
	clrf	tmr0o1

	; --==*[ PORTS - setup port B ]*==--
	clrf	PORTB
	bsf	STATUS, RP0			; pin 4 and 5 as input (photo-interrupter signals)
	movlw	b'00110000'			; pin 1 has to be an output (direction signal)
	movwf	TRISB				; all other pins are outputs, too (default)
	bcf	STATUS, RP0

	; --==*[ PORTS - setup port C ]*==--
	clrf	PORTC
	bsf	STATUS, RP0
	movlw	b'11111011'			; pin 2 as output (pwm signal)
	movwf	TRISC				; pins 6 and 7 have to be inputs (default)
	bcf	STATUS, RP0			; all other pins are inputs, too  (default)

	; --==*[ CCP1 - setup PWM Module ]*==--
	bsf	STATUS, RP0
	movlw	d'249'				; pwm period (calculated with formula)
	movwf	PR2
	bcf	STATUS, RP0			; duty cycle = 0
	clrf	CCPR1L				; CCPR1L is upper 8 (bit: 9...2) bits of duty cycle
	movlw	b'00000101'			; enable timer2 (bit: 2) and set prescale of 1:4 (bit: 0-1)
	movwf	T2CON				; timer2 is important for pwm operation!
	movlw	b'00001111'			; select pwm mode for ccp1 module (bit: 0-3)
	movwf	CCP1CON				; and reset lower two bits of duty cycle (bit: 4-5)

	; --==*[ USART - setup ]*==--
	bsf	STATUS, RP0
	movlw	0x40				; configure baud generator register (calculated with formula)
	movwf	SPBRG				; with: 9600 baud, no parity, 8 data bits, no handshake
	movlw	b'00100100'			; enable trasmit (bit: 5) and high speed baud rate (bit: 2)
	movwf	TXSTA
	bcf	STATUS, RP0
	movlw	b'10010000'			; enable serial port (bit: 7) and continuous reception (bit: 4)
	movwf	RCSTA
	clrw					; w = 0
	movwf	RCREG				; reset uart receiver and fifo
	movwf	RCREG				; so we can avoid receive/framing/overrun errors at the beginning
	movwf	RCREG
	movwf	TXREG				; just in case:	 the txif flag is now valid (=1; avoids infinite loops in sendByte)

	; --==*[ TIMER 0 - setup ]*==--
	bsf	STATUS, RP0			; this is tricky; prescaler has to be assigned to the WDT,
						; in case you want to achieve 1:1 prescale
	bcf	OPTION_REG, PS0			; first, set prescaler to 1:2
	bcf	OPTION_REG, PS1
	bcf	OPTION_REG, PS2
	bsf	OPTION_REG, PSA			; then, assign prescaler to wdt; now we have a 1:1 prescale for timer0 :-)
	bcf	OPTION_REG, T0SE
	bcf	OPTION_REG, T0CS
	bcf	STATUS, RP0

	; --==*[ INTERRUPTS - setup ]*==--
	bsf	STATUS, RP0
	clrf	PIE1
	bsf	PIE1, RCIE			; enable "receive byte" interrupt
	bcf	STATUS, RP0
	clrf	INTCON				; reset all interrupt flags
	bsf	INTCON, RBIE			; enable "interrupt on change" interrupt
	bsf	INTCON, T0IE			; enable "timer0 overflow" interrupt
	bsf	INTCON, PEIE			; enable peripheral interrupts
	bsf	INTCON, GIE			; enable global interrupts

	; --==*[ MAIN LOOP ]*==--
loop:
	b		loop


; --==*[ sendByte - ROUTINE ]*==--
sendByte:					; send byte (which is stored in W)
sendByte_l0:					; wait until new data arrived in txreg
	btfss	PIR1, TXIF			; (indicated via transmit interrupt flag bit: txif)
	b		sendByte_l0
sendByte_l1:
	movwf	TXREG				; send new data
	return


; --==*[ INTERRUPT HANDLING ROUTINE ]*==--
int_handler:
	btfsc	RCSTA, OERR			; overflow error occured, handle it
	b	err_Overflow
	btfsc	RCSTA, FERR			; framing error occured, handle it
	b	err_Frame
	btfsc	PIR1, RCIF			; receive interrupt: rcif
	b	int_USART_receive
	btfsc	INTCON, RBIF			; pin interrupt: rbif
	b	int_RB_change
	btfsc	INTCON, T0IF			; tmr0 interrupt: t0if
	b	int_timer0_reset
	retfie

int_RB_change:
	incf	tickL, 1			; increment ticks (low byte)
	btfsc	STATUS, Z
	incf	tickH, 1			; increment ticks on overflow (high byte)
	incf	winkelL, 1			; same as tick, but will not be reset (eichungswert)
	btfsc	STATUS, Z
	incf	winkelH, 1
	movwf	wtemp1				; save W
	movfw	PORTB
	movwf	newb				; newb = PORTB
	movlw	b'00110000'			; and mask
	andwf	oldb, 1				; reset all bits except 4 and 5
	andwf	newb, 1				; reset all bits except 4 and 5
	clrf	quad				; reset quad value
	clrw					; oldb == 00 ?
	subwf	oldb, W
	bz	o00
	movlw	b'00010000'			; oldb == 01 ?
	subwf	oldb, W
	bz	o01
	movlw	b'00100000'			; oldb == 10 ?
	subwf	oldb, W
	bz	o10
	b	o11				; else, oldb == 11
o00:
	movlw	b'00010000'			; newb == 01 ?
	subwf	newb, W
	bnz	quit
	bsf	quad, 7				; left
	b	quit
o01:
	movlw	b'00110000'			; newb == 11 ?
	subwf	newb, W
	bnz	quit
	bsf	quad, 7				; left
	b	quit
o10:
	clrw					; newb == 00 ?
	subwf	newb, W
	bnz	quit
	bsf	quad, 7				; left
	b	quit
o11:
	movlw	b'00100000'			; newb == 10 ?
	subwf	newb, W
	bnz	quit
	bsf	quad, 7				; left
quit:
	movfw	PORTB
	movwf	oldb				; oldb = PORTB
	movfw	wtemp1				; restore W
	bcf	INTCON, RBIF			; reset interrupt (important)
	retfie


int_timer0_reset:
	btfsc	tmr0o0, 7			; wait 128 overflows
	goto	a1
	incf	tmr0o0, 1
	goto	a0
a1:
	btfsc	tmr0o1, 6			; wait 64 overflows
	goto	a4
	incf	tmr0o1, 1
	goto	a0
a4:
	btfsc	PORTB, 7			; a short hack, so we can measure the impulses
	goto	next1				; of timer0 with an oscillograph
	bsf	PORTB, 7			; signal is on bit 7 of portb
	goto	mainl
next1:
	bcf	PORTB, 7
mainl:
	movwf	wtemp2				; save W
	movfw	tickL				; store ticks in result1
	movwf	result1L
	movfw	tickH
	movwf	result1H

	movfw	quad				; and blend the direction bit on MSB of result1
	iorwf	result1H, 1

	clrf	tickH				; clear tick counter
	clrf	tickL
	clrf	tmr0o0				; clear timer0 overflow counters
	clrf	tmr0o1
	movfw	wtemp2				; restore W
a0:
	bcf	INTCON, T0IF			; reset interrupt (important)
	retfie


int_USART_receive:
	movwf	wtemp3				; save W
	movlw	COMMAND_3			; command3 active ?
	subwf	cmdNum, W
	bz	getData_command3		; yes, handle it
	movfw	RCREG				; store received byte
	clrf	RCREG				; it's a good idea to flush the buffer
	clrf	RCREG				; after receiving a byte, so it's
	clrf	RCREG				; forced that we have a new byte in the buffer in the next step
	movwf	recByte
	movlw	COMMAND_2			; -execute command2 ?
	subwf	recByte, W
	bz	command2			;  yes, do it
	movlw	COMMAND_3			; -execute command3 ?
	subwf	recByte, W
	bz	command3			;  yes, do it
	movlw	COMMAND_4			; -execute command4 ?
	subwf	recByte, W
	bz	command4			;  yes, do it

commandUnknown:					; else, received byte is unknown
	bsf	PORTB, 0			; show error on leds
	movfw	wtemp3				; restore W
	retfie

; --==*[ COMMAND EXEC - transmit motor data in debug mode ]*==--
command2:
	movfw	result1H
	call	sendByte
	movfw	result1L
	call	sendByte
	movfw	winkelH
	call	sendByte
	movfw	winkelL
	call	sendByte
	movfw	wtemp3				; restore W
	retfie

; --==*[ COMMAND INIT - setup for receive motor data (part 1/2) ]*==--
command3:					; command3
	movlw	COMMAND_3
	movwf	cmdNum				; cmdNum contains now the current command value
	movlw	.2
	movwf	byteCnt				; we want exactly 2 bytes from the pc
	movfw	wtemp3				; restore W
	retfie

; --==*[ COMMAND EXEC - receive motor data (part 2/2) ]*==--
getData_command3:
	decf	byteCnt, 1			; handle byte counter
	bz	c3_b2				; if byte counter is 0 then it is the 2nd byte
	movfw	RCREG				; else, 1st byte receive
	movwf	motorL				; store in motorL
	b	outhere				; and exit
c3_b2:
	movfw	RCREG				; 2nd byte receive
	movwf	motorH				; store in motorH
	movlw	0xFF				; reset cmdNum to undefined value (0xFF)
	movwf	cmdNum
						; reconfigure PWM
	movfw	motorH
	movwf	CCPR1L				; store high byte (8; bits 9 - 2)
	bcf	CCP1CON, CCP1Y
	btfsc	motorL, 0			; store low byte (2; bits 0)
	bsf	CCP1CON, CCP1Y
	bcf	CCP1CON, CCP1X
	btfsc	motorL, 1			; store low byte (2; bits 1)
	bsf	CCP1CON, CCP1X
	btfss	motorL, 2			; motorL<2> bit is significant for motor direction
	b	turn_left
	bsf	PORTB, 1			; turn motor right
	b	outhere
turn_left:
	bcf	PORTB, 1			; turn motor left
outhere:
	movfw	wtemp3				; restore W
	retfie


; --==*[ COMMAND EXEC - transmit motor data ]*==--
command4:
	movfw	result1H			; transmit high byte
	call	sendByte
	movfw	result1L			; transmit low byte
	call	sendByte
	movfw	wtemp3				; restore W
	retfie


; --==*[ ERROR HANDLING - for the serial communication ]*==--
err_Overflow:					; handle overflow error
	movwf	wtemp4				; save W
	bsf	PORTB, 7			; show error on leds (10)
	bcf	PORTB, 6
	bcf	RCSTA, CREN			; disable continuous reception
	movf	RCREG, W			; flush receive fifo buffer (3 bytes deep)
	movf	RCREG, W
	movf	RCREG, W
	bsf	RCSTA, CREN			; reenable continuous reception
	movfw	wtemp4				; restore W
	retfie
err_Frame:					; handle frame error
	movwf	wtemp4				; save W
	bcf	PORTB, 7			; show error on leds (01)
	bsf	PORTB, 6
	movf	RCREG, W			; flush receive fifo buffer (3 bytes deep)
	movf	RCREG, W
	movf	RCREG, W
	movfw	wtemp4				; restore W
	retfie


	end

⌨️ 快捷键说明

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