;******************************************************************************
;                           FREQUENCY COUNTER
;                           Model  : WTCNT
;                           Author : Terry J. Weeder
;                           Date   : November 18, 1993
;                           Version: 1.0
;
;                           WWW.WEEDTECH.COM
;
;                           Ported to 16f84 by
;                           Peter Cousens 
;                           October  1998
;
;  
;******************************************************************************
;
;watchdog disabled
;
	list	P=16F84
ind	equ	0h
rtcc	equ	1h
pc	equ	2h
status	equ	3h
fsr	equ	4h
port_a	equ	5h
port_b	equ	6h
;port_c	equ	7h
c	equ	0h
dc	equ	1h
z	equ	2h
pd	equ	3h
to	equ	4h
MSB	equ	7h
LSB	equ	0h
;
cnt	equ	2h  
rs	equ	2h
rw	equ	1h
e	equ	0h
o	equ	7h
;
count1	equ	2ch
count2	equ	2dh
in_reg	equ	2eh 
addcnt	equ	2fh
gate	equ	0Ch
cnt1	equ	0Dh
cnt2	equ	0Eh
cnt3	equ	0Fh
calc1	equ	10h
calc2	equ	11h
calc3	equ	12h
sum1	equ	13h
sum2	equ	14h
sum3	equ	15h
rtcc2	equ	16h
;
	org	0
	goto	start
			
;
int_del	movlw	0x05		;delay 5.000 ms (4 MHz clock)
	movwf	count1
d1	movlw	0xA5
	movwf	count2
d2	decfsz	count2	,f
	goto	d2
	decfsz	count1	,f
	goto	d1
	retlw	0x00
;
lcd_out	movwf	port_b		;load data into port_b
	movlw	b'00000000'	;define port_b as output
	tris	port_b
	bsf	port_a,rs	;rs = data
	bcf	port_a,rw	;r/w = write
	bsf	port_a,e	;toggle enable
	bcf	port_a,e
	movlw	b'11111111'	;define port_b as input
	tris	port_b
	bcf	port_a,rs	;rs = instruction
	bsf	port_a,rw	;r/w = read
	bsf	port_a,e	;enable high
	movf	port_b,w	;get address counter
	movwf	addcnt
	bsf	addcnt,7
	bcf	port_a,e	;enable low
out1	bsf	port_a,e	;enable high
	btfss	port_b,7	;test busy flag
	goto	out2
	bcf	port_a,e	;enable low
	goto	out1
out2	bcf	port_a,e	;enable low
	goto	shift
;
inst	movwf	port_b		;load instruction into port_b
	movlw	b'00000000'	;define port_b as output
	tris	port_b
	bcf	port_a,rs	;rs = instruction
	bcf	port_a,rw	;r/w = write
	bsf	port_a,e	;toggle enable
	bcf	port_a,e
	movlw	b'11111111'	;define port_b as input
	tris	port_b
	bsf	port_a,rw	;r/w = read
inst1	bsf	port_a,e	;enable high
	btfss	port_b,7	;test busy flag
	goto	inst2
	bcf	port_a,e	;enable low
	goto	inst1
inst2	bcf	port_a,e	;enable low
	retlw	0x00
;
shift	btfss	addcnt,0	;shift to opposite side of display?
	retlw	0x00
	btfss	addcnt,1
	retlw	0x00
	btfss	addcnt,2
	retlw	0x00
	btfss	addcnt,3
	retlw	0x00
	movlw	0x39
	addwf	addcnt	,f
	bsf	addcnt,7
	movf	addcnt,w
	goto	inst
;
sub	bcf	status,o	;clear overflow bit
	movf	calc1,w		;subtract calc1 from cnt1 
	subwf	cnt1	,f
	btfsc	status,c
	goto	sb1
	movlw	0x01		;borrow from cnt2 if overflow
	subwf	cnt2	,f
	btfsc	status,c
	goto	sb1
	subwf	cnt3	,f		;borrow from cnt3 if cnt2 overflow
	btfss	status,c
	bsf	status,o	;set overflow bit if result is negative
