SOURCE CODE


Here is the 16F84 source code for the program. This source code was updated on 31 May, to correct some flaws that caused the PIC chip to transmit some alphabetical characters, at some bearings. The polarity of the CALIB trigger pulse has also been reversed, so that the trigger can be taken from exactly the same source as the digital readout, to eliminate any differences between the two displayed values.

It was again updated on 26 October 2000, to correct a really dumb flaw in the ASCII output routine, which was only obvious when tested with the Palm display... The baud rate was also corrected, very slightly... see UPDATES for details.

;--------------------------------------------------------------------
;
; DOPPLER SERIAL INTERFACE PROGRAM
; FILENAME : DOPPLER.asm
; REVISION DATE : 26 OCTOBER 2000
;
;--------------------------------------------------------------------
;
; SERIAL RS232 OUTPUT OF DOPPLER BEARING DATA
; 1200 BAUD, 1 START BIT, 7 DATA BITS, NO PARITY, 2 STOP BITS
; OUTPUT DATA = ASCII BEARING, 3 DIGITS PER TRANSMISSION
; MESSAGE FORMAT : AGRELO DF ( APRS COMPATIBLE ) 
;	BYTE 1 : "%" CHARACTER ( APRS "DF BEARING" IDENTIFIER )  
;	BYTE 2 : BRGX100
;	BYTE 3 : BRGX10
;	BYTE 4 : BRGX1
;	BYTE 5 : "/" CHARACTER
;	BYTE 6 : "7" CHARACTER ( RELATIVE SIGNAL QUALITY, 0-7 ) 
;	BYTE 7 : "CARRIAGE RETURN"
;
; MESSAGE OUTPUT IS SQUELCHED WHEN NO SIGNAL IS PRESENT
;
; USES PIC 16F84 uP
; 3.58 MHZ CRYSTAL CLOCK
; PIN 1 = RA2 = 360 BEARING COUNTER RESET ( FROM MAIN PC BOARD )
; PIN 6 = RB0/INT = CALIB 1-SHOT INPUT ( FROM MAIN PC BOARD )
; PIN 3 = RA4/T0CKI = X720 CLOCK INPUT ( FROM DIVIDER BOARD )
; PIN 2 = RA3 = RS232 DATA OUTPUT
;
; GENERAL DESCRIPTION ;
;
; THE INTERNAL TMR0 ( = 8 BITS ) + TMR0 OVERFLOW BIT IN STATUS REGISTER
; ARE USED TOGETHER AS A 9 - BIT BINARY "SIGNAL BEARING" COUNTER. THE 
; CLOCK FOR TMR0 COMES FROM PIN 3, ( THROUGH THE PRESCALER, SET FOR 2:1
; DIVISION RATION ) AND IS GENERATED BY THE LS/TTL DIVIDER CIRCUITS ON 
; THE DIVIDER BOARD. CLOCK INPUT FREQUENCY =720X ANTENNA SCAN RATE
;
; TMR0 IS RESET TO ZERO WHENEVER PIN 1 GOES LOW, (= RA2) WHICH INDICATES
; THE DIVIDE-BY-16 CHIP ON THE MAIN BOARD HAS OVERFLOWED. (= 000 DEGREES)
;
; WHENEVER AN INTERRUPT PULSE IS DETECTED ON PIN 6, ( = CALIB 1-SHOT, 
; FROM THE MAIN BOARD ) THE NUMBER IN TMR0 IS "LATCHED"... THIS ( 9 BIT, 
; BINARY ) NUMBER REPRESENTS THE SIGNAL BEARING.
;
; THE NUMBER IS CONVERTED FROM 9-BIT BINARY INTO 3 DIGITS OF BCD DATA,
; THEN FURTHER CONVERTED TO ASCII CHARACTERS, AND TRANSMITTED OUT
; THROUGH PIN 2. A CARRIAGE RETURN CHARACTER ( 'CR' ) IS ADDED TO THE
; OUTPUT STRING.
;
; NO AVERAGING, ERROR CHECKING, OR OTHER PROCESSING IS PERFORMED ON
; THE TRANSMITTED DATA. 
;
;--------------------------------------------------------------------
;
; COLDSTART ROUTINE
;
; CODE EXECUTION BEGINS HERE AT POWER ON 
; 
;--------------------------------------------------------------------
		ORG 	H'00'		;COLDSTART ADDRESS
COLDSTART 	GOTO	STARTUP   	;JUMP AROUND INTERRUPT AREA
		ORG	H'04'		;INTERRUPT ADDRESS
		GOTO	INTERRUPT 	;JUMP OVER STARTUP ROUTINES 
