ME 218C Final Project
Introduction Mechanical
Hardware
Electrical
Hardware
Software Gems of
Wisdom
Pictures/
Video
Links

SMst.asm


; Final Project - Terman Pond Flotilla
; ME218B
; By Allen Cheung
; -----------------------------------------------------------------
;
;
; Pins used:
;    RB<7, 5> as transmit/receive lines for EUSART to Xbee radio
;    RC<7> RB<4, 6> for SPI to slaves
;    RC<0:2> as SS lines to slaves
;    RA<0> for ibutton
;    RA<1> for debug LED
;    RC<5> as PWM for pump
;
	list 	P=PIC16F690
	#include 	"p16F690.inc"
	__config 	(_CP_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO)


;
;	Variable Definitions
;   ---------------------------------------------------------------
	#include	vars.h


;   Beginning of Program
;   --------------------------------------------------------------------
	org	0
	goto	Main
	org	5
	goto	Interrupt

;
;	Tables
;   --------------------------------------------------------------------
;	Lookup table for bit pattern to write to Port C output
END_TBL:
; 	make sure address is less than 0xff

	#include	xbee_comm.h
	#include	shipinits.h
	#include	ibutton.h
	#include	synch.h
	#include	wait.h
;
;	Initialize routine.  
;   --------------------------------------------------------------------
Initialize:
;	Setup Clock
	CALL	Clock_Init
;	Setup EUSART
	CALL	EUSART_Init
;	Setup PWM
	CALL	PWM_Init
;	Setup SPI
	CALL	SPI_Init
;	Setup LEDs
	CALL	LED_Init
;	Enable Interrupts
	banksel	INTCON
	BSF	INTCON, GIE
	BSF	INTCON, PEIE
	RETURN

InitializeGameState:
	banksel	PORTA
	CLRF	COM_frameid
	MOVLW	0x01
	MOVWF	COM_options
	CLRF	COM_rxFlag
	CLRF	COM_rxIndex
	CLRF	StateMachine
	BSF	StateMachine, Waiting
;	Setup ping data to respond
	MOVLW	0x01
	MOVWF	PingData1
	CLRF	PingData2
	
	RETURN

;   ****************************************************************************
;   ****************************************************************************
;	Main Loop
;   --------------------------------------------------------------------
;   Continuously loops and handles the program
;       Looks for a button press, looks for a received message on EUSART
;       If slave select raised transmits message or ack
;   ****************************************************************************
;   ****************************************************************************
Main:
	CALL	Initialize
	CALL	InitializeGameState
	CALL	ToggleLED

	CALL	Waiting_for_iButton
;	Setup ping data
	MOVLW	0x02
	MOVWF	PingData1

	CALL	ToggleLED
	CALL	Waiting_for_Sync
	CALL	ToggleLED
	CALL	SendFlag

;;	SIMULATION
;	MOVLW	0xBC
;	MOVWF	HelmAddrH
;	MOVLW	0x0A
;	MOVWF	HelmAddrL
;   Main Loop, we're going to enter a state machine, depending on the state of
;     certain variables, it will dictate what we do

Play_Game:


	banksel	PORTA
;	Are we gonna hard reset?
	BTFSC	StateMachine, Waiting
	GOTO	Main
;	Have we received an API packet?
	CALL	APIRx
	GOTO	Play_Game


CheckTimer0Flag:
	banksel	PORTA
	BTFSS	Timer0Flag, 0
	RETURN
;	Flag is set, then clear it
	BCF	Timer0Flag, 0
	DECFSZ	TimeOutTimer
	RETURN
	GOTO	ShutOffActuation


ToggleLED:
	banksel	PORTC
	BTFSS	PORTC, 4
	GOTO	$+3
	BCF	PORTC, 4
	RETURN
	BSF	PORTC, 4
	RETURN


APIRx:
	banksel	PORTA
;	Check whether an API packet is received
	BTFSS	COM_rxFlag, COM_rxDone
	RETURN
	BCF	COM_rxFlag, COM_rxDone
;	Toggle LED
	CALL	ToggleLED
;	A packet has been received, what is it?
	MOVLW	COM_nav
	SUBWF	COM_rxData1, W
	BTFSC	STATUS, Z
;	It's navigation
	GOTO	API_Navigation
	MOVLW	COM_adm
	SUBWF	COM_rxData1, W
	BTFSC	STATUS, Z
;	It's admiral
	GOTO	API_Admiral
;	It's nothing we're interested in, return
	RETURN

;   We've received a navigation command from the helm.  Interpret the data
;   to water speed, speed, and direction, then apply those parameters
API_Navigation:
;	First, is it from our helm?
	CALL	CheckHelmAddr
	ADDLW	0x00
	BTFSS	STATUS, Z
	RETURN
;	Ok, it is from our helm
;	Reset TimeOutTimer
	MOVLW	TimeOutTimerMax
	MOVWF	TimeOutTimer
;	Direction
	MOVLW	0xF0
	ANDWF	COM_rxData2, W
	MOVWF	ShipDirection
;	Speed
	RLF	COM_rxData2, F
	RLF	COM_rxData2, F
	RLF	COM_rxData2, F
	RLF	COM_rxData2, F
	MOVLW	0xF0
	ANDWF	COM_rxData2, W
	MOVWF	ShipSpeed
;	Divide speed by two
;	RRF	ShipSpeed, F
;	MOVLW	0x7F
;	ANDWF	ShipSpeed, F
;	WaterSpeed
	RLF	COM_rxData3, F
	RLF	COM_rxData3, F
	RLF	COM_rxData3, F
	RLF	COM_rxData3, F
	MOVLW	0xF0
	ANDWF	COM_rxData3, W
	MOVWF	ShipWaterSpd
;	All the parameters are copied over, send them to slaves
	CALL	SetParameters
	CALL	ToggleLED
	RETURN

SetParameters:
	banksel	PORTA
;	Send Rudder direction information
	CALL	SendDirectionInfo
;	Move motor speed to registers, differential
	MOVF	ShipSpeed, W
	MOVWF	LeftMotor
	MOVWF	RightMotor

	MOVLW	0x60
	SUBWF	ShipSpeed, W
	BTFSC	STATUS, Z
	GOTO	DoneTurn
	MOVLW	0x70
	SUBWF	ShipSpeed, W
	BTFSC	STATUS, Z
	GOTO	DoneTurn
	MOVLW	0x80
	SUBWF	ShipSpeed, W
	BTFSC	STATUS, Z
	GOTO	DoneTurn
	MOVLW	0x90
	SUBWF	ShipSpeed, W
	BTFSC	STATUS, Z
	GOTO	DoneTurn
;	Turning right or left?
	BTFSS	ShipDirection, 7
	GOTO	LeftTurn
RightTurn:	MOVLW	0x08
	SUBWF	ShipDirection, F
	RRF	ShipDirection, F	; Divide by two
	BCF	ShipDirection, 7
	MOVF	ShipDirection, W
	ADDWF	LeftMotor, F
	MOVLW	0xF0
	BTFSC	STATUS, C
	MOVWF	LeftMotor
	MOVF	ShipDirection, W
	SUBWF	RightMotor, F
	BTFSS	STATUS, C
	CLRF	RightMotor
	GOTO	DoneTurn
LeftTurn:	COMF	ShipDirection, F
	MOVLW	0x08
	SUBWF	ShipDirection, F
	RRF	ShipDirection, F	; Divide by two
	BCF	ShipDirection, 7
	MOVF	ShipDirection, W
	ADDWF	RightMotor, F
	MOVLW	0xF0
	BTFSC	STATUS, C
	MOVWF	RightMotor
	MOVF	ShipDirection, W
	SUBWF	LeftMotor, F
	BTFSS	STATUS, C
	CLRF	LeftMotor

;	Send Motor speed information
DoneTurn:	
	MOVLW	0xF0
	ANDWF	LeftMotor, F
	ANDWF	RightMotor, F
	CALL	SendMotorInfo
;	Activate the pump ourselves
	banksel	CCPR1L
	MOVF	ShipWaterSpd, W
                MOVWF           CCPR1L
	banksel	PORTA
	RETURN