sb1	movf	calc2,w		;subtract calc2 from cnt2
	subwf	cnt2	,f
	btfsc	status,c
	goto	sb2
	movlw	0x01		;borrow from cnt3 if cnt2 overflow
	subwf	cnt3	,f
	btfss	status,c
	bsf	status,o	;set overflow bit if result is negative
sb2	movf	calc3,w		;subtract calc3 from cnt3
	subwf	cnt3	,f
	btfss	status,c
	bsf	status,o	;set overflow bit if result is negative
	retlw	0x00
;
add	movf	calc1,w		;add calc1 to cnt1
	addwf	cnt1	,f
	btfss	status,c
	goto	ad1
	incfsz	cnt2	,f		;add to cnt2 if cnt1 overflow
	goto	ad1
	incf	cnt3	,f		;add to cnt3 if cnt2 overflow
ad1	movf	calc2,w		;add calc2 to cnt2
	addwf	cnt2	,f
	btfsc	status,c
	incf	cnt3	,f		;add to cnt3 if cnt2 overflow
	movf	calc3,w		;add calc3 to cnt3
	addwf	cnt3	,f
	retlw	0x00
;
cnvt	movlw	0x07		;7 digits in display
	movwf	count1
	movlw	0x19		;set fsr for MSB in display
	movwf	fsr
	movlw	0x2F		;one less that ASCII "0"
cnvt0	movwf	ind
	incf	fsr	,f
	decfsz	count1	,f
	goto	cnvt0
	movlw	0x0F		;load "1,000,000" in calc1-3
	movwf	calc3
	movlw	0x42
	movwf	calc2
	movlw	0x40
	movwf	calc1
cnvt1	call	sub		;subtract number from count
	incf	19	,f		;increment 1,000,000's register
	movlw	0x3A
	xorwf	19,w
	btfsc	status,z
	goto	overflow
	btfss	status,o	;check if overflow
	goto	cnvt1
	call	add		;add back last number
	movlw	0x01		;load "100,000" in calc1-3
	movwf	calc3
	movlw	0x86
	movwf	calc2
	movlw	0xA0
	movwf	calc1
cnvt2	call	sub		;subtract number from count
	incf	1A	,f		;increment 100,000's register
	btfss	status,o	;check if overflow
	goto	cnvt2
	call	add		;add back last number
	clrf	calc3		;load "10,000" in calc1-3
	movlw	0x27
	movwf	calc2
	movlw	0x10
	movwf	calc1
cnvt3	call	sub		;subtract number from count
	incf	1B	,f		;increment 10,000's register
	btfss	status,o	;check if overflow
	goto	cnvt3
	call	add		;add back last number
	movlw	0x03		;load "1,000" in calc1-3
	movwf	calc2
	movlw	0xE8
	movwf	calc1
cnvt4	call	sub		;subtract number from count
	incf	1C	,f		;increment 1,000's register
	btfss	status,o	;check if overflow
	goto	cnvt4
	call	add		;add back last number
	clrf	calc2		;load "100" in calc1-3
	movlw	0x64
	movwf	calc1
cnvt5	call	sub		;subtract number from count
	incf	1D	,f		;increment 100's register
	btfss	status,o	;check if overflow
	goto	cnvt5
	call	add		;add back number
	movlw	0x0A		;load "10" in calc1-3
	movwf	calc1
cnvt6	call	sub		;subtract number from count
	incf	1E	,f		;increment 10's register
	btfss	status,o	;check if overflow
	goto	cnvt6
	call	add		;add back last number
	movf	cnt1,w		;put remainder in 1's register
	addwf	1F	,f
	incf	1F	,f
	retlw	0x00
;
count	movlw	b'00110111'	;rtcc = ext, 1/256
	option
	movlw	b'00010000'	;define port_a as output 
	tris	port_a
	bcf	port_a,3
	bcf	port_a,2
	clrf	cnt3
	clrf	rtcc
	clrf	rtcc2
	bsf	port_a,2	;toggle rtcc pin
	bcf	port_a,2
	movf	gate,w		;get gate time
	movwf	count1
	bsf	port_a,3	;start count
