; ******************************************************************************
;									       *
;       PJT1.ASM - PIC#1 (19200 BAUD 8 MHz)				       *
;									       *
;  Monitor pushbuttons: tune +, tune -, pgm, inc channel, scan;  send          *
;  frequency to RDAC; send frequency and channel to PIC#2.                     *
;									       *
; ******************************************************************************

	LIST            F=INHX8M
	PROCESSOR       16F84
;	RADIX           DEC

;
;  __CONFIG bits:
;
; 					B4:   CODE PROTECTION, 1=OFF
; 					B3:   POWER UP, 1=TIMED
; 					B2:   WDOG, 0=off, 1=ON
; 					B1-0: OSC SELECT, 01=XT, 11=RC
        __CONFIG        B'11001' 

	__IDLOCS	H'0001'

; ------------------------------------------------------

	include p16f84.inc
;
;     STATUS bit definitions
;
		#define	_C		STATUS,0
		#define	_Z		STATUS,2
;
;  Data memory for timers
;
TEMP1	EQU	0x17			; timer count 1 us
TEMP2	EQU	0x18			;             20 ms
TEMP3	EQU	0x19			;	      5 s
TEMP4	EQU	0x1a			; character temp
;
;  Data memory for serial receive
;
COUNT	EQU	0x1b			; # bits/serial character
TXREG	EQU	0x1c			; data to transmit
DELAY   EQU	0x1d			; delay between serial bits
;
CHN	EQU	0x0E			; Current channel
FREQ1	EQU	0x0F			; Current frequency LSB
FREQ2	EQU	0x10			; Current frequency MSB
RDAC0	EQU	0x11			; RDAC0 (low order) setting 
RDAC1	EQU	0x12			; RDAC1 (high order) setting
CALMD	EQU	0x13			; Calibration mode flags
FAST	EQU	0x14			; Button fast mode flags
INCDEC1	EQU	0x15			; Freq up/down increment LSB
INCDEC2	EQU	0x1e			;			 MSB
UDRATE	EQU	0x1f			; Up/down rate indicator
;
;  Frequency binary search variables
;
;  "I"s are the RDAC settings at the low, mid, and high frequencies
;
ILO0	EQU	0x20			; LS byte, low freq bounds counts
ILO1	EQU	0x21			; MS
IHI0	EQU	0x22			; LS byte, high freq bounds counts
IHI1	EQU	0x23			; MS
IMID0	EQU	0x24			; LS byte, mid freq bounds counts
IMID1	EQU	0x25			; MS
;
;  "F"s are the frequencies at the counts above.  When the RDAC is set to I,
;  the resulting frequency read is F:  FLO corresponds to ILO, etc.
;
FLO0	EQU	0x26			; LS byte, low freq
FLO1	EQU	0x27			; MS
FHI0	EQU	0x28			; LS byte, high freq
FHI1	EQU	0x29			; MS
FMID0	EQU	0x2A			; LS byte, mid frequency
FMID1	EQU	0x2B			; MS
;
;  Frequency to be found
;
TFREQ0	EQU	0x2C			; LS byte
TFREQ1	EQU	0x2D			; MS byte
FTMP0	EQU	0x2E
FTMP1	EQU	0x2F
FCRES	EQU	0x30			; Results:  1 is TFREQ < FMID, 2 is TFREQ > FMID
FCNPASS EQU	0x31			; # passes
;
;  Symbolic constants other than memory locations
;
CLOCKRATE	equ	.8000000	; clock rate MHz
BAUDRATE	equ	.19200		; baud rate
FCLK		equ	CLOCKRATE/4	; instruction rate
BAUDCONST	equ	((FCLK/BAUDRATE)/3-2)	; delay for 1 serial bit
DLY100US	equ	((.32*FCLK)/.1000000)	; tight loops for 100us wait