SendDirectionInfo:
	banksel	PORTA
	MOVF	ShipDirection, W
	MOVWF	SPI_TXDATA
	BSF	SPI_TXDATA, 0	; mark as direction
	BSF	SPI_TXDATA, 1	; mark as slave left
	BCF	SPI_SlaveLft	; pull slave select low
	CALL	SPI_Transmit
	BSF	SPI_SlaveLft	; pull slave select high
	RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SendFlag:
	banksel	PORTA
	MOVF	Team, W
	MOVWF	SPI_TXDATA
	BSF	SPI_TXDATA, 0	; mark as direction
	BCF	SPI_TXDATA, 1	; mark as slave right
	BCF	SPI_SlaveRt	; pull slave select low
	CALL	SPI_Transmit
	BSF	SPI_SlaveRt	; pull slave select high
	RETURN

SendWhiteFlag:
	banksel	PORTA
	MOVLW	0x80
	MOVWF	SPI_TXDATA
	BSF	SPI_TXDATA, 0	; mark as direction
	BCF	SPI_TXDATA, 1	; mark as slave right
	BCF	SPI_SlaveRt	; pull slave select low
	CALL	SPI_Transmit
	BSF	SPI_SlaveRt	; pull slave select high
	RETURN


SendMotorInfo:
	banksel	PORTA
;	Left motor
	MOVF	LeftMotor, W
	MOVWF	SPI_TXDATA
	BCF	SPI_TXDATA, 0	; mark as speed
	BSF	SPI_TXDATA, 1	; mark as slave left
	BCF	SPI_SlaveLft	; pull slave select low
	CALL	SPI_Transmit
	BSF	SPI_SlaveLft	; pull slave select high
;	Right motor
	MOVF	RightMotor, W
	MOVWF	SPI_TXDATA
	BCF	SPI_TXDATA, 0	; mark as speed
	BCF	SPI_TXDATA, 1	; mark as slave right
	BCF	SPI_SlaveRt	; pull slave select low
	CALL	SPI_Transmit
	BSF	SPI_SlaveRt	; pull slave select high
	RETURN

API_Admiral:
;	Command is from the admiral, now we need to check the admiral address
	CALL	CheckAdmAddr
	ADDLW	0x00
	BTFSS	STATUS, Z
	RETURN
;	Address matches admiral, now which command is sent?
	MOVF	COM_rxData2, W
	BTFSS	STATUS, Z
	RETURN
	MOVLW	COM_ping
	SUBWF	COM_rxData3, W
	BTFSC	STATUS, Z
	GOTO	AdmPing
	MOVLW	COM_standdown
	SUBWF	COM_rxData3, W
	BTFSC	STATUS, Z
	GOTO	AdmStanddown
	MOVLW	COM_hardreset
	SUBWF	COM_rxData3, W
	BTFSC	STATUS, Z
	GOTO	AdmHardreset
	MOVLW	COM_softreset
	SUBWF	COM_rxData3, W
	BTFSC	STATUS, Z
	GOTO	AdmSoftreset
;	Not a valid command
	RETURN

;   Respond to admiral's ping by sending back the ping data correctly
AdmPing:
	CALL	SetAddressToAdmiral
	MOVLW	COM_pingresp
	MOVWF	COM_data1
	MOVF	PingData1, W
	MOVWF	COM_data2
	MOVF	PingData2, W
	MOVWF	COM_data3
	CALL	API_TxPacket
	RETURN
	
;  Respond to standdown by shutting off everything, sending ack to admiral,
;  passing it on to helm, and then block until helm acknowledges
AdmStanddown:
;	Shut off everythng
	CALL	ShutOffActuation
;	Send ack to admiral
	CALL	SendAckToAdmiral
;	Pass it on to helm
	CALL	SetAddressToHelm
	MOVLW	COM_craft
	MOVWF	COM_data1
	CLRF	COM_data2
	MOVLW	COM_sdreceived
	MOVWF	COM_data3
	CALL	API_TxPacket
;	Now block until helm acknowledges
ASD1:	BTFSS	COM_rxFlag, COM_rxDone
	GOTO	$-1
	BCF	COM_rxFlag, COM_rxDone
;	Is it a helm ack???
;	Check helm addr
	CALL	CheckHelmAddr
	ADDLW	0x00
	BTFSS	STATUS, Z
	GOTO	ASD1
;	It's from the helm, is it an ack?
	MOVLW	COM_ack
	SUBWF	COM_rxData1, W
	BTFSS	STATUS, Z
	GOTO	ASD1
	MOVF	COM_rxData2, W
	BTFSS	STATUS, Z
	GOTO	ASD1
	MOVLW	COM_sdreceived
	SUBWF	COM_rxData3, W
	BTFSS	STATUS, Z
	GOTO	ASD1
;	It is a helm ack, sweet, now just return
	RETURN

SendAckToAdmiral:
	CALL	SetAddressToAdmiral
	MOVLW	COM_ack
	MOVWF	COM_data1
	MOVF	COM_rxData2, W
	MOVWF	COM_data2
	MOVF	COM_rxData3, W
	MOVWF	COM_data3
	CALL	API_TxPacket
	RETURN

;  Respond to soft reset by shutting off everything and then acknowledging
;  to admiral
AdmSoftreset:
	CALL	ShutOffActuation
;	Send ack to the admiral
	CALL	SendAckToAdmiral
	RETURN

ShutOffActuation:
	MOVLW	0x80
	MOVWF	ShipDirection
	MOVWF	RightMotor
	MOVWF	LeftMotor
	CALL	SendDirectionInfo
	CALL	SendMotorInfo
	RETURN
	
;   Respond to hard reset by shutting off everything and then return to waiting
;   for ibutton state
AdmHardreset:
	CALL	ShutOffActuation
	CLRF	StateMachine
	BSF	StateMachine, Waiting
	RETURN




;	SPI_Transmit
;   --------------------------------------------------------------------
;   Transmits to SPI, no slave select
SPI_Transmit:
;	Ensure Bank 1
	BSF	STATUS,RP0
	BCF	STATUS,RP1
	BTFSS	SSPSTAT, BF 	; Has data been received(transmit complete)?
	GOTO	$-1
;	Bank 0
	BCF	STATUS,RP0
	MOVF	SSPBUF, W	; WREG reg = contents of SSPBUF
	MOVWF	SPI_RXDATA	; Save in user RAM, if data is meaningful
	MOVF	SPI_TXDATA, W	; W reg = contents of TXDATA
	MOVWF	SSPBUF	; New data to xmit
	RETURN

;
;	Interrupt Service Routine
;   ***********************************************************************
;   ***** The PIC's one and only ISR...  =(  ******************************
;   ***********************************************************************
Interrupt:
;	PUSH
	MOVWF	W_TEMP	; Copy W to TEMP register
	SWAPF	STATUS, W	; Swap status to be saved into W
	banksel	PORTA
	MOVWF	STATUS_TEMP	; Save status to STATUS_TEMP register
;	ISR
	banksel	PIR1
	BTFSC	PIR1, RCIF
	CALL	EUSART_Rx_Int
	BTFSC	INTCON, T0IF
	CALL	Timer0_Int
;	POP
	banksel	PORTA
	SWAPF	STATUS_TEMP, W	; Swap nibbles in STATUS_TEMP register
			; and place result into W
	MOVWF	STATUS	; Move W into STATUS register
			;   (sets bank to original state)
	SWAPF	W_TEMP, F	; Swap nibbles in W_TEMP and place result in W_TEMP
	SWAPF	W_TEMP, W	; Swap nibbles in W_TEMP and place result into W	
	RETFIE

EUSART_Rx_Int:
;	Clear flag first
	BCF	PIR1, RCIF
	BTFSC	COM_rxFlag, 3
	GOTO	AllFlagsClear
	BTFSC	COM_rxFlag, 2
	GOTO	CheckFor0x81
	BTFSC	COM_rxFlag, 1
	GOTO	CheckFor0x08
	BTFSC	COM_rxFlag, 0
	GOTO	CheckFor0x00
CheckFor0x7E:	MOVLW	0x7E
	SUBWF	RCREG, W
	BTFSS	STATUS, Z
	GOTO	SomethingWrong
	BSF	COM_rxFlag, 0
	RETURN
CheckFor0x00:	MOVF	RCREG, F
	BTFSS	STATUS, Z
	GOTO	SomethingWrong
	BSF	COM_rxFlag, 1
	RETURN
CheckFor0x08:	MOVLW	0x08
	SUBWF	RCREG, W
	BTFSS	STATUS, Z
	GOTO	SomethingWrong
	BSF	COM_rxFlag, 2
	RETURN