fr4	movlw	0xFA
	movwf	count2
	goto	fr6
fr5	nop
	nop
	nop
	nop
	nop
	nop
fr6	movf	rtcc,w		;test for rtcc rollover (12)
	subwf	rtcc2	,f
	btfss	status,z
	goto	fr7
	nop
	goto	fr8
fr7	btfsc	status,c
	incf	cnt3	,f
fr8	movwf	rtcc2
	nop
	nop
	nop
	decfsz	count2	,f
	goto	fr5
	decfsz	count1	,f
	goto	fr4
	bcf	port_a,3	;stop count
	movf	rtcc,w		;get rtcc count
	movwf	cnt2
	subwf	rtcc2	,f		;test for rtcc rollover
	btfss	status,c
	goto	fr9
	btfss	status,z
	incf	cnt3	,f
fr9	clrf	cnt1		;set to get prescaler count
fr10	decf	cnt1	,f
	bsf	port_a,2	;toggle rtcc pin
	bcf	port_a,2
	movf	rtcc,w		;test if rtcc has changed
	xorwf	cnt2,w
	btfsc	status,z
	goto	fr10
	retlw	0x00
;
;******************************************************************************
;                                   START
;******************************************************************************
;
start	clrf	port_a		;instruction, write, enable low
	movlw	b'00010000'
	tris	port_a
	clrf	port_b
	movlw	b'00000000'
	tris	port_b
	call	int_del
	call	int_del
	call	int_del
	movlw	0x38		;initialize display
	movwf	port_b
	bsf	port_a,e	;toggle enable
	call	int_del
	bcf	port_a,e
	bsf	port_a,e	;toggle enable
	call	int_del
	bcf	port_a,e
	bsf	port_a,e	;toggle enable
	call	int_del
	bcf	port_a,e
	movlw	0x38		;function
	call	inst
	movlw	b'00001100'	;display on, cursor off
	call	inst
	movlw	b'00000001'	;clear display
	call	inst
	movlw	b'00000110'	;entry mode
	call	inst
;
mhz	movlw	0x14		;0.1 sec gate
	movwf	gate
	call	count
	call	cnvt		;convert binary to BCD
	movlw	0x30		;test if "0"
	xorwf	19,w
	btfss	status,z
	goto	mhz1
	movlw	0x30		;test if "0"
	xorwf	1A,w
	btfsc	status,z
	goto	khz1
mhz1	movlw	0x82		;set display address
	call	inst
	movlw	0x02		;output first 2 characters
	movwf	count1
	movlw	0x19		;MSD of freq
	movwf	fsr
mhz2	movlw	0x30		;test if "0"
	xorwf	ind,w
	btfss	status,z
	goto	mhz3
	movlw	0x20		;change preceeding "0's" to "space"
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	mhz2
	goto	mhz4
mhz3	movf	ind,w
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	mhz3
mhz4	movlw	0x2E		;"."
	call	lcd_out
	movlw	0x05		;output last 5 characters
	movwf	count1	
mhz5	movf	ind,w
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	mhz5
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x4D		;"M"
	call	lcd_out
	movlw	0x48		;"H"
	call	lcd_out
	movlw	0x7A		;"z"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	goto	mhz
;
khz	movlw	0x14		;0.1 sec gate
	movwf	gate
	call	count
	call	cnvt		;convert binary to BCD
	movlw	0x30		;test if 0
	xorwf	19,w
	btfss	status,z
	goto	mhz1
	movlw	0x32		;test if < 2
	subwf	1A,w
	btfsc	status,c
	goto	mhz1
	movlw	0x30		;test if "0"
	xorwf	1A,w
	btfss	status,z
	goto	khz1
	movlw	0x30		;test if "0"
	xorwf	1B,w
	btfsc	status,z
	goto	xkhz
khz1	movlw	0x82		;set display address
	call	inst
	movlw	0x05		;output first 5 characters
	movwf	count1
	movlw	0x19		;MSD of freq
	movwf	fsr