#define	_TX	PORTB,0			; Serial receive data port RB0
#define _GATE	PORTB,1			; Freq counter gate pulse port RB1
#define _INCCH  PORTB,3			; INCREMENT CHANNEL button RB3
#define _SCAN   PORTB,4			; SCAN button RB4  
#define _PGMCH  PORTB,5			; PROGRAM CHANNEL button RB5
#define _RDACS	PORTA,0			; RDAC chip select
#define _RDACLK	PORTA,1			; RDAC clock
#define _RDACD	PORTA,2			; RDAC serial data in
#define _CALGP	CALMD,0			; In gate pulse calibration mode
#define _CALTA	CALMD,1			; In tuning amp calibration mode
;
;  This can be confusing.  When RDAC counts go down, frequency goes up.  The
;  pushbuttons for the purposes of this program are named according to what
;  they cause the RDAC counts to do:  FREQ COUNTS DOWN causes RDAC counts to
;  go down, which in turn causes frequency to go up.
;
#define _FDOWN	PORTB,6			; FREQ COUNTS DOWN button RB6
#define _FUP	PORTB,7			; FREQ COUNTS UP button RB7

	ORG	0x2100			; EEPROM initialization:
	DE	0x4e,0x44		; Channel 0 LSB, MSB 17600
	DE	0xb1,0x44		;         1          17700
	DE	0x15,0x45		; 	  2	     17800
	DE	0x78,0x45		;	  3	     17900
	DE	0x82,0x45		;	  4	     17910
	DE	0x8c,0x45		;	  5	     17920
	DE	0x96,0x45		;	  6	     17930
	DE	0xa0,0x45		;	  7	     17940
	DE	0xdb,0x45		;	  8	     18000
	DE	0x3f,0x46		;	  9	     18100

	ORG     0
	GOTO	START

	ORG	4
;
;  Interrupt service
;
	INCF	FREQ2,1			; Each interrupt=256 timer counts
	BCF	INTCON,T0IF		; Clear TIM0 interrupt flag
	RETFIE				; Set global interrupt enable bit
; ---------------------------------------------------------

	;       SETUP

START   MOVLW   B'11111111'     	; PORT REGS TO DEFAULTS
	MOVWF   PORTB

	BSF     STATUS,RP0      	; OPTION & TRIS ARE HI REGS

	MOVLW   B'01100011'
	; B7:   RBPU   - ENABLE PORT B PULL-UP RES, 0=OFF
	; B6:   INTEDG - RB0 INT EDGE SEL 0=-VE
	; B5:   T0CS   - TMR0 SOURCE, 0=FOSC/4, 1=RA4 PIN
	; B4:   T0SE   - RA4CLK PIN EDGE SELECT, 0=+VE
	; B3:   PSA    - PRESCALE ASSIGN 0=TIMER, 1=WDG
	; B2-0: PS2-0  - PRESCALE RATE 111=256 FOR TIMER (=127 FOR WDT) was 101

	MOVWF   OPTION_REG

	MOVLW   B'00000000'
	MOVWF	INTCON			; DISABLE ALL INTERRUPTS

	MOVLW   B'11111110'     	; 0=OUTPUT; 1=INPUT:  Port B
	MOVWF   TRISB	
	MOVLW   B'00011000'     	; 0=OUTPUT; 1=INPUT:  Port A
	MOVWF	TRISA

	BCF     STATUS,RP0      	; BACK TO LO REGS

	BSF	_RDACS			; Clear RDAC chip select
	BCF	_TX
	CLRF	CHN			; CLEAR TEMP CHANNEL NUMBER
	CLRF	FREQ1
	CLRF	FREQ2
	CLRF	CALMD			; Clear calibration mode flags
	CALL	WT5S
	
RESTART	movlw	'T'			; Tell user we're ready
	call	XMITW
	movlw	'O'
	call	XMITW
	movlw	'K'
	call	XMITW
	movlw	0
	call	XMITW
;
;  Check buttons and flags:
;
;  _FUP		Increment RDAC setting (decrease frequency)
;  _FDOWN	Decrement RDAC setting (increase frequency)
;  _INCCH	Increment channel 
;  _PGMCH	Write current channel settings to EEPROM
;  _SCAN	Scan through channels
;  _FUP+_FDOWN	Enter gate pulse calibration mode
;
CHECK	BTFSC	_CALGP			; In gate pulse calibration mode?
	GOTO	CGP
	BTFSS	_FUP			; Check buttons, which are normally SET.
	GOTO	FUP			; UP - Increment RDAC, decrease frequency
	BTFSS	_FDOWN
	GOTO	FDOWN			; DOWN - Decrement RDAC, increase frequency
	BTFSS	_INCCH
	GOTO	STEP			; INC CH - Increment current channel #
	BTFSS	_PGMCH
	GOTO	PGMCH			; PGM CH - Program current channel
	BTFSS	_SCAN
	GOTO	SCAN			; SCAN - Step through channels

	CALL	FREQ			; If no buttons are set, measure and
	CALL	SENDR			; display current LO frequency.

	movlw	'T'
	call	XMITW
	movlw	' '
	call	XMITW
	movlw	' '
	call	XMITW
	movlw	0
	call	XMITW
	
	GOTO	CHECK