CheckFor0x81:	MOVLW	0x81
	SUBWF	RCREG, W
	BTFSS	STATUS, Z
	GOTO	SomethingWrong
	BSF	COM_rxFlag, 3
	RETURN
AllFlagsClear:
;	Read data into appropriate index of receiving buffer
	MOVLW	COM_rxBuffAddr
	ADDWF	COM_rxIndex, W
	MOVWF	FSR
;	Read data
	MOVF	RCREG, W
	MOVWF	INDF
;	Increment the index
	INCF	COM_rxIndex, F
	MOVF	COM_rxIndex, W
	SUBLW	COM_rxLn
;	result is positive or zero, now check if it's zero
	BTFSS	STATUS, Z
;	index is not equal to array length, just return
	RETURN
;	index is equal to array length, API frame is done
	CLRF	COM_rxFlag
	CLRF	COM_rxIndex
	BSF	COM_rxFlag, COM_rxDone
	RETURN
SomethingWrong:
	CLRF	COM_rxIndex
	CLRF	COM_rxFlag
	RETURN

Timer0_Int:
	BCF	INTCON, T0IF
	DECFSZ	Timer0Count, F
	RETURN
;	If the counter finished, reset it and set a flag
	MOVLW	Timer0Max
	MOVWF	Timer0Count
	BSF	Timer0Flag, 0
	RETURN

	END

ibutton.h

; ******************************************************************************
; ******************************************************************************
;	Functions for iButton
; ******************************************************************************
; ******************************************************************************

iWAIT:
	BTFSS	PIR1, TMR1IF
	GOTO	iWAIT	
	RETURN

TIMER1_Init:
	banksel	OSCCON
	BSF	OSCCON, IRCF0
	BSF	OSCCON, IRCF1
	BSF	OSCCON, IRCF2

	banksel	T1CON
	BCF	T1CON, TMR1CS	; use internal clock (Fosc/4)
	BCF	T1CON, T1CKPS0	; set prescale value as 1:1
	BCF	T1CON, T1CKPS1
	BSF	T1CON, TMR1ON	; Enable Timer 1
;	BCF	T1CON, TMR1GE

	RETURN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

iButton_Init:
	banksel	ANSEL
	BCF	ANSEL, ANS0
	RETURN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

READ_iButton:
;	Have we received something?  All we care about is admiral ping
	BTFSC	COM_rxFlag, COM_rxDone
	CALL	CheckIfAdmiralPingIbutton

;	banksel	TRISA	; set the pin as an output
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BCF	TRISA, 0
	
;	banksel	PORTA	; set the line low
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BCF	iButtonPin
	
;	banksel	TMR1L	; wait for 500 usec
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0xd5	;232-19
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFC	; 768
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT			

;	banksel	TRISA	; set the pin as an input
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BSF	TRISA, 0

;	banksel	TMR1L	; wait for 50 usec
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0x4e	; 100-22
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFF
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT	

;	banksel	PORTA	; read the pin
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BTFSC	iButtonPin
	GOTO	READ_iButton	; if no iButton found, repeat
	RETURN		; if iButton is found, proceed to reset

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckIfAdmiralPingIbutton:
	MOVLW	COM_adm
	SUBWF	COM_rxData1, W
	BTFSS	STATUS, Z
;	It's not admiral command
	RETURN
;	It is admiral
	CALL	CheckAdmAddr
	ADDLW	0x00
	BTFSS	STATUS, Z
	RETURN
;	Address matches admiral, now is it ping?
	MOVF	COM_rxData2, W
	BTFSS	STATUS, Z
	RETURN
	MOVLW	COM_ping
	SUBWF	COM_rxData3, W
	BTFSS	STATUS, Z
	CALL	AdmPing
	RETURN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RESET_iButton:
;	banksel	TRISA	; set the pin as an output
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BCF	TRISA, 0
	
;	banksel	PORTA	; set the line low
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BCF	iButtonPin
	
;	banksel	TMR1L	; wait for 500 usec
	MOVLW	0xd5	;232-19
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFC	; 768
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT	

	NOP		
	NOP		
	NOP		
	NOP		
	NOP		
	NOP		
	
;	banksel	PORTA	; set the line high
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BSF	iButtonPin
	
;	banksel	TMR1L	; wait for 500 usec
	MOVLW	0xd5	;232-19
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFC	; 768
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT			

	NOP

;goto	RESET_iButton
	RETURN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SEND_READ_COMMAND:
;	banksel	TMR1L
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0x33
;	MOVLW	0xff
	MOVWF	readROMcommand
	MOVLW	8
	MOVWF	CNT
SEND_LOOP:			; send read ROM command
	RRF	readROMcommand, f
	BTFSS	STATUS, C
	GOTO	WRITE_0
	GOTO	WRITE_1
CHECK_END_OF_SEND_LOOP:
	DECFSZ	CNT, f
	GOTO	SEND_LOOP

;goto	SEND_READ_COMMAND	
	RETURN

WRITE_1:
;	banksel	TRISA	; set the pin as an output
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BCF	TRISA, 0
	
;	banksel	PORTA	; set the line low
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BCF	iButtonPin
	
;	banksel	TMR1L	; wait for 5 usec
;	MOVLW	5
;	XORLW	0xFF
;	MOVWF	TMR1L
;	MOVLW	0xFF
;	MOVWF	TMR1H
;	BCF	PIR1, TMR1IF
;	CALL	iWAIT	

	NOP
	NOP
	NOP
	
	banksel	TRISA	; set the pin as an input
	BSF	TRISA, 0
	
;	banksel	TMR1L	; wait for 70 usec
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0x70	;140-28
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFF
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT

	NOP
	NOP
	NOP

	GOTO	CHECK_END_OF_SEND_LOOP
	
WRITE_0:
;	banksel	TRISA	; set the pin as an output
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BCF	TRISA, 0
	
;	banksel	PORTA	; set the line low
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BCF	iButtonPin
	
;	banksel	TMR1L	; wait for 60 usec
	MOVLW	0x68	;120-16
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFF
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT	
	
;	banksel	TRISA	; set the pin as an input
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BSF	TRISA, 0
	
;	banksel	TMR1L	; wait for 15 usec
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0x04	;30-26
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFF
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT	

	NOP
	NOP

	GOTO	CHECK_END_OF_SEND_LOOP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
READ_iButton_data:
;	banksel	TMR1L
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0x18	;24
	MOVWF	CNT

READ_LOOP:	
;	banksel	TRISA	; set the pin as an output
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BCF	TRISA, 0
	
;	banksel	PORTA	; set the line low
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BCF	iButtonPin
	
;	banksel	TMR1L	; wait for 5 usec

	NOP
	NOP
	NOP
	NOP
	
;	banksel	PORTA	; set the line high
;	BCF	STATUS, RP1
;	BCF	STATUS, RP0
;	BSF	iButtonPin
;	banksel	TRISA	; set the pin as an input
	BCF	STATUS, RP1
	BSF	STATUS, RP0
	BSF	TRISA, 0
	
;	banksel	TMR1L	; wait for 10 usec

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
;NOP
;NOP
;NOP

;	banksel	TMR1L
	BCF	STATUS, RP1
	BCF	STATUS, RP0
						
	RRF	iButtonReadingM, f	; shift the reading to get it ready for the next bit
	RRF	iButtonReadingH, f
	BTFSC	STATUS, C
	GOTO	SETHI
	BCF	iButtonReadingM, 7
	GOTO	NEXT

SETHI	BSF	iButtonReadingM, 7
;	RRF	iButtonReadingL, f	; shift the reading to get it ready for the next bit
;	RRF	iButtonReadingM, f
;	BTFSC	STATUS, C
;	BSF	iButtonReadingL, 7
;	RRF	iButtonReadingH, f
;	BTFSC	STATUS, C
;	BSF	iButtonReadingM, 7

;	banksel	PORTA		; set the line low
;	BCF	STATUS, RP1
;	BCF	STATUS, RP0
;	BCF	iButtonPin
;	banksel	PORTA		; read the pin
NEXT	BCF	STATUS, RP1
	BCF	STATUS, RP0
	BTFSC	iButtonPin
	GOTO	READ_1		; if high, reading is 1
	BCF	iButtonReadingH, 7	; if low, reading is 0