khz2	movlw	0x30		;test if "0"
	xorwf	ind,w
	btfss	status,z
	goto	khz3
	movlw	0x20		;change preceeding "0's" to "space"
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	khz2
	goto	khz4
khz3	movf	ind,w
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	khz3
khz4	movlw	0x2E		;"."
	call	lcd_out
	movf	ind,w		;output last 2 characters
	call	lcd_out
	incf	fsr	,f
	movf	ind,w
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x4B		;"K"
	call	lcd_out
	movlw	0x48		;"H"
	call	lcd_out
	movlw	0x7A		;"z"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	goto	khz
;
xkhz	movlw	0xC8		;1 sec gate
	movwf	gate
	call	count
	call	cnvt		;convert binary to BCD
	movlw	0x30		;test if 0
	xorwf	19,w
	btfss	status,z
	goto	khz
	movlw	0x32		;test if < 2
	subwf	1A,w
	btfsc	status,c
	goto	khz
	movlw	0x30		;test if 0
	xorwf	1A,w
	btfss	status,z
	goto	xkhz1
	movlw	0x30		;test if 0
	xorwf	1B,w
	btfsc	status,z
	goto	hz0
xkhz1	movlw	0x82		;set display address
	call	inst
	movlw	0x04		;output first 4 characters
	movwf	count1
	movlw	0x19		;MSD of freq
	movwf	fsr
xkhz2	movlw	0x30		;test if "0"
	xorwf	ind,w
	btfss	status,z
	goto	xkhz3
	movlw	0x20		;change preceeding "0's" to "space"
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	xkhz2
	goto	xkhz4
xkhz3	movf	ind,w
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	xkhz3
xkhz4	movlw	0x2E		;"."
	call	lcd_out
	movf	ind,w		;output last 3 characters
	call	lcd_out
	incf	fsr	,f
	movf	ind,w
	call	lcd_out
	incf	fsr	,f
	movf	ind,w
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x4B		;"K"
	call	lcd_out
	movlw	0x48		;"H"
	call	lcd_out
	movlw	0x7A		;"z"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	goto	xkhz
;
hz	movlw	0xC8		;1 sec gate
	movwf	gate
	call	count
	call	cnvt		;convert binary to BCD
	movlw	0x30		;test if "0"
	xorwf	19,w
	btfss	status,z
	goto	xkhz1
	movlw	0x30		;test if "0"
	xorwf	1A,w
	btfss	status,z
	goto	xkhz1
	movlw	0x32		;test if < 2
	subwf	1B,w
	btfsc	status,c
	goto	xkhz1
hz0	movlw	0x82		;set display address
	call	inst
	movlw	0x07		;output first 7 characters
	movwf	count1
	movlw	0x19		;MSD of freq
	movwf	fsr
hz1	movlw	0x30		;test if "0"
	xorwf	ind,w
	btfss	status,z
	goto	hz2
	movlw	0x20		;change preceeding "0's" to "space"
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	hz1
	goto	hz3
hz2	movf	ind,w
	call	lcd_out
	incf	fsr	,f
	decfsz	count1	,f
	goto	hz2
hz3	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x48		;"H"
	call	lcd_out
	movlw	0x7A		;"z"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	movlw	0x20		;"space"
	call	lcd_out
	goto	hz
;
overflow	movlw	0x01		;clear display
	call	inst
	movlw	0x84		;display address
	call	inst
	movlw	0x4F		;"O"
	call	lcd_out
	movlw	0x76		;"v"
	call	lcd_out
	movlw	0x65		;"e"
	call	lcd_out
	movlw	0x72		;"r"
	call	lcd_out
	movlw	0x66		;"f"
	call	lcd_out
	movlw	0x6C		;"l"
	call	lcd_out
	movlw	0x6F		;"o"
	call	lcd_out
	movlw	0x77		;"w"
	call	lcd_out
	movlw	0x02		;cursor at home
	call	inst
	goto	mhz
;
	end