CKNXT	CALL	WT20M
	CALL	WT20M
	GOTO	CHECK
;
;  Step to next channel
;
STEP	CALL	INCCH
	MOVLW	'T'			; Indicate we're on a channel by
	CALL	XMITW			; displaying "*".
	MOVLW	'*'	
	CALL	XMITW
	MOVLW	0
	CALL	XMITW
	GOTO	CKNXT
;
;  Increment channel number
;
INCCH	CALL	WT5M			; Debounce INC CH key
	BTFSS	_INCCH
	GOTO	INCCH

	MOVF	CHN,W
	SUBLW	.9
	BTFSS	_Z
	GOTO	INCCH1
	MOVLW	0xFF
	MOVWF	CHN

INCCH1	INCF	CHN,F
	CALL	SENDC			; Tell PIC#2 to display channel #

	BCF	_C			; Get LS freq byte for this channel
	RLF	CHN,W			; from EEPROM
	CALL	READEE
	MOVWF	TFREQ0
	movwf	FREQ1

	BCF	_C			; Get MS byte
	RLF	CHN,W
	ADDLW	1
	CALL	READEE
	MOVWF	TFREQ1
	movwf	FREQ2
	call	SENDF
;	call	WT5S
	call	WT20M
	call	WT20M
	
;	CALL	SENDR			; Display raw frequency as RDAC settings
;
;  For now, try to find the RDAC settings associated with the frequency just
;  retrieved from EEPROM
;

	call	FINDF
	RETURN
;
;  Program current channel in EEPROM with current frequency
;
PGMCH	CALL	WT5M			; Debounce PGM CH key
	BTFSS	_PGMCH
	GOTO	PGMCH

	MOVF	FREQ1,W			; Low order byte
	MOVWF	TEMP1
	BCF	_C
	RLF	CHN,W
	CALL	WRITEE

	MOVF	FREQ2,W			; High order byte
	MOVWF	TEMP1
	BCF	_C
	RLF	CHN,W
	ADDLW	1
	CALL	WRITEE

	GOTO	CKNXT
;
;  READEE - Read EEPROM address in W, return value in W
;
READEE	MOVWF	EEADR
	BSF	STATUS,RP0
	BSF	EECON1,RD
	BCF	STATUS,RP0
	MOVF	EEDATA,0
	RETURN
;
;  WRITEE - Write TEMP1 into EEPROM address W
;
WRITEE	MOVWF	EEADR
	MOVF	TEMP1,W
	MOVWF	EEDATA
	BSF	STATUS,RP0	; Bank 1
	BCF	EECON1,EEIF
	BSF	EECON1,WREN	; Write enable EEPROM
	MOVLW	0x55		; Magic sequence
	MOVWF	EECON2
	MOVLW	0xAA
	MOVWF	EECON2
	BSF	EECON1,WR	; Begin write

WRITE1	BTFSS	EECON1,EEIF
	GOTO	WRITE1

	BCF	EECON1,EEIF	; Clear write interrupt flag
	BCF	EECON1,WREN
	BCF	STATUS,RP0	; Back to bank 0
	RETURN
;
;  Send channel number to PIC#2
;
SENDC	MOVLW	'C'		
	CALL	XMITW
	MOVF	CHN,W
	CALL 	XMITW
	RETURN
;
;  Increment current frequency RDAC setting, thereby decreasing the frequency.
;
FUP	BTFSS	_FDOWN			; Are both FUP & FDOWN pressed?
	GOTO	CAL_GP

	CLRF	UDRATE			; Clear increment rate and indicator.
	MOVLW	1
	MOVWF	INCDEC1
	CLRF	INCDEC2