CHECK_END_OF_READ_LOOP:
;	banksel	TMR1L	; wait for 60 usec
	BCF	STATUS, RP1
	BCF	STATUS, RP0
	MOVLW	0x5c	;120-28
	XORLW	0xFF
	MOVWF	TMR1L
	MOVLW	0xFF
	MOVWF	TMR1H
	BCF	PIR1, TMR1IF
	CALL	iWAIT	

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	DECFSZ	CNT, f
	GOTO	READ_LOOP

;goto	READ_iButton_data
;goto	READ_LOOP
	RETURN
READ_1:
	BSF	iButtonReadingH, 7
	GOTO	CHECK_END_OF_READ_LOOP

Waiting_for_iButton:
	CALL	TIMER1_Init
	CALL	iButton_Init
start_iButton:
	CALL	READ_iButton
	CALL	RESET_iButton
	CALL	SEND_READ_COMMAND
	CALL	READ_iButton_data

;	check if read right 	
;	MOVLW	0xeb
	MOVLW	0xff
	SUBWF	iButtonReadingM, w
	BTFSC	STATUS, Z
	GOTO	start_iButton

;	MOVLW	0x4b
	MOVLW	0xff
	SUBWF	iButtonReadingH, w
	BTFSC	STATUS, Z
	GOTO	start_iButton
	RETURN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

shipinits.h

;
;   Clock_Init
;
;
Clock_Init:
	banksel	OSCCON
	BSF	OSCCON, IRCF0
	BSF	OSCCON, IRCF1
	BSF	OSCCON, IRCF2
	RETURN

;
;   SPI_Init
;   --------------------------------------------------------------------
;   Routine to initialize SPI on the PIC.
SPI_Init:
	; Handle all the ANSEL and TRIS pins for SPI
	banksel	ANSELH
	BCF	ANSELH, ANS8;		Turn off AD on SS
	BCF	ANSELH, ANS9;		Turn off AD on SDO
	BCF	ANSELH, ANS10;		Turn off AD on SDI/SDA
	banksel	TRISA
	BSF	TRISB, TRISB4;		Set SDI/SDA line as input
	BCF	TRISC, TRISC7;		Set SDO line as output
	; Are we master or slave
	BCF	TRISB, TRISB6;		Set SCK line as output for Master
	banksel	SSPSTAT
	CLRF	SSPSTAT;		SMP = 0, CKE = 0, clear status bits
	BSF	SSPSTAT, CKE;		CKE = 1
	banksel	SSPCON
	MOVLW	0x31		; Set up SPI port, Master mode, CLK/16
	MOVWF	SSPCON		; Mode 3 (CKE = 1, CKP = 1)
				; Data sampled in middle (SMP = 0, Master mode)

;	Set up the Slave Select lines as outputs raised high
	banksel	PORTC
	BSF	PORTC, 0
	BSF	PORTC, 1
	BSF	PORTC, 2
	banksel	TRISC
	BCF	TRISC, TRISC0;		Set SS line as output
	BCF	TRISC, TRISC1;		Set SS line as output
	BCF	TRISC, TRISC2;		Set SS line as output
	
	; Should be ready to transmit
	banksel	SSPBUF
	MOVLW	0x80
	MOVWF	SSPBUF	; New data to xmit
	RETURN

;
;	EUSART_Init routine.
;   --------------------------------------------------------------------
;   Routine to initialize the EUSART peripheral on the PIC
EUSART_Init:
;	Clear analog for RB5
	banksel ANSEL
	BCF	ANSELH, ANS11
	banksel	TXSTA
;	Choose 8 bit asynchronous /16
	BCF	TXSTA, SYNC
	BSF	TXSTA, BRGH
	BCF	BAUDCTL, BRG16
;	Choose a 9600 Baud rate (10 MHz clock)
;	MOVLW	0x0C
;	MOVLW	0x40
;	Choose a 9600 Baud rate (8 MHz clock)
	MOVLW	0x33
	MOVWF	SPBRG
;	Enable 8-bit tx
	BCF	TXSTA, TX9
;	Enable transmit
	BSF	TXSTA, TXEN
;	Enable serial port
	banksel	RCSTA
	BSF	RCSTA, SPEN
;	Enable 8-bit rx
	BCF	RCSTA, RX9
;	Enable receive
	BSF	RCSTA, CREN
;	Enable interrupt
	banksel	PIE1
	BSF	PIE1, RCIE
	RETURN

;
;	PWM_Init routine
;   --------------------------------------------------------------------
;   Routine to initialize PWM on the PIC
PWM_Init:
;	Ensure Bank 1
                BSF             STATUS, RP0
	BCF	STATUS, RP1
;	Disable PWM pin
                BSF             TRISC, TRISC5	; Set C5 to input
;	Set PWM Period
                MOVLW           0xF0
                MOVWF           PR2
;	Configure CCP for PWM
                BCF             STATUS, RP0	; Select bank 0
                MOVLW           0x3E
                MOVWF           CCP1CON
;	Set PWM duty cycle
                MOVLW           0x00
                MOVWF           CCPR1L
;	Configure and start Timer2
                BCF             PIR1, TMR2IF	; Clear Timer2 interrupt flag
                BSF             T2CON, T2CKPS1	; Set Timer2 prescale value to 16
                BSF             T2CON, TMR2ON	; Turn Timer2 on
;	Enable PWM output after new PWM cycle started
PWM_Pt_1:
                BTFSS           PIR1, TMR2IF
                GOTO            PWM_Pt_1
                BSF             STATUS, RP0	; Select bank 1
                BCF             TRISC, TRISC5	; Set C5 to output
	RETURN

;
;	Timer0_Init routine
;   --------------------------------------------------------------------
;   Routine to initialize Timer0 on the PIC
Timer0_Init:
	banksel	OPTION_REG
;	Set as timer
	BCF	OPTION_REG, T0CS
;	Set prescaler to timer 0
	BCF	OPTION_REG, PSA
;	1:256 prescaler
	BSF	OPTION_REG, PS0
	BSF	OPTION_REG, PS1
	BSF	OPTION_REG, PS2
;	Clear the flag
	banksel	INTCON
	BCF	INTCON, T0IF
;	Enable the interrupt
	BSF	INTCON, T0IE
;	Reset the counter and flag
	MOVLW	Timer0Max
	MOVWF	Timer0Count
	CLRF	Timer0Flag
	RETURN

LED_Init:
	banksel	PORTC
	BSF	PORTC, 4
	banksel	TRISC
	BCF	TRISC, 4
	RETURN

synch.h

;   We're waiting to synch up.  We're waiting until we
;      receive a broadcast message from the helm, at which
;      point we want to check whether their ibutton data
;      matches up well with ours
Waiting_for_Sync:
	banksel	PORTA
	BTFSS	COM_rxFlag, COM_rxDone
	GOTO	$-1
	BCF	COM_rxFlag, COM_rxDone
;	We've received an API packet, is it ibutton?
	MOVLW	COM_ibutton
	SUBWF	COM_rxData1, W
	BTFSS	STATUS, Z
;	Not ibutton, is it ping?
	GOTO	IsItPing
	MOVF	iButtonReadingH, W
	SUBWF	COM_rxData2, W
	BTFSS	STATUS, Z
	GOTO	Waiting_for_Sync
	MOVF	iButtonReadingM, W
	SUBWF	COM_rxData3, W
	BTFSS	STATUS, Z
	GOTO	Waiting_for_Sync
;	It is an ibutton command!  Now we store the address
;	   and send a matched response
;	Store the address of helm
	MOVF	COM_rxAddrH, W
	MOVWF	HelmAddrH
	MOVF	COM_rxAddrL, W
	MOVWF	HelmAddrL
;	Setup ping data to respond
	MOVWF	PingData2
	MOVLW	0x04
	MOVWF	PingData1
;	Send matched command to the helm
	CALL	SetAddressToHelm
	MOVLW	COM_craft
	MOVWF	COM_data1
	MOVLW	0x00
	MOVWF	COM_data2
	MOVLW	COM_matched
	MOVWF	COM_data3
xxx:	CALL	API_TxPacket
	CALL	Wait
	CALL	API_TxPacket
	CALL	Wait
;	Save Team
	BTFSC	iButtonReadingM, 0
	GOTO	$+3
	CLRF	Team	; Team Blue if iButton reading is even
	RETURN
	MOVLW	0xF0
	MOVWF	Team	; Team Red if iButton reading is odd