;
;--------------------------------------------------------------------
;
; STARTUP ROUTINE
;
; CPU JUMPS HERE FROM COLDSTART ROUTINE
; NO SUBROUTINES ARE CALLED
; INITIALIZE THE VARIOUS REGISTERS AND I/O PORTS
; CPU PROCEEDS TO RESET ROUTINE WHEN DONE
;
;--------------------------------------------------------------------
;
; SWITCH BANK SELECT = 1 FOR ACCESS TO CTRL REGISTERS
; INIT "A" PORT, BIT 3 = OUTPUT ( FOR RS232 OUTPUT, PIN 2 )
; INIT "A" PORT, BIT 2 = INPUT ( FOR 360 RESET, PIN 1 )
; INIT "A" PORT, BIT 4 = INPUT ( FOR X720 CLOCK, PIN 3 )
; INIT "B" PORT, BIT 0 = INPUT ( FOR CALIB 1-SHOT, PIN 6 )
; INIT TMR0 = TRIGGER FROM PIN 3
; INIT TMR0 = POSITIVE EDGE TRIGGER
; INIT TMR0 = PRESCALER OUTPUT
; INIT PRESCALER RATIO = 2:1
; SWITCH BANK SELECT = 0 FOR MAIN PROGRAM 
; ENABLE ZC DETECT INTERRUPT
; INIT STROBE_COUNT = 7 ( FOR DIGITAL READOUT ONLY )
;
		ORG	H'10'		;
STARTUP		CLRF	PORTA		;A PORT, BIT 2 = RS232 OUT
;
; SWITCH TO BANK 1 FOR ACCESS TO CONTROL REGISTERS
;
		BSF	STATUS,5   	;SELECT BANK 1 FOR TRISA REG
		CLRF	TRISA		;INIT PORT A, = ALL OUTPUTS
		BSF	TRISA,2		;360 RESET = INPUT
		BSF	TRISA,4		;X720 CLOCK = INPUT
		CLRF	TRISB		;INIT PORT B = ALL OUTPUTS
		BSF	TRISB,0		;ZC DETECT = INPUT
		BSF	OPT,6		;ZC DETECT = RISING EDGE
		BSF	OPT,5		;COUNTER CLK = PIN 3
		BCF	OPT,4		;CLOCK = RISING EDGE
		BCF	OPT,3		;PRESCALER = ON
		BCF	OPT,0		;PRESCALER = 2:1
		BCF	OPT,1		;SAME
		BCF	OPT,2		;SAME	
;
; BACK TO BANK 0 FOR MAIN PROGRAM
;
		BCF	STATUS,5   	;BACK TO BANK 0
		BSF	INTCON,4   	;ENABLE ZC DETECT INTERRUPT
		MOVLW	H'07'		;INIT STROBE_COUNT
		MOVWF	STROBE_COUNT	; = 7
;
;--------------------------------------------------------------------
;
; RESET ROUTINE
;
; CPU ARRIVES HERE FROM STARTUP ROUTINE
; NO SUBROUTINES ARE CALLED
; CLEARS THE BEARING COUNTER AND ENABLES INTERRUPTS
; WHENEVER 74LS93 ON MAIN PC BOARD "OVERFLOWS" ( = 000 DEGREES )
; CPU REMAINS HERE ( LOOPS ENDLESSLY ) UNTIL INTERRUPTED
;
;--------------------------------------------------------------------
; WATCH "A" PORT, BIT 2 ( = PIN 1 ) FOR FALLING EDGE SIGNAL
; WHEN DETECTED, CHECK IF THIS ROUTINE WAS PREVIOUSLY INTERRUPTED
; IF SO, IGNORE IT... MIGHT BE A MISTAKE
; OTHERWISE, RESET TMR0 + OVERFLOW BIT AND ENABLE
; THE ZERO CROSSING INTERRUPT. ALSO RESET THE PRESCALER RATIO
; TO 2:1 FOR THE TMR0 REGISTER. ( = BEARING COUNTER )
;
; THIS ROUTINE WILL LOOP ENDLESSLY UNLESS INTERRUPTED BY A
; ZERO-CROSSING DETECT PULSE ON PIN 6. WHEN THE INTERRUPT IS
; PROCESSED, ( = MESSAGE TRANSMITTED ) CONTROL WILL RETURN HERE. 
;
; LOOK FOR FALLING EDGE SIGNAL ON PIN 1
;
RESET1		MOVF	PORTA,0		;GET PORT A DATA
		ANDLW	H'04'		;ONLY BIT 2
		XORWF	LAST,0		;LOOK FOR A CHANGE
		MOVWF	RESULT		;SAVE RESULT FOR BIT TEST
		BTFSS	RESULT,2   	;CHANGED IF BIT 2 = 1
		GOTO	RESET1		;LOOP IF NO CHANGE
		MOVF	PORTA,0		;GET THE NEW BYTE
		ANDLW	H'04'		;ONLY BIT 2
		MOVWF	LAST		;SAVE IT
		BTFSC	LAST,2		;CHANGED TO 0 ?
		GOTO	RESET1		;IF NOT, LOOP 
