;********************************************************
;
;	This is a program to run the PIC 16F877 or 16C77 
;	MPU to drive the Ultra Sonic board that was built 
;	for the 2000 Aerial Robotics Team.  
;	Port B will be used for the 6500 module drive, and the CCP1
;	pin for both echo signals.  Below is the pin out
;
;	PORTB...
;	0=INIT 1
;	1=BINH 1
;	2=BLNK 1
;	3=N/A
;	4=INIT 2
;	5=BINH 2
;	6=BLNK 2
;	7=N/A
;
;	CCP1=ECHO 1 and ECHO 2
;
;***********************************************************

;***** Program Hiarchie *********************
;
;	Initialization
;	Polling Routine
;		run mod 1
;		delay
;		transmit data of mod 1
;		run mod 2
;		delay
;		transmit data of mod 2
;	IntService
;		ECHO_RX
;		BINH running
;
;********************************************

	list P=PIC16C77, F=INHX8M, C=160, N=77, ST=OFF, MM=OFF, R=DEC, X=OFF
	#include P16C77.inc
;	this is the standard header file for 16c77
	list
	list
	__config(_CP_OFF & _PWRTE_ON & _XT_OSC & _WDT_OFF & _BODEN_OFF)

;***** Equates ******************************

Bank0Ram	equ	H'20'
MaxCount	equ	50

;***** Variables ***************************

	cblock	Bank0Ram
	MACRO_TEMP
	TEMP
	TIME1		;this is the low byte for the CCP1L
	TIME2		;this is the high byte for the CCP1H
	W_TEMP		;temp used in IntService
	STATUS_TEMP	;temp used in IntService
	FSR_TEMP	;temp used in IntService
	MASK		;used to set the right bit in PORTB
	Nibble1
	Nibble2
	Nibble3
	Nibble4

	endc

;***** Macro Definitions *******************

MOVLF	macro	literal,dest
	movlw	literal
	movwf	dest
	endm

MOVFF	macro	source,dest
	movf	source,W
	movwf	dest
	endm

DELAY	macro	time
	local 	Again
	movlw	time
	movwf	MACRO_TEMP
Again
	decfsz	MACRO_TEMP
	goto	Again
	endm

;*****	Vectors *********************************

	org	H'000'		;reset vectors
	goto	MainLine	;Branch past tables
	org	H'004'		;Interupt vector
	goto	IntService	;Branch to interupt service routine

;***** Tables ********************************************

;***** End of Table **************************************

;***** MainLine code *************************************

MainLine
	call Initial		;initialize everything
MainLoop
	call	FIRE_1		;fire the module 1
	MOVLF	7,TEMP
Delay1
	call 	LoopTime	;to wait 0.5 sec
	decfsz	TEMP,F		;dec the counter
	goto	Delay1
	call	CONVERT		;convert TIME1 and TIME2 to HEX ascii
	call	TRANSMIT	;transmit the data in Nibble1 - Nibble3

	call	FIRE_2		;fire module 2
	MOVLF	7,TEMP
Delay2
	call	LoopTime	;to wait 0.5 sec
	decfsz	TEMP,F		;dec the counter
	goto	Delay2
	call	CONVERT		;convert the data into ascii
	call	TRANSMIT	;transmit the data in TIME1 and TIME2

	goto	MainLoop


;***** Initial Sub ***********************************
;
;	this will initialize all of the ports and etc.

Initial
	bsf	STATUS,RP0	;set to Bank 1
	MOVLF	B'00000111',ADCON1	;setting all AD pins to digital I/O
	clrf	TRISA			;setting all port a to output	
	clrf	TRISB			;setting PORTB as out
	MOVLF	B'00000100',TRISC	;all port c output, CCP1 in
	MOVLF	B'11110000',TRISD	;all input for port d
	clrf	TRISE			;all output for port e
	MOVLF	249,PR2			;setting LoopTime time
	MOVLF	B'00000100',PIE1	;enable CCP1 interupt
	MOVLF	B'00000001',PIE2	;enable CCP2 interupt
	MOVLF	B'00100100',TXSTA	;setting the serial port info
	MOVLF	25,SPBRG		;setting baud rate generator to 9600
	bcf	STATUS,RP0		;setting to bank 0 ram
	MOVLF	B'01001101',T2CON	;setting up timer 2 for looptie
	MOVLF	B'00000000',T1CON	;setting up timer 1,
	MOVLF	B'00000101',CCP1CON	;capture on rising edge
	MOVLF	B'00001010',CCP2CON	;compare for CCP2, generate interupt
	clrf	PORTA
	clrf	PORTB
	clrf	PORTC
	clrf	PORTD
	clrf	PORTE
	MOVLF	B'10000000',RCSTA	;enable the serial port
	MOVLF	B'11000000',INTCON	;enable interupts
	
	return