;	Get out of waiting mode
	BCF	StateMachine, Waiting
	RETURN

IsItPing:
	MOVLW	COM_adm
	SUBWF	COM_rxData1, W
	BTFSS	STATUS, Z
;	It's not admiral
	GOTO	Waiting_for_Sync
;	It's admiral
;	Command is from the admiral, now we need to check the admiral address
	CALL	CheckAdmAddr
	ADDLW	0x00
	BTFSS	STATUS, Z
	GOTO	Waiting_for_Sync
;	Address matches admiral, now which command is sent?
	MOVF	COM_rxData2, W
	BTFSS	STATUS, Z
	GOTO	Waiting_for_Sync
	MOVLW	COM_ping
	SUBWF	COM_rxData3, W
	BTFSS	STATUS, Z
	CALL	AdmPing
	GOTO	Waiting_for_Sync

vars.h

;   Utility Variables
BIT0HI	equ	0x01
BIT1HI	equ	0x02
BIT2HI	equ	0x04
#define	SPI_SlaveRt	PORTC,2	
#define	SPI_SlaveLft	PORTC,1
#define	SPI_Slave3	PORTC,0

Timer0Max	equ	0x0A

AdmiralAddrH	equ	0xBC
AdmiralAddrL	equ	0xFF

; Locations in memory
SPI_RXDATA	equ	0x20
SPI_TXDATA	equ	0x21
Timer1	equ	0x22
Timer2	equ	0x23

W_TEMP	equ	0x24
STATUS_TEMP 	equ	0x25

COM_addrs_msb	equ	0x26
COM_addrs_lsb	equ	0x27
COM_data1	equ	0x28
COM_data2	equ	0x29
COM_data3	equ	0x2A
COM_checksum	equ	0x2B
COM_frameid	equ	0x2C
COM_options	equ	0x2D

COM_rxBuffAddr	equ	0x2E
COM_rxAddrH	equ	0x2E
COM_rxAddrL	equ	0x2F
COM_rxData1	equ	0x32
COM_rxData2	equ	0x33
COM_rxData3	equ	0x34
COM_rxIndex	equ	0x3B
COM_rxFlag	equ	0x3C
COM_rxDone	equ	7

Timer0Count	equ	0x3D
Timer0Flag	equ	0x3E

ShipDirection	equ	0x3F
ShipSpeed	equ	0x41
ShipWaterSpd	equ	0x42
DirMod	equ	0x43
LeftMotor	equ	0x44
RightMotor	equ	0x45
	

PortAGhost	equ	0x46

HelmAddrH	equ	0x47
HelmAddrL	equ	0x48

PingData1	equ	0x49
PingData2	equ	0x4A

TimeOutFlag	equ	0x4C
TimeOutTimer	equ	0x4D
TimeOutTimerMax	equ	0x09

;   State machine variables
;   ------------------------
StateMachine	equ	0x4B
Waiting	equ	1


; variables for iButton
readROMcommand	equ	0x50
CNT	equ	0x51
iButtonReadingH	equ	0x52
iButtonReadingM	equ	0x53
iButtonReadingL	equ	0x54
Team	equ	0x55
TeamRed	equ	1
TeamBlue	equ	0
#define	iButtonPin	PORTA, 0

wait.h

Wait: banksel Timer1 MOVLW 0xFF; setup the first counter for waiting MOVWF Timer2 Wait2: MOVLW 0xFF; setup the second counter for waiting MOVWF Timer1 Wait1: NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP DECFSZ Timer1, F; decrement first counter, if zero loop GOTO Wait1; is done DECFSZ Timer2, F; decrement second counter, if zero loop GOTO Wait2; is done RETURN

xbee_comm.h

API_Start	equ	0x7E
API_TxData	equ	0x01
API_NoRsp	equ	0x00
API_Tx16b	equ	0x01
API_TxResult	equ	0x89
API_Rx16b	equ	0x81
API_Broadcast	equ	0xFF
COM_lnth_msb	equ	0x00
COM_lnth_lsb	equ	0x08
COM_rxLn	equ	0x08

;	Types of messages
COM_nav	equ	0x02
COM_adm	equ	0x04
COM_ibutton	equ	0x01
COM_craft	equ	0x08
COM_pingresp	equ	0x10
COM_ack	equ	0x80

;	Ship to helm message tags
COM_matched	equ	0x01
COM_sdreceived	equ	0x02

;	Admiral to ship message tags
COM_standdown	equ	0x01
COM_ping	equ	0x80
COM_hardreset	equ	0x40
COM_softreset	equ	0x20


EUSART_txL	macro	byte
	CALL	Wt_USART_TxRdy
	banksel	TXREG
	MOVLW	byte
	MOVWF	TXREG
endm

EUSART_txF	macro	file
	CALL	Wt_USART_TxRdy
	banksel	TXREG
	MOVF	file, W
	MOVWF	TXREG
endm

ChecksumCalc	macro
;	Ensure Bank 0
	BCF	STATUS,RP0
	BCF	STATUS,RP1
;	Start setting up the checksum
	MOVLW	API_Tx16b
	MOVWF	COM_checksum
	MOVF	COM_frameid, W
	ADDWF	COM_checksum, F
	MOVF	COM_options, W
	ADDWF	COM_checksum, F	
	MOVF	COM_addrs_msb, W
	ADDWF	COM_checksum, F
	MOVF	COM_addrs_lsb, W
	ADDWF	COM_checksum, F
	MOVF	COM_data1, W
	ADDWF	COM_checksum, F	
	MOVF	COM_data2, W
	ADDWF	COM_checksum, F	
	MOVF	COM_data3, W
	ADDWF	COM_checksum, F
	COMF	COM_checksum, F
endm

;   Deprecated, do NOT use
SetToSend	macro	frameID, options, d1, d2, d3
;	Ensure Bank 0
	BCF	STATUS,RP0
	BCF	STATUS,RP1
;	Setup frame id, options, rf data
	MOVLW	frameID
	MOVWF	COM_frameid
	MOVLW	options
	MOVWF	COM_options
	MOVLW	d1
	MOVWF	COM_data1
	MOVLW	d2
	MOVWF	COM_data2
	MOVLW	d3
	MOVWF	COM_data3
endm

;	Wait til the transfer buffer is ready
;   --------------------------------------------------------------------
;   Routine that waits until the EUSART is ready to transmit another byte of data
Wt_USART_TxRdy:
	banksel	TXSTA	; wait til tranfer register ready
	BTFSS	TXSTA, TRMT	; check state of transmit buffer
	GOTO	$-1
	RETURN

API_TxPacket:
	ChecksumCalc
	EUSART_txL	API_Start
	EUSART_txL	COM_lnth_msb
	EUSART_txL	COM_lnth_lsb
	EUSART_txL	API_Tx16b
	EUSART_txF	COM_frameid
	EUSART_txF	COM_addrs_msb
	EUSART_txF	COM_addrs_lsb
	EUSART_txF	COM_options
	EUSART_txF	COM_data1
	EUSART_txF	COM_data2
	EUSART_txF	COM_data3
	EUSART_txF	COM_checksum
	RETURN

SetAddressToBroadcast:
	banksel	PORTA
	MOVLW	0xFF
	MOVWF	COM_addrs_msb
	MOVWF	COM_addrs_lsb
	RETURN

SetAddressToAdmiral:
	banksel	PORTA
	MOVLW	AdmiralAddrH
	MOVWF	COM_addrs_msb
	MOVLW	AdmiralAddrL
	MOVWF	COM_addrs_lsb
	RETURN

SetAddressToHelm:
	banksel	PORTA
	MOVF	HelmAddrH, W
	MOVWF	COM_addrs_msb
	MOVF	HelmAddrL, W
	MOVWF	COM_addrs_lsb
	RETURN

CheckHelmAddr:
	banksel	PORTA
	MOVF	HelmAddrH, W
	SUBWF	COM_rxAddrH, W
	BTFSS	STATUS, Z
	RETLW	0xFF
	MOVF	HelmAddrL, W
	SUBWF	COM_rxAddrL, W
	BTFSS	STATUS, Z
	RETLW	0xFF
	RETLW	0x00

CheckAdmAddr:
	banksel	PORTA
	MOVLW	AdmiralAddrH
	SUBWF	COM_rxAddrH, W
	BTFSS	STATUS, Z
	RETLW	0xFF
	MOVLW	AdmiralAddrL
	SUBWF	COM_rxAddrL, W
	BTFSS	STATUS, Z
	RETLW	0xFF
	RETLW	0x00

