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

📄 picservo.asm

📁 Code ASM for PIC16F628. Use for CNC/Servo Motor. With simulatio in Proteus (7.0)
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	CLRF	DataByte
ResetMsgLoop
	MOVF	DataByte, w
	CALL	GetResetMsg
	ANDLW	0ffh					; check for end of message
	BTFSC	STATUS, Z
	GOTO	EndResetLoop			; was 0, exit
	CALL	TransmitDataByte
	INCF	DataByte, f
	GOTO	ResetMsgLoop
EndResetLoop
	BSF		INTCON, GIE

	RETURN


;+=============================================================================
;| Command Parsing Routines.
;|
;| The following routines form the command parser and state machine to 
;| handle multi-byte commands.
;+=============================================================================


;+-----------------------------------------------------------------------------
;| SUBROUTINE: ParseCommand
;| 
;| Parse the given byte in W as a command. All incoming data is sent to this
;| routine to be interrupted. If the command is a single byte command it is
;| processed immediatly, if not the Parser waits for the next byte to execute
;| the command.
;+-----------------------------------------------------------------------------
ParseCommand
	; Determine if the Parser is waiting for a data byte, it is
	; store the incoming byte in the data field, if not store it
	; in the command field.
	BTFSS	Parser_WaitForData
	MOVWF	Parser_Command			; Store in command
	BTFSC	Parser_WaitForData
	MOVWF	Parser_Data				; Store in Data

	; Access the Command nibble and store it in the Parser_Temp variable
	; so we can access it and determine what the command is
	SWAPF	Parser_Command, w		; Place the upper nibble from the command
									; into the W register's lower nibble
	ANDLW	0Fh						; Mask out what was the channel select
	MOVWF	Parser_Temp				; Store in a Temp Variable.
	
	; Check for each command against the stored value and if we 
	; match one, goto the handler for that command, if we don't match
	; any command we need to discard the command.

	MOVLW	0h						; Check Reset Command
	SUBWF	Parser_Temp, w
	BTFSC	STATUS, Z				; Does it match?
	GOTO	ParseResetCmd			; Yes

	MOVLW	1h						; Check Set Servo Position
	SUBWF	Parser_Temp, w
	BTFSC	STATUS, Z				; Does it match?
	GOTO	ParseSetServoPosCmd		; Yes

	MOVLW	2h						; Check Set Servo Offset
	SUBWF	Parser_Temp, w
	BTFSC	STATUS, Z				; Does it match?
	GOTO	ParseSetServoOffsetCmd	; Yes

	MOVLW	3h						; Check Enable Servo Output
	SUBWF	Parser_Temp, w
	BTFSC	STATUS, Z				; Does it match?
	GOTO	ParseEnableServoCmd		; Yes

	MOVLW	4h						; Check Disable Servo Output
	SUBWF	Parser_Temp, w
	BTFSC	STATUS, Z				; Does it match?
	GOTO	ParseDisableServoCmd	; Yes

	; We have an invalid command, reset the parser and return
	BCF		Parser_WaitForData		; next byte is a command
	RETURN							; Return to the caller

;------------------------------------------------------------------------------
; Handle the Reset Command
ParseResetCmd
	; If the Parser_WaitForData value is not set, then we need to set it and
	; get the data byte before proceeding
	BTFSS	Parser_WaitForData
	GOTO	ParserWaitForDataByte

	; We have the data byte, now lets parse the command and execute it
	; If the data byte is NOT Zero it means that this is not a valid 
	; command and are are out of sync with the host so we make the 
	; current data byte a command and restart parsing
	MOVF	Parser_Data, f
	BTFSS	STATUS, Z				; is it zero?
	GOTO	ParseResetInvalid		; No.

	; the data byte is zero so all is well,
	CALL	ResetState

	BCF		Parser_WaitForData		; next byte is a command
	RETURN

ParseResetInvalid
	BCF		Parser_WaitForData		; next byte is a command
	MOVF	Parser_Data, w			; data byte is the next command
	GOTO	ParseCommand

;------------------------------------------------------------------------------
; Handle the Set Servo Position Command
ParseSetServoPosCmd
	; If the Parser_WaitForData value is not set, then we need to set it and
	; get the data byte before proceeding
	BTFSS	Parser_WaitForData
	GOTO	ParserWaitForDataByte

	; We have the data byte, now lets parse the command and execute it

	; Get the channel number in W
	MOVF	Parser_Command, w
	ANDLW	07h						; ensure we only have 0-7 as the channel

	; Conver the channel number into the address of the Mask data byte for the
	; given servo, then add the offset to the "Position value"
	CALL	GetAddressOfServoData
	ADDLW	2

	; set the indirect address register to the RAM address of the Servos
	; Position regiter, then save the data byte into that RAM location
	MOVWF	FSR

	MOVF	Parser_Data, w
	MOVWF	INDF

	BCF		Parser_WaitForData		; next byte is a command
	RETURN