;
; FALLING EDGE SIGNAL WAS DETECTED ON PIN 1
; CHECK IF THIS ROUTINE WAS INTERRUPTED. ( "SKIP" BIT 0 = 1 )
; IF SO, THIS MIGHT BE A MISTAKE... CLEAR THE "SKIP" FLAG AND LOOP AGAIN
;
RESET2		BTFSS	SKIP,0		;INTERRUPTED ?
		GOTO	RESET3		;IF NOT, PROCEED
		BCF	SKIP,0		;CLEAR THE SKIP FLAG BIT
		GOTO 	RESET1		;LOOP ONCE MORE
;
; NOT A MISTAKE... PROCEED
; CLEAR THE BEARING COUNTER AND OVERFLOW BIT
; CLEAR THE LAST INTERRUPT AND RE-ENABLE IT
;
RESET3		CLRF	TMR0		;CLEAR TIMER REGISTER
		BCF	INTCON,2   	;CLEAR THE OVERFLOW BIT
		BCF	INTCON,1   	;CLEAR INTERRUPT FLAG BIT
		BSF	INTCON,7   	;ENABLE GIE BIT
		GOTO	RESET1		;LOOP TIL INTERRUPTED
;
;--------------------------------------------------------------------
;
; INTERRUPT ROUTINE
;
; CPU JUMPS HERE WHEN CALIB 1-SHOT GENERATES AN INTERRUPT
; NO SUBROUTINES ARE CALLED
; REGISTER CONTENTS ARE SAVED AND PRESCALER IS "SLOWED DOWN" TO
; PREVENT FURTHER CHANGES OF BEARING DATA
; CPU PROCEEDS TO STROBE ROUTINE WHEN DONE
;
;--------------------------------------------------------------------
; CALIB 1-SHOT TRIGGER WAS DETECTED AT B PORT, BIT 0 ( = PIN 6 )
;
; FURTHER INTERRUPTS ARE AUTOMATICALLY DISABLED UNTIL THE GIE 
; BIT IN INTCON REGISTER IS SET
;
; SAVE W AND STATUS REGISTER CONTENTS
; SWITCH PRESCALER RATIO FROM 2 TO 256
; PROCEED TO THE OUTPUT ROUTINES
;
;
INTERRUPT   	MOVWF	W_TEMP 		;SAVE W REGISTER CONTENTS
		SWAPF	STATUS,W   	;MOVE STATUS TO W REGISTER
		MOVWF	STATUS_TEMP   	;SAVE STATUS REGISTER
;
; SWITCH TO BANK 1 TO ACCESS THE OPTION REGISTER
;
		BSF	STATUS,5   	;GO TO BANK 1 FOR OPTION REG 
		BSF	OPT,2		;PRESCALER RATIO TO 256
		BSF	OPT,1		;SAME
		BSF	OPT,0		;SAME, PROCEED TO BINBCD
;
; SWITCH BACK TO BANK 0 FOR MAIN PROGRAM
;
		BCF	STATUS,5   	;BACK TO BANK 0
;
;--------------------------------------------------------------------
;
; STROBE ROUTINE
;
; CPU ARRIVES HERE FROM INTERRUPT ROUTINE
; NO SUBROUTINES ARE CALLED
; PROCEEDS TO BINBCD ROUTINE WHEN DONE
;
; THIS ROUTINE WAS ADDED ONLY FOR THE BENEFIT OF 
; THE DIGITAL READOUT OPTION... IT IS NOT NECESSARY 
; FOR THE SERIAL OUTPUT FUNCTION. IT GENERATES A STROBE
; PULSE FOR THE DATA LATCHES OF THE DIGITAL READOUT ONCE
; EVERY 7 ( RS232 ) "MESSAGES" 
; ( SLOWS DOWN THE DISPLAY UPDATE RATE TO PREVENT 
;   EXCESSIVE "JITTER" OF THE READOUT )
;
;-------------------------------------------------------------------
;
; DECREMENT STROBE_COUNTER
; CHECK IF STROBE_COUNTER = 0
; IF NOT, JUMP TO BINBCD ROUTINE
; OTHERWISE, RESET STROBE_COUNTER TO = 7
; AND GENERATE A STROBE PULSE ON RB3 ( = PIN 9 )
; THEN PROCEED TO BCDBIN ROUTINE  
;
STROBE		DECFSZ	STROBE_COUNT,1	;TIME TO STROBE ?
		GOTO 	BINBCD		;IF NOT, JUMP
		MOVLW	H'07'		;RESET STROBE_COUNT
		MOVWF	STROBE_COUNT	;SAME
		BSF	PORTB,3		;MAKE A PULSE
		NOP			;GIVE IT TIME
		NOP			;
		BCF	PORTB,3		;END PULSE