FUPNXT1	MOVLW	'T'			; Display D# (since frequency is going
	CALL	XMITW			; down), where # is the increment rate
	MOVLW	'D'			; indicator.
	CALL	XMITW
	MOVF	UDRATE,W
	ADDLW	0x30
	CALL	XMITW
	MOVLW	0
	CALL	XMITW

FUPNXT2	BTFSS	_FDOWN			; Both FUP & FDOWN Pressed?  Enter
	GOTO	CAL_GP			; calibrate gate pulse mode.

	BTFSS	_INCCH			; FUP + INC CH pressed?  Increase
	GOTO	FUPNXT3			; rate increment.

	BTFSS	_SCAN			; FUP + SCAN pressed?  Decrease rate
	GOTO	FUPNXT4			; increment.

	MOVF	INCDEC1,W		; Increment RDAC
	ADDWF	RDAC0,F
	BTFSC	_C
	INCF	RDAC1,F
	MOVF	INCDEC2,W
	ADDWF	RDAC1,F
	CALL	RDAC
	CALL	FREQ
	CALL	SENDR

	BTFSC	_FUP			; UP key still pressed?
	GOTO	CKNXT			; No - wait for next key

	GOTO	FUPNXT2

FUPNXT3	CALL	WT5M			; Debounce INC CH key
	BTFSS	_INCCH
	GOTO	FUPNXT3

	MOVF	UDRATE,W
	SUBLW	.4
	BTFSC	_Z
	GOTO	FUPNXT2

	BCF	_C			; Multiply increment by 8
	RLF	INCDEC1,F
	RLF	INCDEC2,F
	BCF	_C
	RLF	INCDEC1,F
	RLF	INCDEC2,F
	BCF	_C
	RLF	INCDEC1,F
	RLF	INCDEC2,F
	INCF	UDRATE,F
	GOTO	FUPNXT1

FUPNXT4	CALL	WT5M			; Debounce SCAN key
	BTFSS	_SCAN
	GOTO	FUPNXT4

	MOVF	UDRATE,W
	BTFSC	_Z
	GOTO	FUPNXT2

	BCF	_C			; Divide increment by 8
	RRF	INCDEC2,F
	RRF	INCDEC1,F
	BCF	_C
	RRF	INCDEC2,F
	RRF	INCDEC1,F
	BCF	_C
	RRF	INCDEC2,F
	RRF	INCDEC1,F
	DECF	UDRATE,F
	GOTO	FUPNXT1
;
;  FUP + FDOWN turns on gate pulse calibration mode, causing "GP" to be
;  displayed.
;
CAL_GP	MOVLW	'T'			; Tell PIC#2 we're in gate pulse
	CALL	XMITW			; calibration mode.
	MOVLW	'G'
	CALL	XMITW
	MOVLW	'P'
	CALL	XMITW
	MOVLW	0
	CALL	XMITW
	BSF	_CALGP			; Set gate pulse calibration mode flag
	GOTO	CKNXT

CALGPX	CLRF	CALMD			; Exit all calibration modes.
	MOVLW	'T'
	CALL	XMITW
	MOVLW	'R'
	CALL	XMITW
	MOVLW	'E'
	CALL	XMITW
	MOVLW	'S'
	CALL	XMITW
	MOVLW	'T'
	CALL	XMITW
	MOVLW	'A'
	CALL	XMITW
	MOVLW	'R'
	CALL	XMITW
	MOVLW	'T'
	CALL	XMITW
	MOVLW	0
	CALL	XMITW
	CALL	WT5S
	MOVLW	'B'
	CALL	XMITW
	CALL	WT20M
	CALL	WT20M
	GOTO	RESTART
