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

📄 picservo.asm

📁 Code ASM for PIC16F628. Use for CNC/Servo Motor. With simulatio in Proteus (7.0)
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	LIST   P=PIC16F84, R=DEC
	#INCLUDE "p16f84.inc"

;------------------------------------------------------------------------------
; ASSEMBLE With MPASM. available for free from http://www.microchip.com
;------------------------------------------------------------------------------
;
; Servo Controler Version 1.1
;	28/10/2001
;	- Fixed Serial receive data problem where the PIC could
;	  miss a byte by assuming that the PC isn't in the middle of 
;	  sending a byte as it deactivates CTS.
;
; This program will control 8 servos connected to PORT B of the
; PIC microcontroler.
;
; The servos work by responding to a pulse presented to them 
; approximately every 20ms. The width of the pulse controls the 
; position of the servo.
;
; In general, a pulse width of around 1520us is used as a neutral
; (centre) position indication. The pulse width is then increased
; or decreased from there. Generally it the pulse range goes from 
; 1 to 2 ms for full deflection (90 degree movement of horn.
;
; So we need to arrange timing to control the width of the output
; pulse. To do this we will run the PIC at 4MHz, this means that
; our instructions are 1us long (clock/4). We will arrange a delay
; loop to wait for a given number of clock cycles.
;
; Because servo aren't that accurate, we will divide the 1 to 2ms
; pulse range into 256 values, which if we work on a loop of 
; four instruction cycles we can get a loop between 4 and 1024 ms
; (the loop is constructed to run at least once)
;
; We then need to offset this (roughly) 0 to 1ms pulse to ensure
; that the servo is centered. We will do this by having an "offset"
; adjustment for each servo. This offset will control the width of
; the initial part of the pulse from 4 to 1024ms. This means that
; we can centre the servo using the offset and then move the servo
; +/-45 degrees from there. With careful use of the offset and
; position, it should be possible to use almost the full travel of
; the servo. 
;
; We will also need to be able to turn on and off the output of
; each servo driver.
;
; PORT B is configured:
;
;	RB0		Servo Control 0
;	RB1		Servo Control 1
;	RB2		Servo Control 2
;	RB3		Servo Control 3
;	RB4		Servo Control 4
;	RB5		Servo Control 5
;	RB6		Servo Control 6
;	RB7		Servo Control 7
;
; PORT A is configured:
;
;	RA0		Serial TX (output)
;	RA1		Serial Request To Send (input)
;	RA2		Serial Clear To Send (output)
;	RA3		Serial RX (input)
;	RA4		LED Drive (0=on, 1=off. Used to indicate data transmission)
;
; Control Data
;
; To control the servos and outputs we need to send commands to the PIC.
; These commands will come from the serial port of a host computer running
; at 2400 baud, Hardware flow control (using CTS/RTS) with eight data bits,
; one stop bit and no parity. (2400 8-N-1).
;
; The commands take the format of one or two bytes sent sequentially 
; the first being the command to execute the second containing the data 
; for the command if needed.
;
; The command byte is split into two "nibbles". The upper 4 bits are used to
; determine the command, the lower 4 bits are used to select the output channel
;
;     +-----+-----+-----+-----+-----+-----+-----+-----+
; MSB |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  | LSB
;     | 128 |  64 |  32 |  16 |  8  |  4  |  2  |  1  | Decimal Value
;     +-----+-----+-----+-----+-----+-----+-----+-----+
;     | Command               | Channel Select        |   
;     +-----+-----+-----+-----+-----+-----+-----+-----+
;
; Note that the value (in hex or decimal) is added to the channel number
; to generate the command byte.
; 
; The Commands are:
;
;	Hex		Decimal		Meaning
;	---------------------------------------------------------------------------
;	0x00	0			Reset Device. All outputs off, servos disabled and 
;						offset and position values set to 128 (mid range).
;						Data byte MUST BE Zero. The Channel Value MUST BE Zero.
;						Special, SHOULD be followed by another zero byte, see
;						text below.
;
;	0x10	16			Set Servo Output "Positon Value". Data byte is the
;						value (between 0 and 255). The Channel Value must be
;						set in the lower 4 bits between 0 and 7.
;
;	0x20	32			Set Servo Output "Offset Value". Data byte is the 
;						value (between 0 and 255). The Channel Value must be
;						set in the lower 4 bits between 0 and 7.
;
;	0x30	48			Enable Servo Output. This starts the PIC generating
;						servo control pulses on the given channel. The Channel 
;						Value must be set in the lower 4 bits between 0 and 7.
;						No Data byte.
;
;	0x40	64			Disable Servo Output. This stops the PIC generating
;						servo control pulses on the given channel. The Channel 
;						Value must be set in the lower 4 bits between 0 and 7.
;						No Data byte.
;
;
; Parser State Control.
;
; Even with the hardware flow control where the PIC uses the CTS line to inhibit
; the host from sending more data when it can't receive it, there is a chance 
; the host and PIC will get out of step with commands and data bytes. This could
; occur because of either a bug in the host software or power being lost to the 
; PIC. This may result in the PIC attempting to treat a data byte as a command or
; a command as a data byte. Therefore some scheme is needed to ensure that the
; state of both can be quickly resynchronised.
;
; This will be done in two ways, the reset command and the rejection of unknown
; commands.
;
; If the PIC receives a byte it believes to be a command but is doesn't
; recognise the command, it will discard it and start looking for another
; command byte. This means that for more values of the data bytes it will
; ignore these as commands. Unfortunately not all however. It is therefore
; possible for the PIC to execute incorrent commands until it comes accross
; one that doesn't make sense. This means that it could skip a normal reset
; reset command if it was one byte long by reading it as a data byte.
;
; The reset command is two bytes long (a command and a data byte) both being
; zeros. However to ensure that the PIC is reset EVERY TIME the resent command
; it sent, it should be sent as THREE sequential zero bytes.
;
; The reason is that if the PIC is out of step and waiting for a data byte, it 
; will comsume the first zero as a data byte, take the next one as the command
; and the last one as the data byte. But what if it isn't out of sync? The
; parser in the PIC will know that a zero command requires a zero data byte
; to be valid, therefore it will receive the first zero as the command, the 
; second as the data and execute the reset. It will then get another zero byte
; which is the command for reset and be waiting for the corresponding zero data
; byte. However the host will start sending other valid command at this time
; and the parser will not receive a zero data byte. It then knows that it must
; discard the reset command and use the new byte as a command.
;

;+=============================================================================
;| Program Beginning.
;+=============================================================================

; Set the configuration, PUT Enabled, WDT Disabled, XT Oscillator, No Code Protection
;
	__CONFIG _XT_OSC & _PWRTE_ON & _WDT_OFF & _CP_OFF    


;+-----------------------------------------------------------------------------
;| Declare Variables 
;+-----------------------------------------------------------------------------

; We will have up to 4 servos connected, each one needs to store the
; number 4us loops for the postion and the number of loops for the
; offset. The values are ordered in memory one after the other to allow 
; the use of the indirect addressing to call a routine that will process 
; all servos. Because we are using the indirect addressing to access
; all the detail for the servo, we will need an extra value to specify
; the mask to use to set and clear the correct servo output.
;
; NOTE: These are assumed to start at the Ram_Base (0Ch) by the rest of
; the program so don't put any variables before these.
;
	
; Declare the start of RAM that we can use
RamBase				EQU		0x0C

	CBLOCK RamBase
	Servo0_Mask				; Mask for Servo 0 output
	Servo0_Offset			; loop count for Servo 0 offset
	Servo0_Position			; loop count for Servo 0 position

	Servo1_Mask				; Mask for Servo 1 output
	Servo1_Offset			; loop count for Servo 1 offset
	Servo1_Position			; loop count for Servo 1 position

	Servo2_Mask				; Mask for Servo 2 output
	Servo2_Offset			; loop count for Servo 2 offset
	Servo2_Position			; loop count for Servo 2 position

	Servo3_Mask				; Mask for Servo 3 output
	Servo3_Offset			; loop count for Servo 3 offset
	Servo3_Position			; loop count for Servo 3 position

	Servo4_Mask			; Mask for Servo 4 output
	Servo4_Offset			; loop count for Servo 4 offset
	Servo4_Position			; loop count for Servo 4 position

	Servo5_Mask			; Mask for Servo 5 output
	Servo5_Offset			; loop count for Servo 5 offset
	Servo5_Position			; loop count for Servo 5 position

	Servo6_Mask			; Mask for Servo 6 output
	Servo6_Offset			; loop count for Servo 6 offset
	Servo6_Position			; loop count for Servo 6 position

	Servo7_Mask			; Mask for Servo 7 output
	Servo7_Offset			; loop count for Servo 7 offset
	Servo7_Position			; loop count for Servo 7 position

	Int_W_Save				; Interrupt W register Store
	Int_STATUS_Save			; Interrupt STATUS register Store

	Flags					; eight flags, see the Flag_* macros
	Enables					; eight servo enable flags

	LED_Drive_Count			; used to count the number of 20ms blocks to keep
							; the LED on to indicate a data byte was received.

	CurrentServoMask		; the current servo mask

	DataByte				; somewhere to store a incoming data byte for processing

	Serial_CurrentByte		; the current byte being received or transmitted
	Serial_LoopCount		; the current bit loop counter

	Parser_Command			; the stored command
	Parser_Data				; the stored data byte
	Parser_Temp	
	ENDC

;+-----------------------------------------------------------------------------
;| Declare MACROs
;+-----------------------------------------------------------------------------

RTCC_19msValue		EQU		107		; leaves 148 'ticks' at 1:128 before the
									; RTCC register clocks over and generates 
									; an interrupt. ~19ms

RTCC_1msValue		EQU		247		; leaves 8 'ticks' at 1:128 before the
									; RTCC register clocks over and generates
									; an interrupt. ~1mS

LED_Drive_Time		EQU		10		; leave the LED on for approx 200ms
#DEFINE LED_Drive			PORTA,4

#DEFINE Serial_TX			PORTA,0
#DEFINE Serial_RX			PORTA,3
#DEFINE Serial_CTS			PORTA,2
#DEFINE Serial_RTS			PORTA,1

Serial_BitDelay		EQU		103
Serial_HalfBitDelay	EQU		52

; Flag Access macros
#DEFINE Serial_ReceiveValid	Flags,0	; set if the current byte received was valid

#DEFINE Parser_WaitForData	Flags,1	; If set the parser is waiting for a data byte
									; for the current command

#DEFINE Flag_ServoPulseSafe Flags,2	; Set once about 2 bit times have expired since the
									; CTS line was deactivated in preperation for doing
									; the servo pulses.

#DEFINE Flag_WaitingForCTS	Flags,3	; The CTS line was deactivated and we are waiting for
									; about 2 bit times to make sure we're not going to miss
									; a data byte.

#DEFINE Serial_RestoreCTS	Flags,4	; The Serial Transmit routine needs to disable CTS when
									; transmitting so it needs to remember to restore it

; servo enable outputs. NOTE These MUST be sequential starting at bit 0 as 
; it is assumed in the parser when enabling and disabling servos
#DEFINE Flag_Servo0_Active	Enables,0
#DEFINE Flag_Servo1_Active	Enables,1
#DEFINE Flag_Servo2_Active	Enables,2
#DEFINE Flag_Servo3_Active	Enables,3
#DEFINE Flag_Servo4_Active	Enables,4
#DEFINE Flag_Servo5_Active	Enables,5
#DEFINE Flag_Servo6_Active	Enables,6
#DEFINE Flag_Servo7_Active	Enables,7

;+-----------------------------------------------------------------------------
;| Beginning of Program 
;+-----------------------------------------------------------------------------
	ORG			0
	GOTO		Main				; Jump to the main entry point

;+-----------------------------------------------------------------------------
;| Beginning of Interrupt Routine 
;| Note that we jump to the interrupt routine so that we can place all our 
;| 'lookup' table at the beginning of the program memory to ensure that when
;| we do an ADD to the PCL register we aren't going to clock over the address
;| and thus stuffing up our instruction pointer
;+-----------------------------------------------------------------------------
	ORG			4
	GOTO		Interrupt

;+-----------------------------------------------------------------------------
;| SUBROUTINE:	ParserChannelToBitMask
;| 
;| Take the channel number as a binary number in the W register and change it
;| to a bit mask so that bit 0 is set if W=0, bit 1 is set of W=1 etc.
;| This can then be used to alter output ports etc.
;| 
;| Valid range for W is 0 to 7
;+-----------------------------------------------------------------------------
ParserChannelToBitMask
	ANDLW	07h						; Ensure that there is a max of 7.
	ADDWF	PCL, f					; Jump into the commands below to return
									; the correct value
	DT		0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80

;+-----------------------------------------------------------------------------
;| SUBROUTINE: GetPWROnMsg
;| 
;| return the character at offset in the W register for the Power On Message
;| returns 0 if at the end of the string
;+-----------------------------------------------------------------------------
GetPWROnMsg
	ADDWF	PCL, f
	DT		"PIC Servo Controller\r\n", 0

;+-----------------------------------------------------------------------------
;| SUBROUTINE: GetResetMsg
;| 
;| return the character at offset in the W register for the Power On Message
;| returns 0 if at the end of the string
;+-----------------------------------------------------------------------------
GetResetMsg
	ADDWF	PCL, f
	DT		"Reset\r\n", 0

;+-----------------------------------------------------------------------------
;| SUBROUTINE:	GetAddressOfServoData
;|
;| Returns the acutal memory address of the first data byte for the given servo
;| This is the Mask value, it is then followed by the offset and position.
;|
;| Call with W between 0 and 3. This routine will ensure the value is 
;| within that range.
;+-----------------------------------------------------------------------------
GetAddressOfServoData
	ANDLW	07h						; Ensure that there is a max of 7.
	ADDWF	PCL, f					; Jump into the commands below to return
									; the correct value
	DT		Servo0_Mask, Servo1_Mask, Servo2_Mask, Servo3_Mask, Servo4_Mask, Servo5_Mask, Servo6_Mask, Servo7_Mask



;+-----------------------------------------------------------------------------
;| Interrupt Routine.
;+-----------------------------------------------------------------------------
Interrupt
	; Save the state of the W and STATUS registers
	; Note this is the only way to do it properly
	MOVWF	Int_W_Save
	MOVF    STATUS, w
	MOVWF	Int_STATUS_Save

	; Process the interrupt. Note that the only interrupt generated is the 
	; timer overflow.
	;
	; when the timer expires from the 19ms delay, we have to disable the CTS line
	; so that the computer will not send us any more data, however we have to
	; continue listening for data for a little while so that we don't miss any if
	; it starts to send just as we deactivate the CTS line.
	;
	; Therefore we will wait for a further 2 bit times (about 1ms) before we signal
	; the main routine that it is safe to process the servo pulses.

	; Check if we have just expired the short 1ms delay
	BTFSS	Flag_WaitingForCTS
	GOTO	Int_LongDelayFinished

	; our short delay has just expired, we need to signal to the
	; main loop that it is now safe to proceed with the servo pulses
	; and disable any further timer interrupts (the main loop will
	; set them up again when it is ready)
	BCF		Flag_WaitingForCTS

⌨️ 快捷键说明

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