;
;--------------------------------------------------------------------
;
; BINBCD ROUTINE
;
; CPU ARRIVES HERE FROM STROBE ROUTINE
; EXAMINE THE 9-BIT BINARY NUMBER WHICH REPRESENTS SIGNAL BEARING
; CONVERT EACH BIT TO AN EQUIVALENT 3 DIGIT BCD NUMBER
; THIS ROUTINE CALLS THE SUM SUBROUTINE IF TESTED BIT = 1  
; CPU JUMPS TO MAXLIMIT WHEN DONE
;
;--------------------------------------------------------------------
;
; CHECKS EACH OF 9 BINARY BITS ( 8 TMR0 BITS + TMR0 "OVERFLOW" BIT ) 
; IF BIT = 0, SKIP TO NEXT BIT
; IF BIT = 1, STORE CORRESPONDING BCD DIGITS IN TEMPORARY REGISTERS 
; AND CALL THE SUM SUBROUTINE
;
; BEGIN BY CLEARING THE TOTAL REGISTERS. ( TOTAL = 000 ) 
; THE FIRST BIT DOES NOT CALL THE SUM SUBROUTINE, BECAUSE THERE IS 
; NOTHING ( = 000 ) IN THE TOTAL REGISTERS, AT THIS POINT. 
; TESTS FOR ALL OTHER BITS CALL THE SUM SUBROUTINE, IF TESTED BIT = 1
;
; CLEAR THE 3 BCD DIGIT "RESULT" REGISTERS 
;
BINBCD		MOVLW	0		;CLEAR W REGISTER
		MOVWF	BCDX100		;CLEAR BCD X100 BYTE
		MOVWF	BCDX10		;CLEAR BCD X10 BYTE
		MOVWF	BCDX1		;CLEAR BCD X1 BYTE
;
; CONVERT 2^8 BIT TO BCD DIGITS 2-5-6
; MOVE RESULT TO TOTAL
;
BIN2E8		BTFSS	INTCON,2   	;BIT 8 = 1 ?
		GOTO	BIN2E7		;IF NOT, JUMP
		MOVLW	BCD2		;LOAD BCD DIGIT 2
		MOVWF	BCDX100		;STORE IT IN BCD X100
		MOVLW	BCD5		;LOAD BCD DIGIT 5
		MOVWF	BCDX10		;STORE IT IN BCD X10
		MOVLW	BCD6		;LOAD BCD DIGIT 6
		MOVWF	BCDX1		;STORE IT IN BCD X1
		BCF	INTCON,2   	;RESET COUNTER OVERFLOW BIT