;***** FIRE_1 subroutine *****************************
;
;	this is used to set up and fire module 1

FIRE_1
	MOVLF	H'E8',CCPR2L		;use CCP2 for BINH (Low 1ms)
	MOVLF	H'03',CCPR2H		;the high byte
	clrf	TMR1L			;clear the timer 1 low byte
	clrf	TMR1H			;clear the timer 1 high byte
	clrf	CCPR1L			;clear the record byte
	clrf	CCPR1H			;clear the high byte
	clrf	PORTB			;ready PORTB
	MOVLF	B'00000010',MASK	;used to xor into PORTB in INT sub
	bsf	PORTB,0			;set INIT 1
	bsf	T1CON,0			;start TIMER 1
	MOVLF	PIE1,FSR		;indirect addressing
	bcf	INDF,2			;disable CCP1 interupt
	call	T40			;delay for 40 us
	MOVLF	PIE1,FSR		;indirect addressing
	bsf	INDF,2			;reset interupts
;	bcf	PIR1,2			;make sure the CCP1IF is clear

;ECHO1_LOOKING
;	btfss	PIR1,2			;testing CCP1IF 
;	goto	ECHO1_LOOKING
;	bcf	T1CON,0			;stop the timer
;	MOVFF	CCPR1L,TIME1		;save the low time
;	MOVFF	CCPR1H,TIME2		;save the high time
;	call	LoopTime		;delay for 10 ms
;	clrf	PORTB			;clear all PORTB
	return

;***** FIRE_2 subroutine *****************************
;
;	this is used to set up and fire module 2

FIRE_2
	MOVLF	H'E8',CCPR2L		;use CCP2 for BINH (Low 1ms)
	MOVLF	H'03',CCPR2H		;the high byte
	clrf	TMR1L			;clear the timer 1 low byte
	clrf	TMR1H			;clear the timer 1 high byte
	clrf	CCPR1L			;clear the record byte
	clrf	CCPR1H			;clear the high byte
	clrf	PORTB			;ready PORTB
	MOVLF	B'00100000',MASK	;used to xor into PORTB in INT sub
	bsf	PORTB,4			;set INIT 2
	bsf	T1CON,0			;start TIMER 1
	MOVLF	PIE1,FSR		;indirect addressing
	bcf	INDF,2			;disable interupt
	call	T40			;delay for 40 us
	MOVLF	PIE1,FSR		;indirect addressing
	bsf	INDF,2			;reset interupts
;	bcf	PIR1,2			;make sure CCP1IF is clear
	
;ECHO2_LOOKING
;	btfss	PIR1,2			;testing CCP1IF 
;	goto	ECHO2_LOOKING
;	bcf	T1CON,0			;stop the timer
;	MOVFF	CCPR1L,TIME1		;save the low time
;	MOVFF	CCPR1H,TIME2		;save the high time
;	call	LoopTime		;delay for 10 ms
;	clrf	PORTB			;clear all PORTB
	return
	
;***** TRANSMIT subroutine ***************************
;
;	this is used to send the data that is stored in
;	TIME1 (low byte) and TIME2 (high byte) out the 
;	serial port.

TRANSMIT
	btfss	PIR1,4			;testing to see if TXREG is clear
	goto	TRANSMIT		;if not keep looking

	MOVFF	Nibble4,TXREG		;send the first nibble
CHECKING1
	btfss	PIR1,4			;test to see if done
	goto	CHECKING1		;if not

	MOVFF	Nibble3,TXREG		;send the second nibble
CHECKING2
	btfss	PIR1,4			;test to see if done
	goto	CHECKING2		;if not

	MOVFF	Nibble3,TXREG
CHECKING25
	btfss	PIR1,4
	goto	CHECKING25

	MOVFF	Nibble2,TXREG		;send the third nibble
CHECKING3
	btfss	PIR1,4			;test to see if done
	goto	CHECKING3

	MOVFF	Nibble2,TXREG
CHECKING35
	btfss	PIR1,4
	goto	CHECKING35

	MOVFF	Nibble1,TXREG		;send the last nibble
CHECKING4
	btfss	PIR1,4			;test to see if done
	goto	CHECKING4

	MOVFF	Nibble1,TXREG
CHECKING45
	btfss	PIR1,4
	goto	CHECKING45

	MOVLF	H'0D',TXREG		;send a space
CHECKING5
	btfss	PIR1,4			;testing to see if done
	goto	CHECKING5

	MOVLF	H'0D',TXREG		;carrage return
CHECKING55
	btfss	PIR1,4
	goto	CHECKING55

	MOVLF	H'0A',TXREG		;new line
