; Bat frequency heterodyne counter
; 
; this version should remove redundant leading zeros
;
; last change: June 6, 1999
; Bertrik Sikken


CommonAnode	equ	1
CommonCathode	equ	2

DisplayType	equ	CommonCathode
DebugMode	equ	0			; set to 0 in final version !!!!


	if	DisplayType==CommonCathode
	messg	"Compiling for common cathode"
	else
	messg	"Compiling for common anode"
	endif

	if	DebugMode==1
	messg	"Warning: compiling for debugging !"
	endif


; !!!! make sure to change the following lines when
; !!!! using the PIC16F84 instead of PIC16C84

	list    p=16c84, r=DEC
	include p16c84.inc
	__fuses _WDT_OFF & _XT_OSC & _PWRTE_ON


; definition of hardware connection
#define pin_osc_gate    PORTB,0
#define pin_osc_in      PORTA,4
; PORTB 1-7 is connected to segments a-g
; PORTA 0-3 is connected to LED commons (RA0 to leftmost digit, RA3 to rightmost)



; definition of variables
	cblock 12
	count_hi
	count_lo
	temp1
	temp2
	dig1
	dig2
	dig3
	dig4
	muxcount
	mux_out
	hun_lsb
	dis_count
	int16_a
	int16_b
	int16_c_hi
	int16_c_lo
	int16_count
	templed7
	endc


init
	bsf     STATUS,RP0
; set tristate registers
	movlw   0			; all outputs for PORTB
	movwf   PORTB
	movlw   B'10000'		; RA4 is input, rest of PORTA is output
	movwf   PORTA
; set prescaler to 256, external, rising edge
	movlw   B'10100111'             
	movwf   TMR0
	bcf     STATUS,RP0

; program mainloop
main
	call    count_pulses
	call    convert_digits
	goto    main


;------------------------------------------
; led conversion lookup table


led7
; in:  number in W
; out: 7-seg code in W in format B'gfedcba0'
;	movwf   templed7
;	movlw   HIGH led7               ; protect against wrong page
;	movwf   PCLATH
;	movfw   templed7
	andlw   15
	addwf   PCL,f
; format B'abcdefg.'
	if	DisplayType==CommonCathode

	retlw   B'01111110'
	retlw   B'00001100'
	retlw   B'10110110'
	retlw   B'10011110'
	retlw   B'11001100'
	retlw   B'11011010'
	retlw   B'11111010'
	retlw   B'00001110'
	retlw   B'11111110'
	retlw   B'11011110'
	retlw	B'10000000'
	retlw	B'10000000'
	retlw	B'10000000'
	retlw	B'10000000'
	retlw	B'10000000'
	retlw	B'00000000'			; empty character

	else

	retlw	B'10000000'
	retlw	B'11110010'
	retlw	B'01001000'
	retlw	B'01100000'
	retlw	B'00110010'
	retlw	B'00100100'
	retlw	B'00000100'
	retlw	B'11110000'
	retlw	B'00000000'
	retlw	B'00100000'
	retlw	B'01111110'
	retlw	B'01111110'
	retlw	B'01111110'
	retlw	B'01111110'
	retlw	B'01111110'
	retlw	B'11111110'			; empty character

	endif	

led7end

	if	HIGH led7 != HIGH led7end
	error	"Warning: page overflow in table lookup!"
	endif



;------------------------------------------
; update digits
; each digit is lit for approx. 2.5 msec, so the total
; time spent is almost 10 msec

display
	if	DisplayType==CommonCathode
  		movlw   B'11111110'
	else
		movlw	B'00000001'
	endif

	movwf   mux_out
	movlw   dig1			; address of leftmost digit
	movwf   FSR

	movlw   4
	movwf   dis_count
dis_loop1
	movfw   mux_out			; activate common pin of LED
	movwf   PORTA

	if	DisplayType==CommonCathode
		bsf     STATUS,C        ; shift in 1
	else
		bcf	STATUS,C	; shift in 0
	endif

	rlf     mux_out,f		; set next common pin
	movfw   INDF
	call    led7
	movwf   PORTB
	incf    FSR,f			; set FSR to next digit