;
; CONVERT 2^7 BIT TO BCD DIGITS 1-2-8
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E7		BTFSS	TMR0,7		;BIT 7 = 1 ?
		GOTO	BIN2E6		;IF NOT, JUMP
		MOVLW	BCD1		;LOAD BCD DIGIT 1
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD2		;LOAD BCD DIGIT 2
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD8		;LOAD BCD DIGIT 8
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 1-2-8 TO TOTAL
;
; CONVERT 2^6 BIT TO BCD DIGITS 0-6-4
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E6		BTFSS	TMR0,6		;BIT 6 = 1 ?
		GOTO 	BIN2E5		;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD6		;LOAD BCD DIGIT 6
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD4		;LOAD BCD DIGIT 4
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-6-4 TO TOTAL
;
; CONVERT 2^5 BIT TO BCD DIGITS 0-3-2
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E5		BTFSS	TMR0,5		;BIT 5 = 1 ?
		GOTO	BIN2E4		;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD3		;LOAD BCD DIGIT 3
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD2		;LOAD BCD DIGIT 2
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-3-2 TO TOTAL
;
; CONVERT 2^4 BIT TO BCD DIGITS 0-1-6
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E4		BTFSS	TMR0,4		;BIT 4 = 1 ?
		GOTO	BIN2E3		;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD1		;LOAD BCD DIGIT 1
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD6		;LOAD BCD DIGIT 6
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-1-6 TO TOTAL
;
; CONVERT 2^3 BIT TO BCD DIGITS 0-0-8
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E3		BTFSS	TMR0,3		;BIT 3 = 1 ?
		GOTO	BIN2E2		;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD8		;LOAD BCD DIGIT 8
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-0-8 TO TOTAL
;
; CONVERT 2^2 BIT TO BCD DIGITS 0-0-4
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E2		BTFSS	TMR0,2		;BIT 2 = 1 ?
		GOTO	BIN2E1		;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD4		;LOAD BCD DIGIT 4
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-0-4 TO TOTAL
;
; CONVERT 2^1 BIT TO BCD DIGITS 0-0-2
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E1		BTFSS	TMR0,1		;BIT 1 = 1 ?
		GOTO	BIN2E0		;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD2		;LOAD BCD DIGIT 2
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-0-2 TO TOTAL
;
; CONVERT 2^0 BIT TO BCD DIGITS 0-0-1
; ADD RESULT TO TOTAL ( = CALL SUM1 )
;
BIN2E0		BTFSS	TMR0,0		;BIT 0 = 1 ?
		GOTO	MAXLIMIT   	;IF NOT, JUMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX100T   	;STORE IT IN BCD X100 TEMP
		MOVLW	BCD0		;LOAD BCD DIGIT 0
		MOVWF	BCDX10T		;STORE IT IN BCD X10 TEMP
		MOVLW	BCD1		;LOAD BCD DIGIT 1
		MOVWF	BCDX1T		;STORE IT IN BCD X1 TEMP
		CALL	BCDSUM1		;ADD 0-0-1 TO TOTAL
		GOTO 	MAXLIMIT   	;DONE, NEXT ROUTINE
;
;--------------------------------------------------------------------
;
; SUM SUBROUTINE
;
; CALLED BY BCDBIN ROUTINE IF TESTED BIT = 1
; CALLS NO SUBROUTINES
; ADDS 3 BCD DIGITS IN "TEMPORARY" REGISTERS TO 3 BCD "TOTAL" REGISTERS
; RESULT PLACED IN 3 BCD "TOTAL" REGISTERS
; RETURNS WHEN ALL 3 DIGITS ARE SUMMED TO "TOTAL"
;
;--------------------------------------------------------------------
;
; ADD BCDX1T TO BCDX1, PUT RESULT IN BCDX1
; CHECK IF CARRY TO BCDX10 WAS GENERATED AND DO IT ( IF REQUIRED )
; ADD BCDX10T AND BCDX10, PUT RESULT IN BCDX10
; CHECK IF CARRY TO BCDX100 WAS GENERATED AND DO IT ( IF REQUIRED )
; ADD BCDX100T TO BCDX100, PUT RESULT IN BCDX100
;  	
BCDSUM1		CLRW			;CLEAR W REGISTER
		ADDWF	BCDX1,0		;GET PREVIOUS BCD X1 ANSWER
		ADDWF	BCDX1T,0   	;ADD NEW PART
		MOVWF	BCDX1		;STORE RESULT
		ADDLW	OFLOW		;CHECK IF ANSWER < 10
		BTFSS	STATUS,DC   	;
		GOTO	BCDSUM10   	;IF ANSWER < 10, JUMP
		INCF	BCDX10,1   	;CARRY 1 TO NEXT DIGIT
		MOVLW	TEN		;SUBTRACT 10 FROM BCD X1 ANSWER
		SUBWF	BCDX1,1		;SAVE IT
BCDSUM10   	CLRW			;CLEAR W REGISTER
		ADDWF	BCDX10,0   	;GET PREVIOUS BCD X10 ANSWER
		ADDWF	BCDX10T,0   	;ADD NEW PART
		MOVWF	BCDX10		;STORE RESULT
		ADDLW	OFLOW		;CHECK IF ANSWER < 10
		BTFSS	STATUS,DC   	;
		GOTO	BCDSUM100   	;IF ANSWER < 10, JUMP
		INCF	BCDX100,1   	;CARRY 1 TO NEXT DIGIT
		MOVLW	TEN   		;SUBTRACT 10 FROM BCD X10 ANSWER
		SUBWF	BCDX10,1   	;SAVE IT
BCDSUM100   	CLRW			;CLEAR W REGISTER
		ADDWF	BCDX100,0   	;GET PREVIOUS BCD X100 ANSWER
		ADDWF	BCDX100T,0 	;ADD NEW PART
		MOVWF	BCDX100		;STORE RESULT
		RETURN			;DONE
