;Sample program - Two channel medium speed rpm counter.

;This code has been tested to >100Hz on an MMi201, dialect 16, 
;with an identical signal on both inputs. Driving only one input makes no significant difference.
 
;Actual test result: Reading increases with frequency to 113Hz, then drops off again, gradually.
;That means your mechanical design must guarantee the input will never go over the limit frequency,
;as there will be no indication that has happened. This could be especially hazardous
;if you are for example closed loop controlling an RPM.

;The two inputs can come from any two adjacent inputs. Take care that the inputs are free of any contact bounce.

;Suggested speed ranges (RPM)

;	Pulses per rev		Max RPM
;		1		6000
;		2		3000
;		3		2000
;		4		1500
;		5		1200
;		6		1000

;Factors that will reduce performance include:

;	*	Unequal On and Off times on the input
;	*	Other tasks increasing processor loading. Test thoroughly.


Start:
		ON		20		;MS12 backlight

		LaunchTask	CN2_Init	;Start counter task
		LaunchTask	Test		;Test task
		RunTasksForever

;----------- Test task ------------------
Test:
		YieldTask
		GoSub		CN2_GET_Counts
		GoIfF		Test
;Display counts in W and Q
		OBLCD_SetCur	0,1
		OBLCD_fDispW	5,0
		fSwap
		OBLCD_SetCur	1,1
		OBLCD_fDispW	5,0
		GoTo		Test


;=========== Count2 - 2 channel counter task ===========
;Short name:	CN2_
;
;Function:
;		Counts pulses on two inputs over a period determined by the 
;		duration CN2_TimeBase. Once the time has expired stops counting
;		until read out. Counting is on the off->on transition
;
;Methods:	Init
;		GET_Counts	Returns True in X if there is a count available.
;				If so, the results are returned in W (channel A) and Q (channel B)
;				and a new count cycle is started.

CN2_TimeBase	EQU		100		; x 10mS

iCN2_In		iEQU		0		;The first of the two inputs
fCN2_CounterA	defFLOAT			;Counter register
fCN2_CounterB	defFLOAT			;Counter register
sCN2_Ready	defSEM				;Control semaphore
bCN2_NewInputs	defBYTE
bCN2_OldInputs	defBYTE				;I store inputs in RAM as part of a strategy to
						;smoothly carry state from one cycle to the next
						;(so each pulse gets counted once and once only)

CN2_Init:
		MarkTime			;Start timebase
		fLoadW		0
		fStore		fCN2_CounterA	;Clear counters
		fStore		fCN2_CounterB
		ClrS		sCN2_Ready
		
CN2_0:
		YieldTask
		LoopIfTiming	CN2_TimeBase,CN2_0a ;Test if time base expired
;Timebase expired
CN2_Set1:
		SetS		sCN2_Ready
		WaitForSF	sCN2_Ready	;Wait for client to read out results
		GoTo		CN2_Init	;Start again

;Still timing
CN2_0a:
		InputFM		iCN2_In
		LoadX		3		;			X	Y	Z	T
		AndM				;Mask off 2 lower bits	New	?	?	?
		Push				;			New	New	?	?
		Push				;			New	New	New	?
		Recall		bCN2_OldInputs	;			Old	New	New	New
		XorM				;1 if change		O X N	New	New	New
		AndM				;1 if change to 1	0->1	New	New	New
		Push				;			0->1	0->1	New	New
		LoadX		1		;			01	0->1	0->1	New
		AndM				;			CountA?	0->1	New	New
		GoIfZ		CN2_NoCountA	;			0->1	New	New	New
		fRecallW	fCN2_CounterA
		fInc
		fStore		fCN2_CounterA
CN2_NoCountA:
		LoadX		2		;			10	0->1	New	New
		AndM				;			CountB?	New	New	New
		GoIfZ		CN2_NoCountB	;			New	New	New	New
		fRecallW	fCN2_CounterB
		fInc
		fStore		fCN2_CounterB
CN2_NoCountB:
		Store		bCN2_OldInputs	;			New	New	New	New
		GoTo		CN2_0

;Read out results if available. Status flag in X
CN2_GET_Counts:
		RecallS		sCN2_Ready
		Push
		RetIfF
		fRecallW	fCN2_CounterA
		fRecallQ	fCN2_CounterB
		ClrS		sCN2_Ready
		Return