; delay for approx. 2.5 msec
	movlw   25
	movwf   temp2
dis_loop2
	movlw   19
	movwf   temp1
dis_loop3
	nop
	nop
	decfsz  temp1,f
	goto    dis_loop3
	decfsz  temp2,f
	goto    dis_loop2

	nop			; timing adjustment
	nop
	nop

	decfsz  dis_count,f
	goto    dis_loop1

	movfw	mux_out
	movwf	PORTA
	nop
	nop
	return


;------------------------------------------

; divides 15-bit number in int16_c by 7-bit int16_b into int16_a
; the remainder goes into int16_c_hi
divide
	movlw   8
	movwf   int16_count
div_loop
	rlf     int16_c_lo,f
	rlf     int16_c_hi,f
	movfw   int16_b
	subwf   int16_c_hi,w
	btfsc   STATUS,C
	movwf   int16_c_hi
	rlf     int16_a,f
	decfsz  int16_count,f
	goto    div_loop
	return

;------------------------------------------
; the following routine converts the 16-bit value
; in count_c_lo and count_c_hi into 4 decimal digits
; dig1 is the most significant digit
;
; leading zeros are converted to a special character

convert_digits
; divide count by 100
	movfw   count_lo
	movwf   int16_c_lo
	movfw   count_hi
	movwf   int16_c_hi
	movlw   100
	movwf   int16_b
	call    divide
; the remainder is used to find the 2 right digits
	movfw   int16_c_hi
	movwf   hun_lsb
; the ratio is used to find the 2 left digits
	movfw   int16_a
; now divide by 10 to find individual digits
	movwf   int16_c_lo
	clrf    int16_c_hi
	movlw   10
	movwf   int16_b
	call    divide
	movfw   int16_a
	movwf   dig1
	movfw   int16_c_hi
	movwf   dig2
	
	movfw   hun_lsb
	movwf   int16_c_lo
	clrf    int16_c_hi
	call    divide
	movfw   int16_a
	movwf   dig3
	movfw   int16_c_hi
	movwf   dig4

; remove leading zeros by converting them to a special character

	movlw	dig1
	movwf	FSR
	movlw	2
	movwf	temp1
rz_loop1
	movfw	INDF
	btfss	STATUS,Z
	goto	rz_end
	movlw	15			; empty character code
	movwf	INDF
	incf	FSR,f
	decfsz	temp1,f
	goto	rz_loop1
rz_end
	return



;------------------------------------------
; count pulses in a 10 msec period, this
; corresponds to the frequency in multiples of 100 Hz


count_pulses
; enable counting
	bsf     STATUS,RP0
	bsf     pin_osc_gate
	bcf     STATUS,RP0

; wait for first edge down

	if	DebugMode==0

c2w1    btfss   pin_osc_in
	goto    c2w1
c2w2    btfsc   pin_osc_in
	goto    c2w2

	endif


; reset timer & prescaler : start count
	clrf    TMR0

; refresh display during counting ...
	call    display

; close gate: stop counting
	bcf     pin_osc_gate
	bsf     STATUS,RP0
	bcf     pin_osc_gate			; make gate 0
	bcf     STATUS,RP0

; save count:
; the high 8 bits are in TMR0
	movfw   TMR0
	movwf   count_hi
; the low 8 bits are in the prescaler
; The contents of the prescaler can be read by stimulating
; the count input and determining when the prescaler overflows
; and causes TMR0 to change

	if	DebugMode==0

	clrf    count_lo
c2loop3
	bsf     pin_osc_gate			; stimulate input
	decf    count_lo,f
	bcf     pin_osc_gate
	movfw   count_hi			; check if TMR0 has changed
	subwf   TMR0,w
	btfsc   STATUS,Z
	goto    c2loop3

	endif


	return

	END