;
;--------------------------------------------------------------------
;
; MAXLIMIT ROUTINE
;
; CPU JUMPS HERE FROM BINBCD ROUTINE
; NO SUBROUTINES ARE CALLED
; CHECKS IF RESULT = 360 ( OR GREATER )
; REPLACE RESULT WITH 000, IF TRUE
; CPU PROCEEDS TO BCDASC ROUTINE WHEN DONE 
;
;--------------------------------------------------------------------
;
; CHECK IF BCD X100 = 3
;
MAXLIMIT   	BTFSS	BCDX100,1   	; = XX1X ?
		GOTO 	BCDASC		;JUMP IF NOT
		BTFSS	BCDX100,0   	; = XXX1 ?
		GOTO	BCDASC		;JUMP IF NOT
;
; CHECK IF BCD X10 = 6
;
		BTFSS	BCDX10,2   	; = X1XX ?
		GOTO	BCDASC		;JUMP IF NOT
		BTFSS	BCDX10,1   	; = XX1X ?
		GOTO	BCDASC		;JUMP IF NOT
;
; BCD = 36X ( OR 37X ) ... REPLACE IT WITH 000
;
		CLRF	BCDX100		;CLEAR BCD X100
		CLRF	BCDX10		;CLEAR BCD X10
		CLRF	BCDX1		;CLEAR BCD X1
		GOTO	BCDASC		;DONE
;
;--------------------------------------------------------------------
;
; BCDASC ROUTINE
;
; CPU JUMPS HERE FROM BINBCD ROUTINE
; NO SUBROUTINES ARE CALLED
; CONVERTS 3 DIGITS OF BCD DATA TO CORRESPONDING ASCII CHARACTERS
; CPU PROCEEDS TO SERIAL ROUTINE WHEN DONE 
;
;--------------------------------------------------------------------
;
; CONVERT ALL 3 BCD DIGITS TO ASCII CHARACTERS
; ASCII CHARACTER = BCD DIGIT + HEX '30'
;
BCDASC		MOVLW	H'30'		;ASCII = BCD + H'30'
		ADDWF	BCDX1,1   	;CONVERT BCDX1 TO ACSX1
		ADDWF	BCDX10,1   	;CONVERT BCDX10 TO ASC10
		ADDWF	BCDX100,1   	;CONVERT BCDX00 TO ASCX100
		GOTO	SERIAL		;OUTPUT ASCII CHARACTERS 		
;
;--------------------------------------------------------------------
;
; SERIAL ROUTINE
;
; CPU ARRIVES HERE FROM "BCDASC" ROUTINE
; CALLS SEROUT SUBROUTINE ONCE FOR EACH CHARACTER
; OUTPUTS "%" CHARACTER ( COMPLY WITH APRS SPEC, = START OF DF MESSAGE )
; OUTPUT 3 ASCII DIGITS ( BCD X100, BCD X10, BCD X1 DEG RELATIVE ) 
; OUTPUT A "/" CHARACTER ( COMPLY WITH APRS SPEC, = FIELD DELIMITER )
; OUTPUT A "7" CHARACTER ( COMPLY WITH APRS SPEC, = SIG QUALITY 0-7 )
; OUTPUT A CARRIAGE RETURN CHARACTER ( COMPLY WITH APRS SPEC, = EOM )
; CPU PROCEEDS TO FINISH SUBROUTINE WHEN DONE 
;
;--------------------------------------------------------------------
;
; MOVE "%" (= HEX 25) TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE
; MOVE ASCII BCDX100 TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE
; MOVE ASCII BCDX10 TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE
; MOVE ASCII BCDX1 TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE
; MOVE "/" (= HEX 2F) TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE
; MOVE "7" (= HEX 37) TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE
; MOVE ASCII 'CR' TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE 
;
SERIAL		MOVLW	H'25'		;= ASCII %
		MOVWF	ASCOUT		;STORE IT
		CALL	SEROUT		;SEND IT
		MOVF	BCDX100,0   	;GET ASCII BCDX100 CHARACTER
		MOVWF	ASCOUT		;STORE IN OUTPUT REGISTER
		CALL 	SEROUT		;OUTPUT IT
		MOVF 	BCDX10,0   	;GET ASCII BCDX10 CHARACTER
		MOVWF	ASCOUT		;STORE IT IN OUTPUT REGISTER
		CALL 	SEROUT		;OUTPUT IT
		MOVF 	BCDX1,0		;GET ASCII BCDX1 CHARACTER
		MOVWF	ASCOUT		;STORE IT IN OUTPUT REGISTER
		CALL 	SEROUT		;OUTPUT IT
		MOVLW	H'2F'		;= ASCII /
		MOVWF	ASCOUT		;STORE IT
		CALL	SEROUT		;SEND IT
		MOVLW	H'37'		;= ASCII 7
		MOVWF	ASCOUT		;STORE IT
		CALL	SEROUT		;SEND IT
		MOVLW 	'0D'		;HEX 0D = CARRIAGE RETURN
		MOVWF	ASCOUT		;STORE IT IN OUTPUT REGISTER
		CALL 	SEROUT		;OUTPUT IT