SSlvL.asm

; Final Project - Terman Pond Flotilla
; ME218B
; By Allen Cheung
; -----------------------------------------------------------------
;
;
; Pins used:
;    RB<7, 5> as transmit/receive lines for EUSART
;
	list 	P=PIC16F690
	#include 	"p16F690.inc"
	#include	pwm.h
	__config 	(_CP_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO)


;
;	Variable Definitions
;   ---------------------------------------------------------------
;   Utility Variables
BIT0HI	equ	0x01
BIT1HI	equ	0x02
BIT2HI	equ	0x04

Tmr0ServMax	equ	0x3F
Timer0Max	equ	0xFF
#define	ServoPin	PORTA,1

MotorSpeedMask	equ	0xE0
; Locations in memory
SPI_RXDATA	equ	0x20
SPI_TXDATA	equ	0x21
Timer1	equ	0x22
Timer2	equ	0x23

W_TEMP	equ	0x24
STATUS_TEMP 	equ	0x25

Timer0Count	equ	0x26
Timer0Flag	equ	0x27
Tmr0ServCount	equ	0x28
ServoPulse	equ	0x29

PORTAghost	equ	0x2A


;   Beginning of Program
;   --------------------------------------------------------------------
	org	0
	goto	Main
	org	5
	goto	Interrupt

;
;	Tables
;   --------------------------------------------------------------------
;	Lookup table for bit pattern to write to Port C output
END_TBL:
; 	make sure address is less than 0xff
ServoTable:
	ADDWF	PCL, F
	RETLW	0x2C
	RETLW	0x2D
	RETLW	0x2E
	RETLW	0x2F
	RETLW	0x30
	RETLW	0x31
	RETLW	0x32
	RETLW	0x34
	RETLW	0x34
	RETLW	0x36
	RETLW	0x37
	RETLW	0x38
	RETLW	0x39
	RETLW	0x3A
	RETLW	0x3B
	RETLW	0x3C

;
;   Clock_Init
;
;
Clock_Init:
	banksel	OSCCON
	BSF	OSCCON, IRCF0
	BSF	OSCCON, IRCF1
	BSF	OSCCON, IRCF2
	RETURN

;
;   SPI_Init
;   --------------------------------------------------------------------
;   Routine to initialize SPI on the PIC.
SPI_Init:
	; Handle all the ANSEL and TRIS pins for SPI
	banksel	ANSELH
	BCF	ANSELH, ANS8;		Turn off AD on SS
	BCF	ANSELH, ANS9;		Turn off AD on SDO
	BCF	ANSELH, ANS10;		Turn off AD on SDI/SDA
	banksel	TRISA
	BSF	TRISB, TRISB4;		Set SDI/SDA line as input
	BCF	TRISC, TRISC7;		Set SDO line as output
	BSF	TRISC, TRISC6;		Set SS line as input
	; Are we master or slave
	BSF	TRISB, TRISB6;		Set SCK line as input for Slave

	banksel	SSPSTAT
	CLRF	SSPSTAT;		SMP = 0, CKE = 0, clear status bits
	BSF	SSPSTAT, CKE;		CKE = 1
	banksel	SSPCON
	MOVLW	0x35		; Set up SPI port, Slave mode (SS), enable
	MOVWF	SSPCON		; Mode 3 (CKE = 1, CKP = 1)
				; (SMP cleared for slave mode)
	banksel	PIE1
	BSF	PIE1, SSPIE		; Enable SSP interrupt
	banksel	PIR1
	BCF	PIR1, SSPIF		; Clear interrupt flag
	; Should be ready to transmit
	RETURN


;
;	PWM_Init routine
;   --------------------------------------------------------------------
;   Routine to initialize PWM on the PIC
PWM_Init:
;	Ensure Bank 1
                BSF             STATUS, RP0
	BCF	STATUS, RP1
;	Disable PWM pin
                BSF             TRISC, TRISC5	; Set C5 to input
;	Set PWM Period
                MOVLW           0xE0
                MOVWF           PR2
;	Configure CCP for PWM
                BCF             STATUS, RP0	; Select bank 0
                MOVLW           0x0C	; Active High
                MOVWF           CCP1CON
;	Set PWM duty cycle
                MOVLW           0x00
                MOVWF           CCPR1L
;	Configure and start Timer2
                BCF             PIR1, TMR2IF	; Clear Timer2 interrupt flag
                BSF             T2CON, T2CKPS0	; Set Timer2 prescale value to 4
                BSF             T2CON, TMR2ON	; Turn Timer2 on
;	Enable PWM output after new PWM cycle started
PWM_Pt_1:	BTFSS           PIR1, TMR2IF
                GOTO            PWM_Pt_1
                BSF             STATUS, RP0	; Select bank 1
                BCF             TRISC, TRISC5	; Set C5 to output
	RETURN

PWM_ActiveHi:
	banksel	CCP1CON
	MOVLW	0x0C
	MOVWF	CCP1CON
	RETURN

PWM_ActiveLo:
	banksel	CCP1CON
	MOVLW	0x0E
	MOVWF	CCP1CON
	RETURN

;
;	Timer0_Init routine
;   --------------------------------------------------------------------
;   Routine to initialize Timer0 on the PIC
Timer0_Init:
	banksel	OPTION_REG
;	Set as timer
	BCF	OPTION_REG, T0CS
;	Set prescaler to WDT
	BSF	OPTION_REG, PSA
;	Clear the flag
	banksel	INTCON
	BCF	INTCON, T0IF
;	Enable the interrupt
	BSF	INTCON, T0IE
;	Reset the counter and flag
	MOVLW	Timer0Max
	MOVWF	Timer0Count
	MOVLW	Tmr0ServMax
	MOVWF	Tmr0ServCount
	CLRF	Timer0Flag
	RETURN

LED_Init:
	banksel	PORTA
	CLRF	PORTAghost
	BSF	PORTA, 0
	BSF	PORTAghost, 0
	banksel	TRISA
	BCF	TRISA, 0
	RETURN

HbridgeCtrlInit:
	CALL	PWM_Init
	banksel	PORTC
	BCF	PORTC, 4
	banksel	TRISC
	BCF	TRISC, TRISC4
	RETURN

Servo_Init:
	banksel	PORTA
	BCF	ServoPin
	banksel	TRISA
	BCF	TRISA, 1
	RETURN
	

;
;	Initialize routine.  
;   --------------------------------------------------------------------
Initialize:
;	Setup Clock
	CALL	Clock_Init
;	Setup Timer0
	CALL	Timer0_Init
;	Setup Hbridge control lines
	CALL	HbridgeCtrlInit
;	Setup SPI
	CALL	SPI_Init
;	Setup LEDs
	CALL	LED_Init
;	Setup Servo
	CALL	Servo_Init
;	Enable Interrupts
	banksel	INTCON
	BSF	INTCON, GIE
	BSF	INTCON, PEIE
	RETURN


;********************************************************************************	
;********************************************************************************
;	Main Loop
;   --------------------------------------------------------------------
;   Continuously loops and handles the program
;       Looks for a button press, looks for a received message on EUSART
;       If slave select raised transmits message or ack
;********************************************************************************
;********************************************************************************
Main:
	CALL	Initialize
	banksel	PORTA
;	Initialize starting values to neutral motor/rudder
	MOVLW	0x34
	MOVWF	ServoPulse
	SetPWMDuty	0x00
	banksel	PORTC
	BCF	PORTC, 4
;   This is the main loop, here we just do nothing, checking the timer0 flag
;      to control the LED.  All responses are handled in SPI interrupt
PNT_2:
	NOP
	CALL	CheckTimer0Flag
	GOTO	PNT_2




CheckTimer0Flag:
	banksel	PORTA
	BTFSS	Timer0Flag, 0
	RETURN
	BCF	Timer0Flag, 0
;	Toggle LED
	BTFSS	PORTAghost, 0
	GOTO	$+4
	BCF	PORTAghost, 0
	BCF	PORTA, 0
	RETURN
	BSF	PORTAghost, 0
	BSF	PORTA, 0
	RETURN