;
;  Gate pulse calibration functions.  Gate pulse calibration mode is entered
;  by pressing _FUP and _FDOWN simultaneously, setting flag _CALGP.  While
;  this flag is set, label CHECK transfers control to CGP.  While in gate
;  pulse calibration mode, controls are 
;
;  _FUP		increment gate pulse multiplier
;  _FDOWN	decrement gate pulse multiplier
;  _SCAN	exit gate pulse calibration mode
;  _PGMCH	Save (changed) gate pulse multiplier to EEPROM
;
CGP	BTFSS	_FUP			; N/C FUP pressed?
	GOTO	CGPUP			;    increase gate time
	BTFSS	_FDOWN			; N/C FDOWN pressed? 
	GOTO	CGPDN			;    decrease gate time
	BTFSS	_SCAN			; N/C SCAN pressed?
	GOTO	CALGPX			;    exit calibration mode
	BTFSS	_PGMCH			; N/C PGM CH pressed?
	GOTO	CGPPGM			;    save gate multiplier value in EEPROM
	GOTO	CKNXT

CGPDN	MOVLW	'g'			; Tell PIC#2 to decrease gate 
	CALL	XMITW			; pulse multiplier value.
	CALL	WT20M			; Causes "GP-" followed by the
	CALL	FREQ			; current frequency to be displayed.
	CALL	WT20M
	MOVLW	'T'
	CALL	XMITW
	MOVLW	'G'		
	CALL	XMITW		
	MOVLW	'P'
	CALL	XMITW
	MOVLW	'-'
CGPDN1	CALL	XMITW
	MOVLW	0
	CALL	XMITW
	GOTO	CKNXT

CGPUP	MOVLW	'G'			; Tell PIC#2 to increase gate 
	CALL	XMITW			; pulse multiplier value.
	CALL	WT20M			; Causes "GP+" followed by the
	CALL	FREQ			; current frequency to be displayed.
	CALL	WT20M
	MOVLW	'T'
	CALL	XMITW
	MOVLW	'G'			
	CALL	XMITW		
	MOVLW	'P'
	CALL	XMITW
	MOVLW	'+'
	GOTO	CGPDN1
	
CGPPGM	MOVLW	'W'			; Tell PIC#2 to save gate pulse
	CALL	XMITW			; multiplier in EEPROM.
	CALL	WT20M			; Allow 20ms/location to program
	CALL	WT20M
	MOVLW	'S'			; Displays "GPW" followed by the
	CALL	XMITW			; gate pulse multiplier value just
	CALL	WT20M			; saved to EEPROM.
	MOVLW	'T'
	CALL	XMITW
	MOVLW	'G'		
	CALL	XMITW		
	MOVLW	'P'
	CALL	XMITW
	MOVLW	'W'
	GOTO	CGPDN1
;
;  Decrement current frequency RDAC setting, thereby increasing frequency.
;
FDOWN	MOVLW	1			; Reset decrement rate and indicator
	MOVWF	INCDEC1
	CLRF	INCDEC2
	CLRF	UDRATE

FDNNXT1	MOVLW	'T'			; Send U# (since frequency is going up), 
	CALL	XMITW			; where # is the decrement rate
	MOVLW	'U'			; indicator.
	CALL	XMITW
	MOVF	UDRATE,W
	ADDLW	0x30
	CALL	XMITW
	MOVLW	0
	CALL	XMITW

FDNNXT2	BTFSS	_INCCH			; If INC CH pressed simulaneously,
	GOTO	FDNNXT3			; raise increment rate.

	BTFSS	_SCAN			; If SCAN pressed simultaneously,
	GOTO	FDNNXT4			; lower increment rate.

	MOVF	INCDEC1,W		; Decrease RDAC settings
	SUBWF	RDAC0,F
	BTFSs	_C
	DECF	RDAC1,F
	MOVF	INCDEC2,W
	SUBWF	RDAC1,F
	CALL	RDAC
	CALL	FREQ
	CALL	SENDR

	BTFSC	_FDOWN			; DOWN key still pressed?
	GOTO	CKNXT			; No - wait for next key

	GOTO	FDNNXT2

FDNNXT3	CALL	WT5M			; Debounce INC CH key
	BTFSS	_INCCH
	GOTO	FDNNXT3

	MOVF	UDRATE,W		; If we're not at maximum decrement
	SUBLW	.4			; rate, increase it.
	BTFSC	_Z
	GOTO	FDNNXT2

	BCF	_C
	RLF	INCDEC1,F
	RLF	INCDEC2,F
	BCF	_C
	RLF	INCDEC1,F
	RLF	INCDEC2,F
	BCF	_C
	RLF	INCDEC1,F
	RLF	INCDEC2,F

	INCF	UDRATE,F
	GOTO	FDNNXT1