;
;--------------------------------------------------------------------
;
; FINISH ROUTINE
;
; CPU ARRIVES HERE FROM SERIAL ROUTINE
; NO SUBROUTINES ARE CALLED
; SET "SKIP" BIT 0 TO IGNORE NEXT ANTENNA CYCLE
; RESTORES PRESCALER TO DIVIDE BY 2
; RESTORES CPU REGISTERS TO ORIGINAL CONDITION
;
; THIS IS THE FINAL ROUTINE IN THE INTERRUPT HANDLER...
; IT RETURNS EXECUTION TO MAIN PROGRAM WHEN DONE
;
;--------------------------------------------------------------------
;
FINISH		BSF	SKIP,0		; = IGNORE NEXT CYCLE
;
; SWITCH TO BANK 1 FOR ACCESS TO OPTION REGISTER
; CHANGE THE PRESCALER RATIO BACK TO DIVIDE BY 2
;
		BSF	STATUS,5      	;GO TO BANK 1 FOR OPTION REG 
		BCF	OPT,2		;PRESCALER RATIO = 2:1
		BCF	OPT,1		;SAME
		BCF	OPT,0		;SAME
;
; SWITCH BACK TO BANK 0 FOR MAIN PROGRAM
; RESTORE CPU REGISTERS AND RETURN
;
		BCF	STATUS,5   	;GO TO BANK 0 FOR MAIN PGM
		SWAPF	STATUS_TEMP,W	;RETRIEVE STATUS REGISTER
		MOVWF	STATUS		;RESTORE STATUS REGISTER
		SWAPF	W_TEMP,1   	;RESTORE W REGISTER
		SWAPF	W_TEMP,W   	;
		RETURN			;RETURN TO MAIN PROGRAM
;
;--------------------------------------------------------------------
; 
; SEROUT SUBROUTINE
;
; OUTPUTS A SINGLE ASCII CHARACTER
; CALLED BY SERIAL ROUTINE
; CALLS BAUD0 OR BAUD1 SUBROUTINE FOR EACH BIT
; RETURNS WHEN LAST STOP BIT IS OUTPUT
;
;--------------------------------------------------------------------
;
; OUTPUT A START BIT
;
SEROUT		CALL	BAUD0		;OUTPUT A START BIT
;
; OUTPUT ASCII BIT 1 ( = DATA BIT 0 )
;
		BTFSS	ASCOUT,0   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,0   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT ASCII BIT 2 ( = DATA BIT 1 )
;
		BTFSS	ASCOUT,1   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,1   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT ASCII BIT 3 ( = DATA BIT 2 )
;
		BTFSS	ASCOUT,2   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,2   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT ASCII BIT 4 ( = DATA BIT 3 )
;
		BTFSS	ASCOUT,3   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,3   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT ASCII BIT 5 ( = DATA BIT 4 )
;
		BTFSS	ASCOUT,4   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,4   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT ASCII BIT 6 ( = DATA BIT 5 )
;
		BTFSS	ASCOUT,5   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,5   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT ASCII BIT 7 ( = DATA BIT 6 )
;
		BTFSS	ASCOUT,6   	;ASCII BIT 0 = LOW ?
		CALL 	BAUD0		;YES, OUTPUT A 0 BIT
		BTFSC	ASCOUT,6   	;ASCII BIT 0 = HIGH ?
		CALL 	BAUD1		;YES, OUTPUT A 1 BIT
;
; OUTPUT A "NO PARITY" BIT ( = 0 ) FOR BIT 8
;
		CALL 	BAUD0		;OUTPUT A 0 BIT
;
; OUTPUT STOP BIT NO. 1
;
		CALL 	BAUD1		;OUTPUT STOP BIT 1
;
; OUTPUT STOP BIT NO. 2
;
		CALL 	BAUD1		;OUTPUT STOP BIT 2
		RETURN			;DONE WITH THIS CHARACTER
;--------------------------------------------------------------------
;
; BAUD0 AND BAUD1 SUBROUTINES
;
; CALLED BY SEROUT SUBROUTINE
; CALLS BAUDTIMER SUBROUTINE
; RETURNS WHEN BIT IS OUTPUT AND 1 BAUD OF TIME IS FINISHED
;
;--------------------------------------------------------------------
;
; THESE ARE THE ROUTINES THAT ACTUALLY TOGGLE THE RS232 OUTPUT PIN
; BAUD0 WILL OUTPUT A '0' BIT, THEN RETURN TO CALLING ROUTINE
; BAUD1 WILL OUTPUT A '1' BIT, THEN RETURN TO CALLING ROUTINE
;
BAUD0		BCF	PORTA,3		;MAKE OUTPUT BIT = 0
		CALL 	BAUDTIMER1	;DELAY FOR BAUD RATE
		RETURN			;DONE, RETURN