;
;	Interrupt Service Routine
;   ***********************************************************************
;   ***** The PIC's one and only ISR...  =(  ******************************
;   ***********************************************************************
Interrupt:
;	PUSH
	MOVWF	W_TEMP	; Copy W to TEMP register
	SWAPF	STATUS, W	; Swap status to be saved into W
	banksel	PORTA
	MOVWF	STATUS_TEMP	; Save status to STATUS_TEMP register
;	ISR
	banksel	PIR1
	BTFSC	PIR1, SSPIF
	CALL	SPI_Int
	BTFSC	INTCON, T0IF
	CALL	Timer0_Int
;	POP
	banksel	PORTA
	SWAPF	STATUS_TEMP, W	; Swap nibbles in STATUS_TEMP register
			; and place result into W
	MOVWF	STATUS	; Move W into STATUS register
			;   (sets bank to original state)
	SWAPF	W_TEMP, F	; Swap nibbles in W_TEMP and place result in W_TEMP
	SWAPF	W_TEMP, W	; Swap nibbles in W_TEMP and place result into W	
	RETFIE

;	SPI_Int
;   --------------------------------------------------------------------
;   ISR that receives/transmits from SPI, but primary purpose is to receive
SPI_Int:
	BCF	PIR1, SSPIF
	banksel	PORTA
	MOVF	SSPBUF, W	; WREG reg = contents of SSPBUF
	MOVWF	SPI_RXDATA	; Save in user RAM, if data is meaningful
	MOVF	SPI_TXDATA, W	; W reg = contents of TXDATA
	MOVWF	SSPBUF	; New data to xmit
;	Is it for the left PIC?
	BTFSS	SPI_RXDATA, 1
	RETURN
;	Process the command
	BTFSC	SPI_RXDATA, 0
	GOTO	ServoDir
;	Motor speed command
;	   upper nibble holds 4 bits of motor speed information
	BTFSS	SPI_RXDATA, 7
	GOTO	BackwardsMot
;	Set means run "forwards"
ForwardsMot:	BCF	PORTC, 4
	MOVLW	0x80
	SUBWF	SPI_RXDATA, F
	RLF	SPI_RXDATA, F
	ANDLW	MotorSpeedMask
;	Divide by two
	RRF	SPI_RXDATA, F
	BCF	SPI_RXDATA, 7
	MOVF	SPI_RXDATA, W
	banksel 	CCPR1L
                MOVWF           CCPR1L	; Set new duty cycle
	CALL	PWM_ActiveHi
	RETURN
BackwardsMot:	BSF	PORTC, 4
	COMF	SPI_RXDATA, F
	MOVLW	0x80
	SUBWF	SPI_RXDATA, F
	RLF	SPI_RXDATA, F
	ANDLW	MotorSpeedMask
;	Divide by two
	RRF	SPI_RXDATA, F
	BCF	SPI_RXDATA, 7
	MOVF	SPI_RXDATA, W
	banksel	CCPR1L
	MOVWF	CCPR1L
	CALL	PWM_ActiveLo
	RETURN
;	Command to set the rudder
;	   upper nibble should hold 4 bits of direction information
ServoDir:
	RRF	SPI_RXDATA, F
	RRF	SPI_RXDATA, F
	RRF	SPI_RXDATA, F
	RRF	SPI_RXDATA, F
	MOVLW	0x0F
	ANDWF	SPI_RXDATA, W
	CALL	ServoTable
	MOVWF	ServoPulse
	RETURN

Timer0_Int:
	BCF	INTCON, T0IF
	banksel	PORTA
;	Check on the servo pulse width
	DECFSZ	Tmr0ServCount
	GOTO	Check
;	If the counter finished, set servo pin high
	BSF	ServoPin
	MOVLW	Tmr0ServMax
	MOVWF	Tmr0ServCount
	GOTO	Counter2
;	Check if the counter is equal to our pulsewidth
;	   if so, set the pin low
Check:
	MOVF	ServoPulse, W
	SUBWF	Tmr0ServCount, W 
	BTFSS	STATUS, Z
	GOTO	Counter2
	BCF	ServoPin
;	Check on our other counter
Counter2:
	DECFSZ	Timer0Count
	RETURN
;	If counter finished, set flag and reset counter
	BSF	Timer0Flag, 0
	MOVLW	Timer0Max
	MOVWF	Timer0Count
	RETURN

	END

SSlvR.asm

; Final Project - Terman Pond Flotilla
; ME218B
; By Allen Cheung
; -----------------------------------------------------------------
;
;
; Pins used:
;    RB<7, 5> as transmit/receive lines for EUSART
;
	list 	P=PIC16F690
	#include 	"p16F690.inc"
	#include	pwm.h
	__config 	(_CP_OFF & _WDT_OFF & _PWRTE_ON & _INTOSCIO)


;
;	Variable Definitions
;   ---------------------------------------------------------------
;   Utility Variables
BIT0HI	equ	0x01
BIT1HI	equ	0x02
BIT2HI	equ	0x04

Tmr0ServMax	equ	0x3F
Timer0Max	equ	0xFF
#define	ServoPin	PORTA,1

MotorSpeedMask	equ	0xE0
; Locations in memory
SPI_RXDATA	equ	0x20
SPI_TXDATA	equ	0x21
Timer1	equ	0x22
Timer2	equ	0x23

W_TEMP	equ	0x24
STATUS_TEMP 	equ	0x25

Timer0Count	equ	0x26
Timer0Flag	equ	0x27
Tmr0ServCount	equ	0x28
ServoPulse	equ	0x29

PORTAghost	equ	0x2A


;   Beginning of Program
;   --------------------------------------------------------------------
	org	0
	goto	Main
	org	5
	goto	Interrupt

;
;	Tables
;   --------------------------------------------------------------------
;	Lookup table for bit pattern to write to Port C output
END_TBL:
; 	make sure address is less than 0xff
ServoTable:
	ADDWF	PCL, F
	RETLW	0x2C
	RETLW	0x2D
	RETLW	0x2E
	RETLW	0x2F
	RETLW	0x30
	RETLW	0x31
	RETLW	0x32
	RETLW	0x34
	RETLW	0x34
	RETLW	0x36
	RETLW	0x37
	RETLW	0x38
	RETLW	0x39
	RETLW	0x3A
	RETLW	0x3B
	RETLW	0x3C

;
;   Clock_Init
;
;
Clock_Init:
	banksel	OSCCON
	BSF	OSCCON, IRCF0
	BSF	OSCCON, IRCF1
	BSF	OSCCON, IRCF2
	RETURN

;
;   SPI_Init
;   --------------------------------------------------------------------
;   Routine to initialize SPI on the PIC.
SPI_Init:
	; Handle all the ANSEL and TRIS pins for SPI
	banksel	ANSELH
	BCF	ANSELH, ANS8;		Turn off AD on SS
	BCF	ANSELH, ANS9;		Turn off AD on SDO
	BCF	ANSELH, ANS10;		Turn off AD on SDI/SDA
	banksel	TRISA
	BSF	TRISB, TRISB4;		Set SDI/SDA line as input
	BCF	TRISC, TRISC7;		Set SDO line as output
	BSF	TRISC, TRISC6;		Set SS line as input
	; Are we master or slave
	BSF	TRISB, TRISB6;		Set SCK line as input for Slave

	banksel	SSPSTAT
	CLRF	SSPSTAT;		SMP = 0, CKE = 0, clear status bits
	BSF	SSPSTAT, CKE;		CKE = 1
	banksel	SSPCON
	MOVLW	0x35		; Set up SPI port, Slave mode (SS), enable
	MOVWF	SSPCON		; Mode 3 (CKE = 1, CKP = 1)
				; (SMP cleared for slave mode)
	banksel	PIE1
	BSF	PIE1, SSPIE		; Enable SSP interrupt
	banksel	PIR1
	BCF	PIR1, SSPIF		; Clear interrupt flag
	; Should be ready to transmit
	RETURN


;
;	PWM_Init routine
;   --------------------------------------------------------------------
;   Routine to initialize PWM on the PIC
PWM_Init:
;	Ensure Bank 1
                BSF             STATUS, RP0
	BCF	STATUS, RP1
;	Disable PWM pin
                BSF             TRISC, TRISC5	; Set C5 to input
;	Set PWM Period
                MOVLW           0xE0
                MOVWF           PR2
;	Configure CCP for PWM
                BCF             STATUS, RP0	; Select bank 0
                MOVLW           0x0C	; Active High
                MOVWF           CCP1CON