CHECKING6
	btfss	PIR1,4
	goto	CHECKING6

	MOVLF	H'0A',TXREG		;new line
CHECKING65
	btfss	PIR1,4
	goto	CHECKING65

	return

;***** CONVERT subroutine ******************************
;
;	this will convert the data in TIME1 (low byte)
;	and TIME2 (high byte) into ascii code for
;	Nibble1, Nibble2, Nibble3.

CONVERT
	MOVFF	TIME1,TEMP	;coping low time byte to temp
	movlw	B'00001111'
	andwf	TEMP,F
	movlw	10
	subwf	TEMP,W		;TEMP-W=W
	btfss	STATUS,C	;test the carry bit
	goto	NUMBER_CASE
;   for letter case
	decf	TEMP,W
	andlw	B'00000111'	;keep that last 3 bits
	addlw	B'01000000'	;adding in the high set
	goto	FirstDone
NUMBER_CASE
	movf	TEMP,W
	addlw	B'00110000'
FirstDone
	movwf	Nibble1		;copy the value to Nibble1
	
	MOVFF	TIME1,TEMP
	swapf	TEMP,F		;time for the next nibble
	movlw	B'00001111'
	andwf	TEMP,F
	movlw	10
	subwf	TEMP,W
	btfss	STATUS,C
	goto	NextNumber
	decf	TEMP,W
	andlw	B'00000111'
	addlw	B'01000000'
	goto	SecondDone
NextNumber
	movf	TEMP,W
	addlw	B'00110000'
SecondDone
	movwf	Nibble2

	MOVFF	TIME2,TEMP	;coping low time byte to temp
	movlw	B'00001111'
	andwf	TEMP,F
	movlw	10
	subwf	TEMP,W		;W-TEMP=W
	btfss	STATUS,C	;test the carry bit
	goto	LastNumber
;   for letter case
	decf	TEMP,W
	andlw	B'00000111'	;keep that last 3 bits
	addlw	B'01000000'	;adding in the high set
	goto	ThirdDone
LastNumber
	movf	TEMP,W
	addlw	B'00110000'
ThirdDone
	movwf	Nibble3		;copy the value to Nibble3

	swapf	TIME2,W		;coping low time byte to temp
	movwf	TEMP
	movlw	B'00001111'
	andwf	TEMP,F
	movlw	10
	subwf	TEMP,W		;W-TEMP=W
	btfss	STATUS,C	;test the carry bit
	goto	VeryLastNumber
;   for letter case
	decf	TEMP,W
	andlw	B'00000111'	;keep that last 3 bits
	addlw	B'01000000'	;adding in the high set
	goto	ForthDone
VeryLastNumber
	movf	TEMP,W
	addlw	B'00110000'
ForthDone
	movwf	Nibble4		;copy the value to Nibble4

	return


;***** LoopTime subroutine ***************************
;
;	this will use timer2 to complete counting 10 mS

LoopTime
	btfss	PIR1,TMR2IF		;check to see if time is up
	goto	LoopTime
	bcf	PIR1,TMR2IF		;reset for next time
	return

;***** T40 subroutine ****************************
;
;	this will use up 40 us of time to ignore the 
;	noise on the echo line from the fireing.

T40
	MOVLF	40,TEMP		;a counter
HERE
	decfsz	TEMP,F		;dec the counter
	goto	HERE
	return


;***** Interupt service **************************
;
;	this is an interupt service

IntService
	movwf	W_TEMP		;saving W
	swapf	STATUS,W	;saving STATUS
	movwf	STATUS_TEMP
Poll
	btfsc	PIR1,CCP1IF	;testing to see if ECHO is here
	goto	ECHO_RX
	btfsc	PIR2,CCP2IF	;testing to see if compare is doen
	goto	SET_BINH
	
	swapf	STATUS_TEMP,W	;restore status
	movwf	STATUS
	swapf	W_TEMP,F	;restore W
	swapf	W_TEMP,W
	
	retfie

;***** ECHO_RX subroutine *************************
;
;	this is used to caputure the time when a echo is recieved.

ECHO_RX
	bcf	PIR1,CCP1IF		;clear the flag
	bcf	T1CON,0			;stop the timer
	MOVFF	CCPR1L,TIME1		;save the low time
	MOVFF	CCPR1H,TIME2		;save the high time
	call	LoopTime		;delay for 10 ms
	clrf	PORTB			;clear all PORTB
	goto	Poll

;***** SET_BINH subroutine ************************
;
;	this is used to set the bit masked in MASK to PORTB
;	basically to set the BINH

SET_BINH
	bcf	PIR2,CCP2IF	;clear the flag
	movf	MASK,W		;move mask to W
	xorwf	PORTB,F		;xor W into PORTB itself
	goto	Poll	

;***** End of all programs ***********************
	end