BAUD1		BSF	PORTA,3		;MAKE OUTPUT BIT = 1
		CALL 	BAUDTIMER1	;DELAY FOR BAUD RATE
		RETURN			;DONE
;--------------------------------------------------------------------
;
; BAUDTIMER SUBROUTINE
;
; PROVIDES TIME DELAY FOR 1 BIT OF OUTPUT DATA
; CALLED BY EITHER BAUD0 OR BAUD1 SUBROUTINES
; RETURNS WHEN TIME DELAY = FINISHED ( = 1 BAUD OF TIME )
;
;--------------------------------------------------------------------
;
BAUDTIMER1	MOVLW	DELAY		;TIME DELAY VALUE
		MOVWF	DELAYCNT   	;SAVE IT
BAUDTIMER2	DECFSZ	DELAYCNT,1   	;DECREMENT THE COUNTER
		GOTO	BAUDTIMER2	;LOOP IF NOT DONE
		RETURN			;OTHERWISE, RETURN
;
;--------------------------------------------------------------------
;
; END OF EXECUTABLE CODE
;
;--------------------------------------------------------------------
;
; LABEL DEFINITION AREA
;
;--------------------------------------------------------------------
;
; REGISTERS
;
PORTA		EQU	H'05'	;PORT A ADDRESS
PORTB		EQU	H'06'	;PORT B ADDRESS
TRISA		EQU	H'85'	;TRISA ADDRESS = PORT A CONTROL REG
TRISB		EQU	H'86'	;TRISB ADDRESS = PORT B CONTROL REG
OPT		EQU	H'81'	;OPTION REGISTER ADDRESS
INTCON		EQU	H'0B'	;INTCON REGISTER ADDRESS
TMR0		EQU	H'01'	;TIMER REGISTER ADDRESS
STATUS		EQU	H'03'	;STATUS REGISTER ADDRESS
BCDX100		EQU	H'0C'	;BCDX100 SUM "ANSWER"
BCDX10		EQU	H'0D'	;BCDX10 SUM "ANSWER"
BCDX1		EQU	H'0E'	;BCDX1 SUM "ANSWER"
BCDX100T   	EQU	H'0F'	;BCDX100 TEMPORARY ( NEXT TERM TO ADD ) 
BCDX10T		EQU	H'10'	;BCDX10 TEMPORARY ( NEXT TERM TO ADD )
BCDX1T		EQU	H'11'	;BCDX1 TEMPORARY ( NEXT TERM TO ADD )
ASCOUT		EQU	H'12'	;ASCII CHARACTER FOR OUTPUT
LAST		EQU	H'13'	;LAST VALUE OF 360 RESET INPUT
DELAYCNT   	EQU	H'14'	;REGISTER FOR BAUD RATE DELAY
RESULT		EQU	H'15'	;RESULT OF LAST 360 RESET COMPARISON
STATUS_TEMP	EQU	H'16'	;INTERRUPT STORAGE FOR STATUS REGISTER
W_TEMP		EQU	H'17'	;INTERRUPT STORAGE FOR W REGISTER
SKIP		EQU	H'18'	;SKIP FLAG REGISTER
STROBE_COUNT	EQU	H'19'	;COUNTER FOR DIGITAL READOUT ONLY
;
; NUMERIC CONSTANTS
;
DELAY		EQU	H'F0'	;CONSTANT (1200 BAUD DELAY)
BCD0		EQU	0	;CONSTANT
BCD1		EQU	1	;CONSTANT
BCD2		EQU	2	;CONSTANT
BCD3		EQU	3	;CONSTANT
BCD4		EQU	4	;CONSTANT
BCD5		EQU	5	;CONSTANT
BCD6		EQU	6	;CONSTANT
BCD7		EQU	7	;CONSTANT
BCD8		EQU	8	;CONSTANT
BCD9		EQU	9	;CONSTANT
ZERO		EQU	0	;CONSTANT
OFLOW		EQU	D'246'	;CONSTANT (BCD OVERFLOW TEST)
TEN		EQU	D'10'	;CONSTANT
DC		EQU	0	;BCD CARRY (STATUS REG BIT 0) 
;
;--------------------------------------------------------------------
;
; END OF SOURCE CODE
;
;--------------------------------------------------------------------
		END


[HOME PAGE][NEXT PAGE]