;	Set PWM duty cycle
                MOVLW           0x00
                MOVWF           CCPR1L
;	Configure and start Timer2
                BCF             PIR1, TMR2IF	; Clear Timer2 interrupt flag
                BSF             T2CON, T2CKPS0	; Set Timer2 prescale value to 4
                BSF             T2CON, TMR2ON	; Turn Timer2 on
;	Enable PWM output after new PWM cycle started
PWM_Pt_1:	BTFSS           PIR1, TMR2IF
                GOTO            PWM_Pt_1
                BSF             STATUS, RP0	; Select bank 1
                BCF             TRISC, TRISC5	; Set C5 to output
	RETURN

PWM_ActiveHi:
	banksel	CCP1CON
	MOVLW	0x0C
	MOVWF	CCP1CON
	RETURN

PWM_ActiveLo:
	banksel	CCP1CON
	MOVLW	0x0E
	MOVWF	CCP1CON
	RETURN

;
;	Timer0_Init routine
;   --------------------------------------------------------------------
;   Routine to initialize Timer0 on the PIC
Timer0_Init:
	banksel	OPTION_REG
;	Set as timer
	BCF	OPTION_REG, T0CS
;	Set prescaler to WDT
	BSF	OPTION_REG, PSA
;	Clear the flag
	banksel	INTCON
	BCF	INTCON, T0IF
;	Enable the interrupt
	BSF	INTCON, T0IE
;	Reset the counter and flag
	MOVLW	Timer0Max
	MOVWF	Timer0Count
	MOVLW	Tmr0ServMax
	MOVWF	Tmr0ServCount
	CLRF	Timer0Flag
	RETURN

LED_Init:
	banksel	PORTA
	CLRF	PORTAghost
	BSF	PORTA, 0
	BSF	PORTAghost, 0
	banksel	TRISA
	BCF	TRISA, 0
	RETURN

HbridgeCtrlInit:
	CALL	PWM_Init
	banksel	PORTC
	BCF	PORTC, 4
	banksel	TRISC
	BCF	TRISC, TRISC4
	RETURN

Servo_Init:
	banksel	PORTA
	BCF	ServoPin
	banksel	TRISA
	BCF	TRISA, 1
	RETURN
	

;
;	Initialize routine.  
;   --------------------------------------------------------------------
Initialize:
;	Setup Clock
	CALL	Clock_Init
;	Setup Timer0
	CALL	Timer0_Init
;	Setup Hbridge control lines
	CALL	HbridgeCtrlInit
;	Setup SPI
	CALL	SPI_Init
;	Setup LEDs
	CALL	LED_Init
;	Setup Servo
	CALL	Servo_Init
;	Enable Interrupts
	banksel	INTCON
	BSF	INTCON, GIE
	BSF	INTCON, PEIE
	RETURN


;********************************************************************************	
;********************************************************************************
;	Main Loop
;   --------------------------------------------------------------------
;   Continuously loops and handles the program
;       Looks for a button press, looks for a received message on EUSART
;       If slave select raised transmits message or ack
;********************************************************************************
;********************************************************************************
Main:
	CALL	Initialize
	banksel	PORTA
;	Initialize starting values to neutral motor/rudder
	MOVLW	0x34
	MOVWF	ServoPulse
	SetPWMDuty	0x00
	banksel	PORTC
	BCF	PORTC, 4
;   This is the main loop, here we just do nothing, checking the timer0 flag
;      to control the LED.  All responses are handled in SPI interrupt
PNT_2:
	NOP
	CALL	CheckTimer0Flag
	GOTO	PNT_2




CheckTimer0Flag:
	banksel	PORTA
	BTFSS	Timer0Flag, 0
	RETURN
	BCF	Timer0Flag, 0
;	Toggle LED
	BTFSS	PORTAghost, 0
	GOTO	$+4
	BCF	PORTAghost, 0
	BCF	PORTA, 0
	RETURN
	BSF	PORTAghost, 0
	BSF	PORTA, 0
	RETURN

;
;	Interrupt Service Routine
;   ***********************************************************************
;   ***** The PIC's one and only ISR...  =(  ******************************
;   ***********************************************************************
Interrupt:
;	PUSH
	MOVWF	W_TEMP	; Copy W to TEMP register
	SWAPF	STATUS, W	; Swap status to be saved into W
	banksel	PORTA
	MOVWF	STATUS_TEMP	; Save status to STATUS_TEMP register
;	ISR
	banksel	PIR1
	BTFSC	PIR1, SSPIF
	CALL	SPI_Int
	BTFSC	INTCON, T0IF
	CALL	Timer0_Int
;	POP
	banksel	PORTA
	SWAPF	STATUS_TEMP, W	; Swap nibbles in STATUS_TEMP register
			; and place result into W
	MOVWF	STATUS	; Move W into STATUS register
			;   (sets bank to original state)
	SWAPF	W_TEMP, F	; Swap nibbles in W_TEMP and place result in W_TEMP
	SWAPF	W_TEMP, W	; Swap nibbles in W_TEMP and place result into W	
	RETFIE

;	SPI_Int
;   --------------------------------------------------------------------
;   ISR that receives/transmits from SPI, but primary purpose is to receive
SPI_Int:
	BCF	PIR1, SSPIF
	banksel	PORTA
	MOVF	SSPBUF, W	; WREG reg = contents of SSPBUF
	MOVWF	SPI_RXDATA	; Save in user RAM, if data is meaningful
	MOVF	SPI_TXDATA, W	; W reg = contents of TXDATA
	MOVWF	SSPBUF	; New data to xmit
	BTFSC	SPI_RXDATA, 1
	RETURN
;	Process the command
	BTFSC	SPI_RXDATA, 0
	GOTO	ServoDir
;	Motor speed command
;	   upper nibble holds 4 bits of motor speed information
	BTFSS	SPI_RXDATA, 7
	GOTO	BackwardsMot
;	Set means run "forwards"
ForwardsMot:	BCF	PORTC, 4
	MOVLW	0x80
	SUBWF	SPI_RXDATA, F
	RLF	SPI_RXDATA, F
	ANDLW	MotorSpeedMask
;	Divide by two
	RRF	SPI_RXDATA, F
	BCF	SPI_RXDATA, 7
	MOVF	SPI_RXDATA, W
	banksel 	CCPR1L
                MOVWF           CCPR1L	; Set new duty cycle
	CALL	PWM_ActiveHi
	RETURN
BackwardsMot:	BSF	PORTC, 4
	COMF	SPI_RXDATA, F
	MOVLW	0x80
	SUBWF	SPI_RXDATA, F
	RLF	SPI_RXDATA, F
	ANDLW	MotorSpeedMask
;	Divide by two
	RRF	SPI_RXDATA, F
	BCF	SPI_RXDATA, 7
	MOVF	SPI_RXDATA, W
	banksel	CCPR1L
	MOVWF	CCPR1L
	CALL	PWM_ActiveLo
	RETURN
;	Command to set the rudder
;	   upper nibble should hold 4 bits of direction information
ServoDir:
	RRF	SPI_RXDATA, F
	RRF	SPI_RXDATA, F
	RRF	SPI_RXDATA, F
	RRF	SPI_RXDATA, F
	MOVLW	0x0F
	ANDWF	SPI_RXDATA, W
	CALL	ServoTable
	MOVWF	ServoPulse
	RETURN

Timer0_Int:
	BCF	INTCON, T0IF
	banksel	PORTA
;	Check on the servo pulse width
	DECFSZ	Tmr0ServCount
	GOTO	Check
;	If the counter finished, set servo pin high
	BSF	ServoPin
	MOVLW	Tmr0ServMax
	MOVWF	Tmr0ServCount
	GOTO	Counter2
;	Check if the counter is equal to our pulsewidth
;	   if so, set the pin low
Check:
	MOVF	ServoPulse, W
	SUBWF	Tmr0ServCount, W 
	BTFSS	STATUS, Z
	GOTO	Counter2
	BCF	ServoPin
;	Check on our other counter
Counter2:
	DECFSZ	Timer0Count
	RETURN
;	If counter finished, set flag and reset counter
	BSF	Timer0Flag, 0
	MOVLW	Timer0Max
	MOVWF	Timer0Count
	RETURN

	END

pwm.h

SetPWMDuty	macro	duty
	banksel	CCPR1L
                MOVLW	duty
                MOVWF           CCPR1L
endm