;------------------------------------------------------------------------------
; Handle the Set Servo Offset Command
ParseSetServoOffsetCmd
	; If the Parser_WaitForData value is not set, then we need to set it and
	; get the data byte before proceeding
	BTFSS	Parser_WaitForData
	GOTO	ParserWaitForDataByte

	; We have the data byte, now lets parse the command and execute it

	; Get the channel number in W
	MOVF	Parser_Command, w
	ANDLW	07h						; ensure we only have 0-7 as the channel

	; Conver the channel number into the address of the Mask data byte for the
	; given servo, then add the offset to the "Offset value"
	CALL	GetAddressOfServoData
	ADDLW	1

	; set the indirect address register to the RAM address of the Servos
	; Position regiter, then save the data byte into that RAM location
	MOVWF	FSR

	MOVF	Parser_Data, w
	MOVWF	INDF

	BCF		Parser_WaitForData		; next byte is a command
	RETURN

;------------------------------------------------------------------------------
; Handle the Enable Servo Command
ParseEnableServoCmd
	; load the command into W and convert the channel into a bit mask
	MOVF	Parser_Command, w
	ANDLW	07h						; ensure we only have 0-7 as the channel
	CALL	ParserChannelToBitMask

	; Cheat and directly manipulate the Enables byte as it matches our
	; channel mask
	IORWF	Enables, f			; bit is set, any other are left unchanged
	
	BCF		Parser_WaitForData		; next byte is a command
	RETURN

;------------------------------------------------------------------------------
; Handle the Disable Servo Command
ParseDisableServoCmd
	; load the command into W and convert the channel into a bit mask
	MOVF	Parser_Command, w
	ANDLW	07h						; ensure we only have 0-7 as the channel
	CALL	ParserChannelToBitMask

	; Cheat and directly manipulate the Enables byte as it matches our
	; channel mask
	XORWF	Enables, f			; bit is cleared, any other are left unchanged
	
	BCF		Parser_WaitForData		; next byte is a command
	RETURN


;------------------------------------------------------------------------------
; Have the parser setup to get a data byte then return to the caller
ParserWaitForDataByte
	BSF		Parser_WaitForData		; next byte is a data byte
	RETURN


;+=============================================================================
;| RS232 Serial Interface Routines
;|
;| Out Serial interface is going to be  2400 baud, 8 data bits, no parity and
;| one stop bit. This means that a bit takes about 416us (1/2400). Therefore
;| we can use our DelayWByFour loop with a value of 103 ((416/4)-1) to delay
;| for bit samples. Note that this is not exactly accurate, but we are scanning 
;| quite offen for the beginning of the start bit an over the next 10 bits (8
;| data + start + stop) the timing isn't going to drift too much.
;|
;| We will also use Hardware flow control so the host doesn't send us anything 
;| when we're not in a position to receive it (ie, in the servo pulse loop).
;| The RS232 Request to Send line is routed to the PIC, but we won't use it
;| because it takes a little extra effort to set it to work properly on the PC.
;| and by default it is active all the time. We will be doing half duplex which
;| means that we can't send and receive at the same time so CTS is disabled
;| while we're transmitting.
;|
;| The RS232 Clear To Send line (active low) is also routed to the PIC, we will
;| enable is when we are able to receive data and disable it when we are not.
;|
;| The serial code and the interrupt routine to generate the servo pulses are
;| mutually exclusive as each will corrupt the timing of the other. Therefore
;| if we detect a start bit, we will disable the interrupts until we have 
;| received a byte.
;|
;| Receiving Data
;|
;| The Serial In line is normally high (1) but when a byte is to be sent the
;| start bit (a zero bit) brings the line low. This is our queue to start
;| reading bits. We will wait for half a bit read the input line and check that
;| the list is still low (0). If it isn't then it was a glitch so we will start
;| looking for the start bit again. If it is still low we will wait for a full
;| bit period and sample the input line again. This is the stored in bit 0 of 
;| the received data byte. We then continue sampling a bit intervals until we
;| have all 8 bits of data. Then we wait one more full bit period and sample the
;| stop bit. This should be high, it is isn't, we have a framing error and the
;| byte should be discarded. This normally happens if the sender's baud rate
;| is different from our own.
;|
;| Transmitting Data
;|
;| We will set the data output line low, wait for one bit period and the set
;| the output to the value of bit 0 in the output byte, We then wait for 
;| another bit period and send the next byte and contine until we're finished
;| all the 8 data bits, we then set the output high and wait for another bit 
;| period to send the stop bit.
;+=============================================================================

