;Program Name: vlffmtr2313.asm   Frequency meter wtih VLF serial link. ;Copyright 2004 Richard Cappels, projects@cappels.org   www.project.cappels.org.include "2313def.inc"		;Include file in same directory as project..equ	RFSigPort	= PORTB	;Port output signal is to appear on..equ	RFSigDDR	= DDRB	;Data Direction Register for signal output.equ	RFSigPin	= 0	;Pin output signal is to appear on..equ	LEDOutPort	= PORTB	;Indicator LED.equ	LEDOutDDR	= DDRB.equ	LEDOutPin	= 3.equ	CompPlusPort	= PORTB	;Comparitor noninverting input (input 0).equ	CompPlusDDR	= DDRB.equ	CompPlusPin	= 0.equ	BridgePowerPort	= PORTB	;Power for bridging resistors.equ	BridgePowerDDR	= DDRB.equ	BridgePowerPin	= 2;***** 16 bit binary-to-packed-BDC Subroutine Register Variables.equ	AtBCD0	=13		;address of tBCD0.equ	AtBCD2	=15		;address of tBCD1.def	tBCD0	=r13		;BCD value digits 1 and 0.def	tBCD1	=r14		;BCD value digits 3 and 2.def	tBCD2	=r15		;BCD value digit 4.def	fbinL	=r16		;binary value Low byte.def	fbinH	=r17		;binary value High byte.def	cnt16a	=r18		;loop counter.def	tmp16a	=r19		;temporary value;***** other register assignments.def 	rbglc			=r1.def	presetrbglc		=r2 ;1,$0A number of seconds when loopmultiplier is = $64.def	presetloopmultiplier	=r3; $64, $01 number of 10 ms increments.def	presetdelaycounter	=r4; $F4 .def	presetdelaycounter1	=r5; $27 .def	Idle1			=r6.def	Idle2			=r7.def	idlecompare		=r8.def	flags			=r9.def	inbytehh		=r20	;Higher byte for asci-hex conversion	.def	temp			= r22	;General purpose register.def 	delaycounter		= r23.def 	delaycounter1		= r24.def 	loopmultiplier		= r25.def	RFChar			= r26	;RF character I/O buffer.def	inbytel			= r28    ;Lower byte for asci-hex conversion.def	inbyteh			= r19	;Data to be sent via wireless port;Definition of flags register;0 if set, disable battery timer.;1;2;3;4;5;6;7;definition of I/O;B0	+ comparitor input - Antenna Signal;B1	- comparitor input - Antenna reference;B2	Bridge power		;B3	LED (high to turn LED on)	.	;B4	Receive/Xmit application (for test purposes)	;B5	(not assigned - configure as INPUT with weak pullup)	;B6	(not assigned - configure as INPUT with weak pullup)	;B7	(not assigned - configure as INPUT with weak pullup)	;D0	Reserved FOR UART RECEIVE - input has weak pullup;D1	Reserved FOR UART TRANSMIT - output.;D2	(not assigned - configure as INPUT with weak pullup);D3	(not assigned - configure as INPUT with weak pullup);D4	(not assigned - configure as INPUT with weak pullup);D5	Counter input for frequency meter;D6	(not assigned - configure as INPUT with weak pullup);D7	(not assigned - configure as INPUT with weak pullup).cseg	.ORG $0000				rjmp start.ORG $0006 	rjmp timer0service	;Timer/counter compare interrupt -for RF.ORG $000A	rjmp comparitorservice	;Service comparitor interupt -for RF.include	"vlfcw2313.inc"	;This include file must be loaded here. File is expected to be.				;in the same directory as this file.DisableBatteryTimer:	set		bld	flags,0	ldi     ZH,high(2*Batteryoffmessage)	;Load high part of byte address into ZH	ldi     ZL,low(2*Batteryoffmessage)	;Load low part of byte address into ZL	rcall 	sendstring			;Send "Battery timer OFF" message.		rjmp	loopDisconnect:	ldi     ZH,high(2*offmessage)	;Load high part of byte address into ZH	ldi     ZL,low(2*offmessage)	;Load low part of byte address into ZL	rcall 	sendstring		;Send "DISCONNECTED" message.stiloff:	rcall	rs_rec			;Wait for Control-A	cpi	RFChar,$01	brne	stiloff	ldi     ZH,high(2*onmessage)	;Load high part of byte address into ZH	ldi     ZL,low(2*onmessage)	;Load low part of byte address into ZL	rcall 	sendstring		;Send "CONNECTED" message.	rjmp	loop	MeasureOnce:			;Measure frequency one time..	rcall	measurefreq	rjmp 	loop	     		start:					;Startup routine	ldi	r16,RAMEND		;Initialize Stack Pointer (AT90S2313 has an 8 bit stack pointer)..	out	spl,r16	clr	flags			;Set all bits in flagreg (flag register) to zero.		ldi	temp,0b00000010		;Set PORTD.	out	DDRD,temp	ldi	temp,0b11011111	out	PORTD,temp	ldi	temp,0b00000000		;Set PORTB.	out	DDRB,temp	ldi	temp,0b11110100	out	PORTB,temp							;The Three statements below are for the VLF RF link.	sbi	BridgePowerDDR,BridgePowerPin	;Turn on bridge power	sbi	LEDOutDDR,LEDOutPin	;Make LED so an output pin.	sei				;Enable interrupts.	rcall	TypeGreeting		rcall	makeit1s		;Set default measurement time to 1 second and jump to loop	rjmp	Disconnectloop:					;*****command interpretation loop****	ldi	RFChar,$3A		;Send prompt (colon char) to terminal	rcall	SendRFByte	ldi	RFChar,$20	rcall	SendRFByte	ldi	RFChar,$20	rcall	SendRFByte		rcall	rs_rec			;Get char from host and interpret char	cpi	RFChar,$3F		;If ? then display the menu.	breq	domenu	cpi	RFChar,$21		;If ! then use watchdog timer to reset the chip.	breq	pull_the_plug	andi	RFChar,$DF		;Make upper-case ascii		cpi	RFChar,'T'		;If it is a T then disable the battery timer.	breq	DisableBatteryTimer	;(Resetting the chip resets this flag).				cpi	RFChar,$52		;If R or r, measure frequency over and over.	breq	MeasureRepetitive		cpi	RFChar,$0D		;If Retrun measure frequency	breq	MeasureOnce	cpi	RFChar,$41		;A 10ms	breq	set10ms		cpi	RFChar,$42		;B 100ms	breq	set100ms	cpi	RFChar,$43		;C 1s		breq 	set1s	cpi	RFChar,$44		;D 10s	breq 	set10s		cpi	RFChar,$45		;E 100s	breq 	goto100secondrealy	cpi	RFChar,$02		;Control-B -idle until Control-A received.	breq	Disconnect	rjmp	loop			;Go get another char to interpret.MeasureRepetitive:			;	Measure frequency over and over again until RF detected.	ldi     ZH,high(2*Repetitivemessage)	;Load high part of byte address into ZH	ldi     ZL,low(2*Repetitivemessage)	;Load low part of byte address into ZL	rcall 	sendstring			;Send "Repetitive measurement" message.	rcall	ClearIdleTimeShort		;Preset idle timer (battery saver).MeasureAgain:	rcall	IdleTime			;Increment idle timer and sleep if its time. 	rcall	measurefreq			;Measure the frequency at the input.	rcall	ReceiveRFByte			;See is present to interrupt the measuremnets.	brcc	MeasureAgain			;If no RF, continute taking measurements.	rjmp 	loop             domenu:	rcall	TypeGreeting			;Type the user menu.	rjmp 	loop				;Go back to main loop.		pull_the_plug:					;Reset the controller using the watchdog timer.	ldi     ZH,high(2*resetmessage)     	;Load high part of reset message address into ZH.	ldi     ZL,low(2*resetmessage)     	;Load low part of reset message address into ZL.	rcall 	sendstring			;Send reset message via RF.	wdr					;Reset then enable watchdog timer and wait for hardware reset	ldi	temp,$08	out	wdtcr,tempwait_for_reset:						rjmp	wait_for_reset			;Loop until watchdog resets the controller.   	goto100secondrealy: rjmp set100s		;Here because of size of relative branch in AT90S2313.set10ms:					;Set registers for a 10 millisecond measuremnet and send notice.	ldi	temp,$01	mov	presetrbglc,temp	ldi	temp,$01	mov	presetloopmultiplier,temp	 	ldi	temp,$F4	mov	presetdelaycounter,temp	ldi	temp,$27	mov	presetdelaycounter1,temp 	       	ldi     ZH,high(2*tenmsmessage)		;Load high part of byte address into ZH     	ldi     ZL,low(2*tenmsmessage)		;Load low part of byte address into ZL     	rcall   sendstring	rjmp	loopset100ms:					;Set registers for a 100 millisecond measuremnet and send notice.	ldi	temp,$01	mov	presetrbglc,temp	ldi	temp,$0A	mov	presetloopmultiplier,temp	 	ldi	temp,$F4	mov	presetdelaycounter,temp	ldi	temp,$27	mov	presetdelaycounter1,temp 	       	ldi     ZH,high(2*hundredmsmessage)	;Load high part of byte address into ZH     	ldi     ZL,low(2*hundredmsmessage)	;Load low part of byte address into ZL     	rcall     sendstring	rjmp	loop     set1s:						;Set registers for a 1 second measuremnet and send notice.	rcall	makeit1s	rjmp	loop          makeit1s:    	ldi	temp,$01	mov	presetrbglc,temp	ldi	temp,$64	mov	presetloopmultiplier,temp	 	ldi	temp,$F4	mov	presetdelaycounter,temp	ldi	temp,$27	mov	presetdelaycounter1,temp 	       	ldi     ZH,high(2*onesmessage)		;Load high part of byte address into ZH     	ldi     ZL,low(2*onesmessage)		;Load low part of byte address into ZL     	rcall     sendstring	ret      set10s:						;Set registers for a 100 second measuremnet and send notice.	ldi	temp,$0A	mov	presetrbglc,temp	ldi	temp,$64	mov	presetloopmultiplier,temp	 	ldi	temp,$F4	mov	presetdelaycounter,temp	ldi	temp,$27	mov	presetdelaycounter1,temp 	       	ldi     ZH,high(2*tensmessage)		;Load high part of byte address into ZH     	ldi     ZL,low(2*tensmessage)		;Load low part of byte address into ZL     	rcall     sendstring	rjmp	loop     set100s:					;Set registers for a 100 second measuremnet and send notice.	ldi	temp,$64	mov	presetrbglc,temp	ldi	temp,$64	mov	presetloopmultiplier,temp	 	ldi	temp,$F4	mov	presetdelaycounter,temp	ldi	temp,$27	mov	presetdelaycounter1,temp 	       	ldi     ZH,high(2*hundredsmessage)	;Load high part of byte address into ZH     	ldi     ZL,low(2*hundredsmessage)	;Load low part of byte address into ZL     	rcall     sendstring	rjmp	loop     rs_rec:     	rcall	ClearIdleTime			;Keep track of time no input from terminal receivedrec_more:					;for the purposes of the battery saver.	rcall	IdleTime	rcall	ReceiveRFByte			;Wait for carry to come back high.	brcc	rec_more			  	rcall	PostRCVDelay			;Wait for far end to be ready to receive before leaving.   	ret       crlf:						;Send carriage return and line feed (the hard way).	ldi	ZH,high(2*crlfmessage)		;Load high part of byte address into ZH	ldi	ZL,low(2*crlfmessage)		;Load low part of byte address into ZL	rcall	sendstring	retsendstring:					;Send Flash string. Call with location of string in Z.	lpm					;Load byte from program memory into r0	tst	r0				;Check if we've reached the end of the message	breq	finishsendstering		;If so, return	mov 	RFChar,r0		rcall	SendRFByte	adiw	ZL,1				;Increment Z registers	rjmp	sendstring			;If not the end, the keep sending until $00 is encountered.finishsendstering:	retsendline:					;Send a string followed by a cariage return and line feed.						;Call with location of start of string in Z.                 	rcall     sendstring     	rcall     crlf     	retTypeGreeting:					;Send power on/reset message via RF link.	rcall	crlf	rcall	crlf	ldi	ZH,high(2*hellomessage)		;Load high part of byte address into ZH	ldi	ZL,low(2*hellomessage)		;Load low part of byte address into ZL	rcall	sendline			;Sent it.	retbyte_to_asciihex:				;Convert byte in inbytel to ascii in inbyteh,inbytel.	mov	inbyteh,inbytel	lsr	inbyteh 			;Convert the high nybble to ascii byte	lsr	inbyteh	lsr	inbyteh	lsr	inbyteh	subi	inbyteh,$D0     		;Add $30.	cpi	inbyteh,$3A     	brlo	PC+2          			;If less than 9 skip next instruction.	subi	inbyteh,$F9     		;Add 8 to ASCII (if data greater than 9).						;(Byte in inbyteh represents upper nybble that was in 						;inbytel at start)	andi	inbytel,0b00001111		;Convert the lower nybble to ascii byte.	subi	inbytel,$D0     		;Add $30.	cpi	inbytel,$3A     	brlo	PC+2          			;If less than 9 skip next instruction.	subi	inbytel,$F9     		;Add 8 to ASCII (if data greater than 9).retsendbyte:      					;Send byte contained in inbytel to terminal.	rcall	byte_to_asciihex	mov	RFChar,inbyteh	rcall	SendRFByte	mov	RFChar,inbytel	rcall	SendRFByte	ret		;*******************	MEASURE FREQUENCYmeasurefreq:	ldi	temp,$00			;Set tccr1a (contorl of 16 bit counter) to all zeros 	out	tccr1a,temp	ldi	temp,$00			;Clear 16 bit counter	out	tcnt1h,temp	out	tcnt1l,temp	ldi	temp,$06			;Enable input to counter 1 	out	tccr1b,temp	mov	rbglc,presetrbglc	reallybigloop:											mov	loopmultiplier,presetloopmultiplier	;****10 ms = $01, 100 ms =  $0A, 1 second = $64	bigloop:	mov 	delaycounter,presetdelaycounter		;Set values for delay of 10 ms. delaycounter = $F4, delaycounter1 = $27	mov 	delaycounter1,presetdelaycounter1				dealylooproutine:					;10 millisecond dealy loop.	dec	delaycounter	cpi	delaycounter,$00	brne	dealylooproutine	dec	delaycounter1	cpi	delaycounter1,$00	brne	dealylooproutine			nop					;A little extra delay.	nop	nop	dec 	loopmultiplier	brne	bigloop		dec	rbglc	brne	reallybigloop	ldi	temp,$00			;Stop 16 bit counter.	out	tccr1b,temp						;Display the data.	in	fbinL,tcnt1l			;Move counter contents to input for number conversion.	in	fbinH,tcnt1h		rcall	bin2BCD16			;Convert to 2.5-byte packed BCD format.	rcall 	crlf			mov	RFChar,tBCD2	ldi	temp,$30	add	RFChar,temp	rcall 	SendRFByte	mov	inbytel,tBCD1	rcall	sendbyte	mov	inbytel,tBCD0			;Since leading digit on high byte is always zero, dont' sent it.	rcall	sendbyte	ldi	RFChar,$20	rcall	SendRFByte	ret	;**** A P P L I C A T I O N   N O T E   A V R 2 0 4 ************************;* Title:		BCD Arithmetics;* Version:		1.1;* Last updated:	97.07.04;* Target:		AT90Sxxxx (All AVR Devices);*;* Support E-mail:	avr@atmel.com;* ;* DESCRIPTION;* This Application Note lists subroutines for the following Binary Coded;* Decimal arithmetic applications:;*;* Binary 16 to BCD Conversion (special considerations for AT90Sxx0x);***** Codebin2BCD16:	ldi	cnt16a,16	;Init loop counter		clr	tBCD2		;clear result (3 bytes)	clr	tBCD1			clr	tBCD0			clr	ZH		;clear ZH (not needed for AT90Sxx0x)bBCDx_1:lsl	fbinL		;shift input value	rol	fbinH		;through all bytes	rol	tBCD0		;	rol	tBCD1	rol	tBCD2	dec	cnt16a		;decrement loop counter	brne	bBCDx_2		;if counter not zero	ret			;   returnbBCDx_2:ldi	r30,AtBCD2+1	;Z points to result MSB + 1bBCDx_3:	ld	tmp16a,-Z	;get (Z) with pre-decrement;----------------------------------------------------------------;For AT90Sxx0x, substitute the above line with:;;	dec	ZL;	ld	tmp16a,Z;;----------------------------------------------------------------	subi	tmp16a,-$03	;add 0x03	sbrc	tmp16a,3	;if bit 3 not clear	st	Z,tmp16a	;	store back	ld	tmp16a,Z	;get (Z)	subi	tmp16a,-$30	;add 0x30	sbrc	tmp16a,7	;if bit 7 not clear	st	Z,tmp16a	;	store back	cpi	ZL,AtBCD0	;done all three?	brne	bBCDx_3		;loop again if not	rjmp	bBCDx_1		hellomessage:				;This is the power on/reset greeting..db     "2313 frequency meter  vlffmtr040713B VLF LINK   Dick Cappels".db	$0A,$0D.db	"A=10ms,B=100ms,C=1s,D=10s,E=100s. Return=meausre, R=repetitive. ".db	$0A,$0D.db	"T=Batt timer off, !=reset, ?=diaplay menu.".db	$0A,$0D.db	"Control-A to connect, Control-B to disconnect.".db	$0A,$0D.db	"Max count = 65535, Max frequency < 2 MHz. ".db	$0A,$0D.db	$00,$00resetmessage:					;This is the messaging telling the user .db	"Reset initiated."			;that the controller is being reset..db	$00,$00crlfmessage:					;A carriage return and linefeed..db     $0A,$0D.db     00,00tenmsmessage:					;The messages below acknowledge the setting of the timebase.db	"Timebase set to 10 ms Frequency is Count X100.".db     $0A,$0D.db     00,00hundredmsmessage:.db	"Timebase set to 100 ms. Frequency is Count X 10 ".db     $0A,$0D.db     00,00onesmessage:.db	"Timebase set to 1 s. Frequency is Count X 1.".db     $0A,$0D.db     00,00tensmessage:.db	"Timebase set to 10 s. Frequency is Count  X 1/10. ".db     $0A,$0D.db     00,00hundredsmessage:.db	"Timebase set to 100 s. Frequency is Count  X 1/100. ".db     $0A,$0D.db     00,00Onmessage:					;Message stating that the meter hsa been connected..db	"Frequency Meter CONNECTED. Control-B to Disconnect. ".db     $0A,$0D.db     00,00Offmessage:					;Message stating that the meter has been disconnected..db	"Frequency Meter DISCONNECTED. Control-A to Connect. ".db     $0A,$0D.db     00,00Repetitivemessage:				;Repetitive measurement message..db	"Taking repetitive measurements. Send characters to interrupt. ".db     $0A,$0D.db     00,00Batteryoffmessage:				;Text message laterting that battery timer has beeen turned off..db	"Battery Timer OFF. Cycle power or reset to enable.".db     $0A,$0D.db     00,00ClearIdleTimeShort:				;Preset idle time counters for battery timer for about 1 minute. 	clr	idle1		clr	idle2	push	temp	mov	temp,presetrbglc	cpi	temp,1	breq	presetblgcIs1	clr	temp	rjmp	tempsetpresetblgcIs1:	ldi	temp,5	tempset:			mov	idlecompare,temp		pop	temp	retClearIdleTime:					;Preset idle time counters for battery timer.	clr	idle1	clr	idle2	push	temp	ldi	temp,15				;15 for about 3 minutes	mov	idlecompare,temp		pop	temp	retIdleTime:					;Count up to 1,200,000 start bit samples the shut down						;to conserve battery (about 5 minutes).	bst	flags,0				;Skip timer if flags bit 0 is set.	brts	noincidle2	inc	idle1	brne	noincidle2	inc	idle2	cp	idle2,idlecompare			brpl	sleeptime			;If time is up, go to sleep.noincidle2:	retsleeptime:	ldi	temp,0				;Shut off everyting you can, go do sleep.	out	PORTB,temp			;Make I/O ports inputs, no pullup.	out	DDRB,temp	out	PORTD,temp	out	DDRD,temp	ldi	temp,0b10000000	out	ACSR,temp			;Make sure comparitor is off.	ldi	temp,0b00110000	out	MCUCR,temp	sleep	rjmp	sleeptime 			;This instruction should never execute..exit						;Assembler will not assemble past this line of this file.