FDNNXT4	CALL	WT5M			; Debounce SCAN key
	BTFSS	_SCAN
	GOTO	FDNNXT4

	MOVF	UDRATE,W		; If we're not at minimum decrement
	BTFSC	_Z			; rate, decrease it
	GOTO	FDNNXT2

	BCF	_C
	RRF	INCDEC2,F
	RRF	INCDEC1,F
	BCF	_C
	RRF	INCDEC2,F
	RRF	INCDEC1,F
	BCF	_C
	RRF	INCDEC2,F
	RRF	INCDEC1,F

	DECF	UDRATE,F
	GOTO	FDNNXT1
;
;  Step through all channels
;
SCAN	MOVLW	'T'			; Display "S", indicating we're in	
	CALL	XMITW			; the SCAN mode.
	MOVLW	'S'		
	CALL	XMITW
	MOVLW	0
	CALL	XMITW
	CALL	WT20M
	CALL	WT20M

SCAN0	CALL	INCCH
	BTFSC	_SCAN			; If SCAN is pressed again, stop
	GOTO	SCAN0			; scanning.

SCAN1	CALL	WT5M
	BTFSC	_SCAN
	GOTO	CKNXT
	GOTO	SCAN1
;
;  Send local oscillator frequency to PIC#2; 'F'LM, where L 
;  is LSB, M is MSB.  It is converted to tuned frequency for display 
;  by adding the intermediate frequency.
;
SENDF	MOVLW	'F'		
	CALL	XMITW
	MOVF	FREQ1,0
	CALL 	XMITW
	MOVF	FREQ2,0
	CALL 	XMITW
	RETURN
;
;  Send LO frequency to PIC#2 for display, as above.  The intermediate
;  frequency is not added, so the LO is displayed.
;
SENDL	MOVLW	'L'	
	CALL	XMITW
	MOVF	FREQ1,0
	CALL 	XMITW
	MOVF	FREQ2,0
	CALL 	XMITW
	RETURN
;
;  Send RDAC settings to PIC#2 for display:  'N'LM, where L is RDAC0,
;  M is RDAC1.
;
SENDR	MOVLW	'N'
	CALL	XMITW
	MOVF	RDAC0,0
	CALL	XMITW
	MOVF	RDAC1,0
	CALL	XMITW
	RETURN
;
;  Serial transmit contents of W register to PIC#2
;
XMIT	MOVWF	TXREG
	BSF	_TX			; send start bit
	MOVLW	BAUDCONST
	MOVWF	DELAY
	MOVLW	.9
	MOVWF	COUNT

TBDWT	DECFSZ	DELAY,F
	GOTO	TBDWT
	MOVLW	BAUDCONST
	MOVWF	DELAY
	DECFSZ	COUNT,F
	GOTO	TNXBIT

	BCF	_TX			; send stop bit
	MOVLW	BAUDCONST
	MOVWF	DELAY
WTSTOP	DECFSZ	DELAY,F
	GOTO	WTSTOP
	RETURN

TNXBIT	RRF	TXREG,F
	BTFSS	_C
	GOTO	SETHI
	BCF	_TX
	GOTO	TBDWT

SETHI	BSF	_TX
	GOTO	TBDWT
;
;  Transmit with extra 5ms wait
;
XMITW	CALL	XMIT
	CALL	WT5M
	RETURN
;
;  Time delay routines
;
WT100U	MOVLW	DLY100US		; 100 usec wait w/4MHz clock s/b .32
	MOVWF	TEMP1	
WT100UA	DECFSZ	TEMP1,1			; 1(2)us
	GOTO	WT100UA			; 2us
	RETURN		

WT20M   MOVLW	.200			; 20 ms wait s/b .200
	MOVWF	TEMP2
WT20A	CALL	WT100U
	DECFSZ	TEMP2,1
	GOTO	WT20A
	RETURN

WT5M	MOVLW	.50			; 5 ms wait s/b .50
	MOVWF	TEMP2
WT5MA	CALL	WT100U
	DECFSZ	TEMP2,1
	GOTO	WT5MA
	RETURN

WT5S	MOVLW	.250			; 5s wait s/b .250
	MOVWF	TEMP3