;+-----------------------------------------------------------------------------
;| SUBROUTINE: InitSerialPort
;| 
;| Initialise the serial port. Set all the lines to the apporpriate levels but
;| ensure that CTS is inactive (high).
;+-----------------------------------------------------------------------------
InitSerialPort
	; Set the output ports to the default states and disable CTS
	BSF		Serial_TX		; Output High by default
	BSF		Serial_CTS		; CTS is inactive so the host can't send us anything

	; Delay for at least one byte incase the host was sending data
	MOVLW	10
	MOVWF	Serial_LoopCount

InitSerialDelay
	MOVLW	Serial_BitDelay
	CALL	DelayWByFour

	DECFSZ	Serial_LoopCount, f		; subtract 1 from loop count
	BTFSS	STATUS, Z				; If zero, exit loop
	GOTO	InitSerialDelay

	RETURN


;+-----------------------------------------------------------------------------
;| SUBROUTINE: TransmitDataByte
;| 
;| Transmit the byte in the W register out the serial port. All interrupts 
;| need to be disabled prior to calling and reenabled after calling.
;+-----------------------------------------------------------------------------
TransmitDataByte
	MOVWF	Serial_CurrentByte		; store the byte to send

	; Check if the CTS line is active (0). if it is we need to disable it and
	; remember to restore it when we exit
	BTFSS	Serial_CTS				; if CTS is set (0), set the flag to restore it
	BSF		Serial_RestoreCTS
	BSF		Serial_CTS				; clear CTS

	; Send the Start bit
	BCF		Serial_TX
	MOVLW	Serial_BitDelay			; 1 bit delay
	CALL	DelayWByFour

	; loop through the byte sending each bit as we go
	MOVLW	8
	MOVWF	Serial_LoopCount

TxDataByteLoop
	BSF		STATUS, C
	RRF		Serial_CurrentByte, f	; get the current bit into the C flag
	BTFSS	STATUS, C
	BCF		Serial_TX				; If the bit = 0 set TX = 0
	BTFSC	STATUS, C
	BSF		Serial_TX				; If the bit = 1 set TX = 1

	MOVLW	Serial_BitDelay			; 1 bit delay
	CALL	DelayWByFour

	DECFSZ	Serial_LoopCount, f		; subtract 1 from loop count
	GOTO	TxDataByteLoop

	; Send the Stop bit
	BSF		Serial_TX
	MOVLW	Serial_BitDelay			; 1 bit delay
	CALL	DelayWByFour

	; restore CTS if needed
	BTFSC	Serial_RestoreCTS		; if flag is set, we must restore CTS
	BCF		Serial_CTS
	BCF		Serial_RestoreCTS		; Clear the flag
	RETURN


;+-----------------------------------------------------------------------------
;| SUBROUTINE: ReceiveDataByte
;| 
;| Receive a byte of data and return it in the W register. Set the flag
;| Serial_ReceiveValid if the byte was received correctly.
;| 
;| This must be called as soon as possible after detecting the falling edge
;| at the start of the start bit. All interrupts need to be disabled prior to 
;| calling and reenabled after calling.
;+-----------------------------------------------------------------------------
ReceiveDataByte
	; initialise the return valid flag and return value
	BCF		Serial_ReceiveValid		; Assume invalid
	MOVLW	0
	MOVWF	Serial_CurrentByte

	MOVLW	Serial_HalfBitDelay		; 1/2 bit delay
	CALL	DelayWByFour
	
	; Check that we are still in a start bit (Serial_RX low)
	BTFSC	Serial_RX
	RETURN							; not in start bit, return with fail
	
	; Receive the bits
	MOVLW	8
	MOVWF	Serial_LoopCount

RxDataByteLoop
	MOVLW	Serial_BitDelay			; 1 bit delay
	CALL	DelayWByFour

	; Sample the value
	BTFSS	Serial_RX
	BCF		STATUS, C				; If the bit = 0, set Carry = 0
	BTFSC	Serial_RX
	BSF		STATUS, C				; If the bit = 1, set Carry = 1

	RRF		Serial_CurrentByte, f	; Shift Carry into the output bit

	DECFSZ	Serial_LoopCount, f		; subtract 1 from loop count
	GOTO	RxDataByteLoop

	; check the stop bit is valid
	MOVLW	Serial_BitDelay			; 1 bit delay
	CALL	DelayWByFour

	BTFSC	Serial_RX
	BSF		Serial_ReceiveValid		; Stop bit != 1, invalid byte

	; load the byte to return
	MOVF	Serial_CurrentByte, w
	RETURN

; End of Code
	END

⌨️ 快捷键说明

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