ÿþ<HTML> <HEAD> <TITLE>DOPPLER DF INSTRUMENTS/MICRO_SOURCE</TITLE> <META NAME="Description" Content ="Describes a homebuilt mobile Doppler D/F unit, with theory, schematics, parts list, and all PC artwork."> <META NAME="Keywords" Content ="doppler direction find, radio direction find, T-hunt, t-hunt, foxhunt, fox-hunt, search rescue, DF, df, RDF, rdf, radiolocation"> <META HTTP-EQUIV="REFRESH" content="0; url=http://www.silcom.com/~pelican2/PicoDopp/PICODOPP.htm"> <! AUTHOR : BOB SIMMONS > <! E-MAIL : PELICAN2@SILCOM.COM > <! CREATED : 9 MAY 2000 > <! UPDATED : 26 OCTOBER 2000 > <! FILENAME : MICRO_SOURCE.HTML > <! PURPOSE : SOFTWARE LISTINGS > <! KEYWORDS : DOPPLER DIRECTION FINDER DF> </HEAD> <BODY BGCOLOR="#D0D0FF" TEXT="#000000" LINK="#000000"> <BR><BR> <FONT FACE="Arial"> <B>SOURCE CODE</B><P><HR SIZE=2> 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. <P> 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. <P> <PRE> ;-------------------------------------------------------------------- ; ; 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 </PRE> <P><BR> [<A HREF="index.html">HOME PAGE</A>][<A HREF="MICRO_OBJECT.html">NEXT PAGE</A>] </BODY> </HTML>