;-------------------------------------------------------------------- ; ; DOPPLER / COMPASS SERIAL INTERFACE PROGRAM ; FILENAME : DOPPLER2.asm ; REVISION DATE : 26 OCTOBER 2000 ; ; COPYRIGHT 2000 BOB SIMMONS / WB6EYV ; www.silcom.com/~pelican2 ; pelican2@silcom.com ; ;-------------------------------------------------------------------- ; ; SERIAL RS232 OUTPUT OF DOPPLER BEARING DATA / COMPASS HEADING DATA ; 1200 BAUD, 1 START BIT, 7 DATA BITS, NO PARITY, 2 STOP BITS ; ; OUTPUT DATA = ASCII DF BEARING, 3 DIGITS PER TRANSMISSION ; + ASCII COMPASS HDG, 3 DIGITS PER TRANSMISSION ; ; MESSAGE FORMAT : MODIFIED AGRELO DF ; BYTE 1 : "%" CHARACTER ( APRS "DF BEARING" IDENTIFIER ) ; BYTE 2 : BRGX100 RELATIVE ; BYTE 3 : BRGX10 RELATIVE ; BYTE 4 : BRGX1 RELATIVE ; BYTE 5 : "/" CHARACTER ; BYTE 6 : "7" CHARACTER ( RELATIVE SIGNAL QUALITY, 0-7 ) ; BYTE 8 : "/" CHARACTER ; BYTE 9 : HDGX100 MAGNETIC ; BYTE 10: HDGX10 MAGNETIC ; BYTE 11: HDGX1 MAGNETIC ; BYTE 12 : "CARRIAGE RETURN" ; ; DF BEARING OUTPUT IS "999" WHEN NO SIGNAL IS PRESENT ; COMPASS HEADING OUTPUT IS "999" IF COMPASS FAILS OR NOT INSTALLED ; ; USES PIC 16F84 uP ; 3.58 MHZ CRYSTAL CLOCK ; ; PIN 1 = RA2 = 360 BRG COUNTER RST INPUT ( 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 ; ; PIN 7 = RB1 = EOC INPUT FROM COMPASS ( END OF CALCULATION ) ; PIN 8 = RB2 = SS OUTPUT TO COMPASS ( SELECT SERIAL DATA ) ; PIN 10 = RB4 = SDO INPUT FROM COMPASS( SERIAL DATA OUTPUT ) ; PIN 11 = RB5 = P/C OUTPUT TO COMPASS ( POLL / CONTINUOUS ) ; PIN 12 = RB6 = SCLK OUTPUT TO COMPASS ( SERIAL CLOCK ) ; ; PIN 9 = RB3 = DIGIT STROBE OUTPUT ( TO DIGITAL DISPLAY BOARD ) ; ; 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, ALONG WITH COMPASS DATA AND OTHER ASCII CHARACTERS. ; ; TRANSMISSION OF THE MESSAGE FINISHES THE INTERRUPT ROUTINE, AND CPU ; CONTROL IS RETURNED TO THE "360 RESET" ROUTINE. ; ; BAUD RATE TIMING IS GENERATED WITH SOFTWARE TIMING LOOPS, SO IT ; IS SENSITIVE TO CRYSTAL OPERATING FREQUENCY. THE COMPASS ROUTINES ALSO ; USE THE BAUD RATE TIMER TO GENERATE A 10 MILLISECOND DELAY, SO CHANGES ; OF CRYSTAL OPERATING FREQUENCY OR BAUD RATE WILL AFFECT COMPASS ; OPERATION, AS WELL... ; ; COMPASS OPERATION IS MUCH SLOWER, SO IT IS "TIME SHARED" BETWEEN TWO ; "TASK GROUPS", TO PREVENT THE ( SLOW ) COMPASS SPEED FROM REDUCING ; THE SPEED OF DF DATA COMMUNICATIONS. EACH TIME THE CPU IS INTERRUPTED, ; ( AND SENDS A SERIAL RS232 MESSAGE ) IT ALSO EXECUTES ONE OF THESE ; TWO TASK GROUPS, DEPENDING ON THE CONTENTS OF A CONTROL FLAG. ; ; THE FIRST TASK GROUP "TRIGGERS" THE COMPASS, WHICH BEGINS THE COMPASS ; MEASUREMENT PROCESS... THIS CAN TAKE HUNDREDS OF MILLISECONDS, SO THE ; CPU DOES NOT "WAIT" FOR A RESULT... IT SETS THE CONTROL FLAG TO ; INDICATE THAT THE "NEXT TASK" WILL BE TO "LOOK FOR AN ANSWER" FROM ; THE COMPASS. THE CPU THEN "ABANDONS" THE COMPASS, AND PROCEEDS TO THE ; REMAINING TASKS FOR THE DF DATA PROCESSING, AND SERIAL RS232 ; MESSAGE TRANSMISSION. ; ; WHEN THE NEXT CPU INTERRUPT OCCURS, ( CALIB 1-SHOT TRIGGER AT PIN 6 ) ; THE INTERRUPT ROUTINE WILL ( NOW ) EXECUTE THE SECOND COMPASS ; "TASK GROUP", BECAUSE THE CONTROL FLAG NOW INDICATES THIS IS THE ; CORRECT ACTION TO TAKE. ; ; THE SECOND TASK GROUP EXAMINES THE COMPASS STATUS LINE ( EOC ) TO SEE ; IF A VALID COMPASS READING IS AVAILABLE. IF NOT, THE CPU DOES NOT ; "WAIT" FOR A RESULT... IT INCREMENTS A "TIMEOUT" COUNTER FOR THE ; COMPASS, AND THEN CHECKS THIS COUNTER TO SEE IF THE COMPASS HAS TAKEN ; TOO MUCH TIME TO PRODUCE A VALID RESULT... ; ; IF THE "TIMEOUT" COUNTER EXCEEDS THE MAXIMUM ALLOWED VALUE, THE COMPASS ; HAS FAILED, OR IS NOT INSTALLED, AND THE COMPASS HEADING DATA IS CHANGED ; TO "999" TO INDICATE A COMPASS FAILURE. THE "NEXT TASK" IS CHANGED ; TO "START A NEW COMPASS CALCULATION" AND THE CPU THEN PROCEEDS TO THE ; REMAINING DF AND RS232 TASKS. ; ; IF THE "TIMEOUT" COUNTER DOES NOT EXCEED THE MAXIMUM ALLOWED VALUE, NO ; ACTION IS TAKEN, AND THE CPU PROCEEDS TO THE REMAINING DF AND RS232 TASKS. ; ; INFO : THE "TIMEOUT" COUNTER IS INCREMENTED EACH TIME THE SECOND "TASK ; GROUP" IS EXECUTED... THIS WILL USUALLY HAPPEN SEVERAL TIMES BEFORE THE ; COMPASS CALCULATION IS COMPLETED, BECAUSE THE COMPASS CAN ONLY ; GENERATE 2 - 5 READINGS/SECOND, BUT THE DF CAN SEND 15 - 18 DF ; MESSAGES/SECOND. ; ; IF/WHEN VALID COMPASS DATA IS DETECTED, THE "TIMEOUT" COUNTER IS RESET TO ; ZERO, AND THE COMPASS DATA IS RETRIEVED BY "CLOCKING" IT OUT OF THE ; COMPASS, ONE BIT AT A TIME. THE DATA IS USED TO UPDATE THE COMPASS HEADING ; INFORMATION, WHICH IS TRANSMITTED OUT THROUGH THE RS232 PORT. THE "NEXT ; TASK" CONTROL FLAG IS THEN CHANGED TO "START A NEW COMPASS CALCULATION", ; AND THE CPU PROCEEDS TO THE REMAINING DF AND RS232 TASKS. ; ; IF THERE IS NO DF SIGNAL, THEN NO INTERRUPT TRIGGER WILL BE APPLIED TO ; PIN 6, AND NO RS232 MESSAGE WILL BE TRANSMITTED... IT IS NECESSARY TO ; GENERATE AN RS232 MESSAGE AT REGULAR TIME INTERVALS, REGARDLESS OF ; WHETHER OR NOT A DF SIGNAL IS PRESENT, SO THAT THE COMPASS DATA CAN BE ; UPDATED. ; ; TO ACHIEVE THIS, A TEST WAS ADDED TO THE "360 ROLLOVER" ROUTINE, ; WHICH WILL "FORCE" A MESSAGE TRANSMISSION AT REGULAR INTERVALS, EVEN IF ; NO DF DATA IS PRESENT. IF THIS "FORCED MESSAGE" EVENT OCCURS, THE DF ; BEARING DATA IS CHANGED TO "999" TO INDICATE THAT NO VALID DF DATA ; IS AVAILABLE. ; ; IN ORDER FOR THE COMPASS TO "WAKE UP" PROPERLY, (WHEN POWER IS APPLIED) ; ALL OF ITS INPUTS MUST BE DISCONNECTED FOR A FEW MILLISECONDS... TO ; ACHIEVE THIS, THE PIC CHIP "STARTS UP" WITH A 1/4 SECOND TIMING LOOP, ; WHICH DELAYS THE CONFIGURATION OF THE VARIOUS I/O PORT BITS FOR 1/4 ; SECOND OF TIME. DURING THIS TIME INTERVAL, THE ( POWER ON )"DEFAULT" ; CONDITION FOR ALL I/O PORTS = "INPUT" MODE. THIS IS A HIGH IMPEDANCE ; MODE, WHICH SEEMS TO SATISFY THE START-UP REQUIREMENTS OF THE COMPASS. ; ;-------------------------------------------------------------------- ; ; 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 ; WAITS 1/4 SECOND TO ALLOW COMPASS TO "WAKE UP" ; INITIALIZE THE VARIOUS REGISTERS AND I/O PORTS ; CPU PROCEEDS TO RESET ROUTINE WHEN DONE ; ;-------------------------------------------------------------------- ; ; WAIT 1/4 SECOND ( ALL I/O PINS = INPUT DURING THIS TIME ) ; 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 ) ; ; WAIT 1/4 SECOND FOR COMPASS TO WAKE UP ; ORG H'10' ; STARTUP MOVLW H'FF' ;START_UP DELAY TIME = 1/4 SEC MOVWF WAIT_HI ; MOVWF WAIT_LO ; STARTUP1 DECFSZ WAIT_LO,1 ; GOTO STARTUP1 ; DECFSZ WAIT_HI,1 ; GOTO STARTUP1 ; ; ; "TICKLE" THE PORTS ; CLRF PORTA ;A PORT CLRF PORTB ;B PORT ; ; SWITCH TO BANK 1 FOR ACCESS TO CONTROL REGISTERS ; BSF STATUS,5 ;SELECT BANK 1 FOR TRISA REG ; ; DEFINE THE PORT BITS ( INPUT OR OUTPUT ) ; 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 TRISB,1 ;COMPASS EOC = INPUT BSF TRISB,4 ;COMPASS SDO = INPUT ; ; DEFINE THE INTERRUPTS, PRESCALER, AND COUNTER CLOCK ; 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 ; ; INITIALIZE SOME VARIABLES ; BSF INTCON,4 ;ENABLE ZC DETECT INTERRUPT MOVLW H'07' ;INIT STROBE_COUNT MOVWF STROBE_COUNT; = 7 MOVLW D'100' ;FOR "FORCED" RS232 MESSAGE MOVWF FORCE ; = 100 ; ;-------------------------------------------------------------------- ; ; 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 )UNTIL INTERRUPTED, OR UNTIL LOOP COUNT = 100 ; ; IF LOOP COUNT = 100, THEN CPU "FORCES" A MESSAGE TRANSMISSION, TO ; UPDATE THE COMPASS INFORMATION ON THE DISPLAY OF THE HOST COMPUTER. ; THE DF BEARING IS CHANGED TO "999" IF THIS OCCURS, TO INDICATE THAT ; NO VALID DF DATA IS AVAILABLE. ( NO DF SIGNAL ) ; ;-------------------------------------------------------------------- ; 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 RESET4 ;IF NOT, CHECK FOR NO DF DATA ; ; 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 ; ; TEST ROUTINE TO CAUSE A "FORCED" RS232 MESSAGE ; IF CPU LOOPS 100 TIMES WITHOUT INTERRUPTION, "FORCE" A MESSAGE ; RESET4 DECFSZ FORCE,1 ;FORCE = FORCE - 1 GOTO RESET1 ;NOT 100 LOOPS YET, CONTINUE ; ; FORCE A MESSAGE ; BCF INTCON,7 ;DISABLE INTERRUPTS CALL INTERRUPT ;FORCE A MESSAGE MOVLW D'100' ;RESET THE INDEX TO 100 LOOPS MOVWF FORCE ; GOTO RESET1 ;ALL DONE, CONTINUE ; ;-------------------------------------------------------------------- ; ; 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 ) ; OR A MESSAGE WAS "FORCED" DUE TO NO DF SIGNAL ; ; FURTHER INTERRUPTS ARE AUTOMATICALLY DISABLED UNTIL THE GIE ; BIT IN INTCON REGISTER IS SET ( SEE "RESET3" ROUTINE ) ; ; 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 ; ; CHANGE PRESCALER TO DIV BY 256 ; 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 CMPTASK 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' IORWF BCDX1,1 ;CONVERT BCDX1 TO ACSX1 IORWF BCDX10,1 ;CONVERT BCDX10 TO ASC10 IORWF BCDX100,1 ;CONVERT BCDX00 TO ASCX100 GOTO CMPTASK ;COMPASS TASK ROUTINE ; ;-------------------------------------------------------------------- ; ; CMPTASK ROUTINE ; ; COMPASS TASK DECISION ROUTINE ; EXAMINES NEXT_TASK TO DETERMINE WHAT SHOULD BE DONE NEXT ; CMPTASK BTFSC NEXT_TASK,0 ;NEXT TASK = TASK 1 ? GOTO CMPSTART ;IF SO, START COMPASS MEASUREMENT GOTO DONE_YET ;OTHERWISE CHECK IF COMPASS = DONE YET ; ;-------------------------------------------------------------------- ; ;CMPSTART ROUTINE ; ;START A COMPASS READING ; ;TAKE POLL LOW ;WAIT FOR 10 mSEC ;TAKE POLL HI ;WAIT 10 mSEC ;MAKE NEXT_TASK = 2 ;JUMP TO HDGASC ;--------------------------------------------------------------------------- CMPSTART BCF PORTB,POLL ;START MEASUREMENT CALL TEN_MSEC ;WAIT 10 MSEC BSF PORTB,POLL ;PULSE ONLY CALL TEN_MSEC ;WAIT 10 MSEC MOVLW 2 ;NEXT_TASK = 2 MOVWF NEXT_TASK ; GOTO HDGASC ; ; ;-------------------------------------------------------------------- ; ;DONE_YET ROUTINE ; ;EXAMINE EOC ( END OF CONVERSION ) HIGH = CONV DONE ;IF EOC = HIGH THEN PROCEED TO GETHDG ( GET HEADING DATA ) ;OTHERWISE, INCREMENT CNVCOUNT ;CHECK IF CNVCOUNT = 10 ;IF CNVCOUNT <10, COMPASS NEEDS MORE TIME... SEND OLD HEADING ;IF CNVCOUNT = 1O, COMPASS HAS FAILED ; MAKE HEADING = "999" ( = FAILED COMPASS ) ; MAKE NEXT_TASK = 1 ( NEXT_TASK = CMPSTART ) ; MAKE CNVCOUNT = 0 ( TRY AGAIN ) ; PROCEED TO HDGASC ( SEND HDG = "999" ) ;--------------------------------------------------------------------------- ; ;EXAMINE EOC BIT ( END OF CONVERSION ) ; DONE_YET BTFSC PORTB,EOC ;MEASUREMENT DONE YET ? GOTO GETHDG ;IF SO, PROCEED ; ; CONVERSION NOT DONE, INCREMENT CNVCOUNT ; INCF CNVCOUNT,1 ;CNVCOUNT = CNVCOUNT + 1 ; ; CHECK IF CNVCOUNT = 10 ( = FAILED COMPASS, TOO LONG TO FINISH ) ; BTFSC CNVCOUNT,1 ;BIT 1 SET ? ( VALUE = 2 ) GOTO HDGASC ;IF NOT, XMIT OLD HEADING BTFSC CNVCOUNT,3 ;BIT 3 SET ? ( VALUE = 8 ) GOTO HDGASC ;IF NOT, XMIT OLD HEADING ; ; COMPASS HAS FAILED ; MAKE HEADING = "999" ; RESET CNVCOUNT TO ZERO ( = TRY AGAIN ) ; RESET NEXT_TAST TO 1 ( = START ANOTHER CONVERSION ) ; MOVLW 9 ;GET BCD 9 MOVWF HDGX100 ;HDGX100 = 9 MOVWF HDGX10 ;HDGX10 = 9 MOVWF HDGX1 ;HDGX1 = 9 MOVLW 0 ;GET 0 MOVWF CNVCOUNT ;RESET CNVCOUNT MOVLW 1 ;GET 1 MOVWF NEXT_TASK ;MAKE NEXT_TASK = START CONVERSION GOTO HDGASC ;TRANSMIT HEADING "999" ; ;-------------------------------------------------------------------- ; ; GETHDG ROUTINE ; GET THE COMPASS HEADING DATA ; ; MAKE NEXT_TASK = 1 ( START ANOTHER CONVERSION ) ; MAKE CNVCOUNT = 0 ( RESET TO ZERO ) ; WAIT 10 MSEC ; ENABLE THE COMPASS OUTPUT ; WAIT 10 MORE MSEC ; CLEAR OUT THE PREVIOUS DATA ; THROW AWAY FIRST 6 BITS ( = NOT USED ) ; READ HDGX100 DATA ; READ HDGX10 DATA ; READ HDGX1 DATA ; PROCEED TO COMPDONE ROUTINE WHEN DONE ; ;-------------------------------------------------------------------- ; ; MAKE NEXT_TASK = 1 ; MAKE CNVCOUNT = 0 ; GETHDG MOVLW 1 ;GET 1 MOVWF NEXT_TASK ;NEXT TASK = START NEW CONVERSION MOVLW 0 ;GET 0 MOVWF CNVCOUNT ;RESET CNVCOUNT FOR NEW MEASUREMENT ; ; WAIT 10 MILLISECONDS ; ENABLE THE COMPASS SERIAL PORT ; WAIT 10 MORE MILLISECONDS ; CALL TEN_MSEC ;WAIT 10 MSEC BCF PORTB,SS ;ENABLE THE SERIAL OUTPUT CALL TEN_MSEC ;WAIT 10 MSEC ; ; CLEAR OUT THE OLD HEADING ; GETHDG1 CLRF HDGX100 ;CLEAR BCD X100 CLRF HDGX10 ;CLEAR BCD X10 CLRF HDGX1 ;CLEAR BCD X1 ; ; FIRST 6 BITS ARE NOT USED ; GETHDG2 CALL GETBIT ;THROW AWAY BIT 0 CALL GETBIT ;THROW AWAY BIT 1 CALL GETBIT ;THROW AWAY BIT 2 CALL GETBIT ;THROW AWAY BIT 3 CALL GETBIT ;THROW AWAY BIT 4 CALL GETBIT ;THROW AWAY BIT 5 ; ; GET BITS FOR HDG X100 ; GETX100 CALL GETBIT ;GET BCD X200 BIT MOVWF HDGX100 ;SAVE BIT CALL GETBIT ;GET BCD X100 BIT RLF HDGX100,1 ;MAKE ROOM FOR IT BCF HDGX100,0 ; IORWF HDGX100,1 ;SAVE IT ; ; GET BITS FOR HDG X10 ; GETX10 CALL GETBIT ;GET BCD X80 BIT RLF HDGX10,1 ;MAKE ROOM FOR IT BCF HDGX10,0 ; IORWF HDGX10,1 ;SAVE IT CALL GETBIT ;GET BCD X40 BIT RLF HDGX10,1 ;MAKE ROOM FOR IT BCF HDGX10,0 ; IORWF HDGX10,1 ;SAVE IT CALL GETBIT ;GET BCD X20 BIT RLF HDGX10,1 ;MAKE ROOM FOR IT BCF HDGX10,0 ; IORWF HDGX10,1 ;SAVE IT CALL GETBIT ;GET BCD X10 BIT RLF HDGX10,1 ;MAKE ROOM FOR IT BCF HDGX10,0 ; IORWF HDGX10,1 ;SAVE IT ; ; GET BITS FOR HDG X1 ; GETX1 CALL GETBIT ;GET BCD X8 BIT RLF HDGX1,1 ;MAKE ROOM FOR IT BCF HDGX1,0 ; IORWF HDGX1,1 ;SAVE IT CALL GETBIT ;GET BCD X4 BIT RLF HDGX1,1 ;MAKE ROOM FOR IT BCF HDGX1,0 ; IORWF HDGX1,1 ;SAVE IT CALL GETBIT ;GET BCD X2 BIT RLF HDGX1,1 ;MAKE ROOM FOR IT BCF HDGX1,0 ; IORWF HDGX1,1 ;SAVE IT CALL GETBIT ;GET BCD X1 BIT RLF HDGX1,1 ;MAKE ROOM FOR IT BCF HDGX1,0 ; IORWF HDGX1,1 ;SAVE IT GOTO CMPDONE ; ;-------------------------------------------------------------------- ; ; GETBIT SUBROUTINE ; ; GET ONE BIT OF HEADING DATA ; WAIT A SMALL TIME INTERVAL ; TAKE SCLK LO ; WAIT A SMALL TIME INTERVAL ; TAKE SCLK HI ; WAIT A VERY SMALL TIME INTERVAL ; READ SDO BIT ; MASK UNUSED BITS AND RETURN ; GETBIT MOVLW BIT_DELAY ;GET BIT DELAY MOVWF BIT_TIME ;SAVE IT GETBIT1 DECFSZ BIT_TIME,1 ;BIT_TIME = BIT_TIME - 1 GOTO GETBIT1 ;LOOP IF NOT DONE BCF PORTB,SCLK ;CLOCK = LO MOVLW BIT_DELAY ;GET BIT DELAY MOVWF BIT_TIME ;SAVE IT GETBIT2 DECFSZ BIT_TIME,1 ;BIT_TIME = BIT_TIME - 1 GOTO GETBIT2 ;LOOP IF NOT DONE BSF PORTB,SCLK ;CLOCK = HI NOP ;GIVE IT A LITTLE TIME NOP ; NOP ; MOVF PORTB,0 ;GET PORT BYTE MOVWF IN_BUFFER ;SAVE IT RRF IN_BUFFER,1 ;MOVE BIT 4 TO BIT 0 RRF IN_BUFFER,1 ; RRF IN_BUFFER,1 ; RRF IN_BUFFER,1 ; MOVF IN_BUFFER,0 ;BACK TO W REG ANDLW H'01' ;BIT 0, ONLY RETURN ;DONE ; ;-------------------------------------------------------------------- ; ;CMPDONE ROUTINE ; ;TAKE SS HI ;WAIT 10 mSEC ;PROCEED TO HDGASC ROUTINE WHEN DONE ; CMPDONE BSF PORTB,SS ;DISABLE THE SERIAL OUTPUT CALL TEN_MSEC ;WAIT 10 MSEC GOTO HDGASC ;TRANSMIT NEW HEADING ; ;-------------------------------------------------------------------- ; ;TEN_MSEC SUBROUTINE ; ;PROVIDES 10 MILLISECONDS OF TIME DELAY ;REQUIRED BY COMPASS HARDWARE FOR VARIOUS OPERATIONS ; TEN_MSEC MOVLW MSEC_COUNT ;START VALUE FOR MSEC_DLY MOVWF MSEC_DLY ;SAVE IT IN MSEC_DLY TEN_MSEC_1 CALL BAUDTIMER1 ;WAIT 0.8 MILLISECONDS DECFSZ MSEC_DLY,1 ;DELAY = DELAY - 1 GOTO TEN_MSEC_1 ;LOOP IF NOT DONE RETURN ;OTHERWISE, RETURN ; ;-------------------------------------------------------------------- ; ; HDGASC ROUTINE ; ; CONVERT ALL 3 HDG DIGITS TO ASCII CHARACTERS ; ASCII CHARACTER = BCD DIGIT + HEX '30' ; HDGASC MOVLW H'30' ;ASCII = BCD + H'30' IORWF HDGX1,1 ;CONVERT BCDX1 TO ACSX1 IORWF HDGX10,1 ;CONVERT BCDX10 TO ASC10 IORWF HDGX100,1 ;CONVERT BCDX00 TO ASCX100 GOTO SERIAL ;READY TO SEND MESSAGE ; ;-------------------------------------------------------------------- ; ; SERIAL ROUTINE ; ; CPU ARRIVES HERE FROM HDGASC ROUTINE ; CALLS SEROUT SUBROUTINE ONCE FOR EACH CHARACTER ; OUTPUTS "%" CHARACTER ( START OF DF MESSAGE ) ; OUTPUT 3 ASCII DIGITS ( BCD X100, BCD X10, BCD X1 DEG RELATIVE ) ; OUTPUT A "/" CHARACTER ( FIELD DELIMITER ) ; OUTPUT A "7" CHARACTER ( SIG QUALITY 0-7 ) ; OUTPUT A "/" CHARACTER ( FIELD DELIMITER ) ; OUTPUT 3 ASCII DIGITS ( HDG X100, HDG X10, HDG X1 DEG MAGNETIC ) ; OUTPUT A CARRIAGE RETURN CHARACTER ( 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 "/" (= HEX 2F) TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE ; MOVE ASCII HDGX100 TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE ; MOVE ASCII HDGX10 TO OUTPUT BUFFER AND CALL "SEROUT" SUBROUTINE ; MOVE ASCII HDGX1 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 H'2F' ;= ASCII / MOVWF ASCOUT ;STORE IT CALL SEROUT ;SEND IT ; ;COMPASS DATA SENT HERE ; MOVF HDGX100,0 ;GET ASCII HDGX100 CHARACTER MOVWF ASCOUT ;STORE IN OUTPUT REGISTER CALL SEROUT ;OUTPUT IT MOVF HDGX10,0 ;GET ASCII HDGX10 CHARACTER MOVWF ASCOUT ;STORE IT IN OUTPUT REGISTER CALL SEROUT ;OUTPUT IT MOVF HDGX1,0 ;GET ASCII HDGX1 CHARACTER MOVWF ASCOUT ;STORE IT IN OUTPUT REGISTER CALL SEROUT ;OUTPUT IT ; ; END OF MESSAGE ; MOVLW H'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 MOVLW D'100' ;RESET THE INDEX TO 100 LOOPS MOVWF FORCE ; ; ; 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 ( = LOGIC 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 WAIT_HI EQU H'1A' ;START-UP TIME DELAY WAIT_LO EQU H'1B' ;START-UP TIME DELAY FORCE EQU H'1C' ;FORCED MESSAGE NEXT_TASK EQU H'1D' ;NEXT COMPASS TASK CNVCOUNT EQU H'1E' ;COMPASS TIMEOUT COUNTER HDGX100 EQU H'1F' ;COMPASS HEADING X100 HDGX10 EQU H'20' ;COMPASS HEADING X10 HDGX1 EQU H'21' ;COMPASS HEADING X1 BIT_TIME EQU H'22' ;COMPASS BIT TIMER IN_BUFFER EQU H'23' ;COMPASS DATA BUFFER MSEC_DLY EQU H'24' ;10 MSEC DELAY ; ; 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) POLL EQU 5 ;COMPASS POLL EOC EQU 1 ;COMPASS END OF CALCULATION SS EQU 2 ;COMPASS SERIAL SELECT SCLK EQU 6 ;COMPASS SERIAL CLOCK BIT_DELAY EQU H'0F' ;SLIGHT DELAY FOR COMPASS READ MSEC_COUNT EQU H'10' ;FOR 10 MSEC DELAY ; ;-------------------------------------------------------------------- ; ; END OF SOURCE CODE ; ;-------------------------------------------------------------------- END