WT5SA	CALL	WT20M
	DECFSZ	TEMP3,1
	GOTO	WT5SA
	RETURN

WT100M  MOVLW	.5			; 100 ms wait s/b .5
	MOVWF	TEMP4
WT100MA CALL	WT20M
	DECFSZ	TEMP4,1
	GOTO	WT100MA
	RETURN
;
;  Count frequency.  The gate pulse on _GATE is normally clear.  Request
;  a gate pulse (nominally 100ms in duration) from PIC#2.  While the
;  gate pulse is high, the timer through 1/64 prescaler causes interrupts
;  every 256 timer counts, or every 256*64=16384 cycles of the signal
;  being counted.  Increment the high order byte of frequency on every
;  interrupt.  After the gate pulse goes back low, whatever remains in
;  the timer becomes the low order byte of frequency.  This two-byte
;  value is then 1/64 the number of input signal cycles over the gate
;  pulse period.  It is sent to PIC#2, which does the conversion to kHz
;  and displays the value.
;
FREQ	CLRF	FREQ1
	CLRF	FREQ2
	MOVLW	'P'
	CALL	XMIT			; send PIC#2 GATE PULSE request
FREQW	BTFSS	_GATE			; Wait for gate pulse to go high
	GOTO	FREQW

	CLRF	TMR0
	MOVLW	0xA0			; enable TIM0 interrupt	
	MOVWF	INTCON

FREQD	BTFSC	_GATE			; Wait for gate pulse to go low again.
	GOTO	FREQD
	CLRF	INTCON			; Disable interrupts.
	MOVF	TMR0,0			; Contents of timer are low order part
	MOVWF	FREQ1			; of frequency.
	CALL	WT20M
	CALL	SENDF
	CALL	WT20M

;	movlw	'T'
;	call	XMITW
;	movlw	'F'
;	call	XMITW
;	movlw	'R'
;	call	XMITW
;	movlw	0
;	call	XMITW
	RETURN
;
;  Get channel settings from EEPROM
;
GETCH	BCF	_C			; Multiply channel # by 2 to get EEPROM 
	RLF	CHN,0			; frequency slot (2 bytes wide).
	MOVWF	EEADR
	BSF	STATUS,RP0
	BSF	EECON1,RD
	BCF	STATUS,RP0		; EEDATA now contains freq LS byte
	MOVWF	FREQ1
	RLF	CHN,0
	ADDLW	1
	MOVWF	EEADR
	BSF	STATUS,RP0
	BSF	EECON1,RD
	BCF	STATUS,RP0		; EEDATA now contains freq MS byte
	MOVWF	FREQ2
	RETURN
;
;  Send both RDAC settings
;
RDAC	BCF	_RDACS			; Set chip select low
	BCF	_RDACD			; RDAC address MS bit (A1) always 0
	BSF	_RDACLK			; clock in A1
	BCF	_RDACLK
	BSF	_RDACLK			; clock in A0(=0) for RDAC0
	BCF	_RDACLK
	MOVF	RDAC0,0			; get RDAC0 setting
	CALL	RDACS			; send RDAC0 data bits

	BCF	_RDACS			; Set chip select low
	BCF	_RDACD			; RDAC address MS bit (A1) always 0
	BSF	_RDACLK			; clock in A1
	BCF	_RDACLK
	BSF	_RDACD		
	BSF	_RDACLK			; clock in A0(=1) for RDAC1
	BCF	_RDACLK
	MOVF	RDAC1,0			; get RDAC1 settings and fall through to send
					; data bits.
RDACS	MOVWF	TEMP4
	MOVLW	.8			; # data bits to move
	MOVWF	COUNT

RDACN	BCF	_RDACD
	RLF	TEMP4,1
	BTFSC	_C
	BSF	_RDACD
	BSF	_RDACLK
	BCF	_RDACLK
	DECFSZ	COUNT,1
	GOTO	RDACN	

	BSF	_RDACS			; Set chip select high
	RETURN
;
;  Find the RDAC setting which most nearly matches frequency TFREQ<0,1> using
;  a binary search.  FREQ increases with decreasing RDAC setting.
;
FINDF	CLRF	ILO0			; Initialize low RDAC setting to 0000
	CLRF	ILO1			; and high RDAC setting to FFFF.
	MOVLW	0xFF
	MOVWF	IHI0
	MOVWF	IHI1

	MOVLW	.16			; Max allowable passes (=log2 0xFFFF)
	MOVWF	FCNPASS

FINDF0	MOVF	ILO0,W			; Set RDACs to ILO and read the
	MOVWF	RDAC0			; frequency.
	MOVF	ILO1,W
	MOVWF	RDAC1
	CALL	RDAC
	CALL	FREQ			; Read frequency
	MOVF	FREQ2,W			; and save as FLO.
	MOVWF	FLO1
	MOVF	FREQ1,W
	MOVWF	FLO0

	MOVF	IHI0,W			; Set RDACs to IHI and read the
	MOVWF	RDAC0			; frequency.
	MOVF	IHI1,W
	MOVWF	RDAC1
	CALL	RDAC
	CALL	FREQ			; Read frequency
	MOVF	FREQ2,W			; and save as FHI.
	MOVWF	FHI1
	MOVF	FREQ1,W
	MOVWF	FHI0

	BCF	_C			; Clear carry for right shift
	RRF	ILO1,W
	MOVWF	FTMP1			; FTMP<0,1>=ILO<0,1>/2
	RRF	ILO0,W
	MOVWF	FTMP0

	BCF	_C
	RRF	IHI1,W
	MOVWF	IMID1			; IMED<0,1>=IHI<0,1>/2
	RRF	IHI0,W
	MOVWF	IMID0

	MOVF	FTMP0,W			; IMED<0,1>=IMED<0,1>+FTMP<0,1>
	ADDWF	IMID0,F
	MOVF	FTMP1,W
	BTFSC	_C
	INCFSZ	FTMP1,W
	ADDWF	IMID1,F

	MOVF	IMID0,W			; Set RDACS to IMID and read the
	MOVWF	RDAC0			; frequency corresonding to IMID,
	MOVF	IMID1,W			; the RDAC setting half way between
	MOVWF	RDAC1			; ILO and IHI.
	CALL	RDAC
	CALL	FREQ			; Read frequency
	MOVF	FREQ2,W			; and save as FMID.
	MOVWF	FMID1
	MOVF	FREQ1,W
	MOVWF	FMID0

	MOVF	FMID1,W			; Determine whether TFREQ is above or below FMID
	SUBWF	TFREQ1,W
	BTFSC	_Z
	GOTO	FINDF1
	BTFSC	_C
	GOTO	FNDFG

FNDFL	movlw	1			; TFREQ < FMID
	movwf	FCRES
	goto	FINDF3

FNDFG	movlw	2			; TFREQ > FMID
	movwf	FCRES
	goto	FINDF3

FINDF1	MOVF	FMID0,W			; TFREQ1 = FMID1, so check low order byte
	SUBWF	TFREQ0,W
	BTFSC	_Z
	GOTO	FNDFE
	BTFSC	_C
	GOTO	FNDFG
	GOTO	FNDFL

FNDFE
;	MOVLW	'T'			; TFREQ<0,1> = FMID<0,1>:  exact hit,
;	CALL	XMITW			; so we're done.  Indicate we're on
;	MOVLW	'*'			; channel by displaying "*".
;	CALL	XMITW
;	MOVLW	0
;	CALL	XMITW
	RETURN

FINDF3 	DECF	FCNPASS,F		; Decrement pass counter
	BTFSC	_Z			; if zero, we're done
	GOTO	FNDFE
FINDF4	BTFSC	FCRES,0			; We're not there yet:  do it again.
	GOTO	FNDFLL
	BTFSC	FCRES,1
	GOTO	FNDFGG

FNDFLL	MOVF	IMID0,W			; TFREQ < FMID so move IMID to ILO and try again.
	MOVWF	ILO0			; Remember: counts and freq move in opposite
	MOVF	IMID1,W			; directions.
	MOVWF	ILO1
	GOTO	FINDF0	

FNDFGG	MOVF	IMID0,W			; TFREQ > FMID so move IMID to IHI and try again.
	MOVWF	IHI0
	MOVF	IMID1,W
	MOVWF	IHI1
	GOTO	FINDF0

	END
