;======  Thermistor temperature measurement =============
;Disclaimer:
;	This is an example program supplied "as is" with no warranties
;	implied or express as to its suitability for any application.
;	You must integrate this code into your own program and thoroughly 
;	test it.

;Incorporating this code into your program (general instructions)
;	Only code between ;vvvvvvvvvvvvvv and '^^^^^^^^^^^^^^ is intended
;	to be used in your program. Everything else is documentation and
;	test code.
;	If the program contains an NVEM0 directive, the stuff below that 
;	must be appended at the end of your program, after one single NVEM0
;	directive.
;	The example code is designed to run under MultiTrack. You must 
;	make sure to include LaunchTask instructions to make it run.
;	You need to understand MultiTrack. It is quite simple to comprehend
;	and will save you a lot of effort in the long run.
;	MultiTrack is previewed in a MiniTutorial within SPLat/PC
;	and covered in detail in the SPLat Knowledge Base.

; Accessing the functionality from your program:
;
;	All external access to the function is via subroutine calls (GoSub). In keeping 
;	with the ideas of object oriented programming we refer to Properties 
;	and Methods. 
;	- Properties are data you can GET or SET. The data belongs 
;	to the function so you are only allowed to access it through subroutine 
;	calls to the applicable GET or SET routine.
; 
;	Example:	GoSub	XYZ_GET_RunStatus
;			GoSub	XYZ_SET_RequiredLevel
;
;	- Methods do something. You invoke them by subroutine calls. 
;
;	Example:	GoSub	XYZ_TurnOnPump
;
;	All property and method calls have names 
;	starting in the short name of the function (XYZ_ above). By convention the short name 
;	is in upper case, very few letters and unique to the function. It ends 
;	in an underscore. The short name is NOT included in the property and 
;	method descriptions below but must be included when you use them.
;	
;	The startup method is usually invoked by a LaunchTask rather than a GoSub.
;
;	Examples:	LaunchTask	XYZ_Start
;			or
;			LaunchTask	XYZ_Init

************* Test code *********************
 ;stscale 200
	LaunchTask	THM_Init,0
	LaunchTask	THM_Init,1
;	LaunchTask	TestTime
	RunTasksForever


;vvvvvvvvvv Start of the actual example code vvvvvvvvvvv

;========== Thermistor temperature measurement (multi-channel) ==================
;Short name THM_

;What it does:

;	Temperature measurement
;	-----------------------
;	THM_ provides thermistor temperature measurement. It is capable of
;	handling several channel using jndexing, providing the thermistors
;	are on contiguously numbered analog inuts and all thermistors use the same
;	drive voltage and linearization polynomial. The result can be in 'C or 'F
;
;	Low pass filtering
;	------------------
;	The results are filtered through a single pole simulated RC filter with a time constant
;	of 2 seconds. 
;	You can change the time constant quite simply by editing two lines of code.
;
;	Selecting 'C or 'F
;	------------------
;	The calculations are all done in 'C. However the final result
;	can be converted to 'F by provided code in THM_GET_Temperature
;
;	Processor load leveling
;	-----------------------
;	The calculations required take quiate a lot of processor time, about 5mS per channel.
;	In order to prevent all channels being calculated in one run of the task queue,
;	(and hence generating a momentarily very long latency for other tasks).
;	a token is used to stagger the channels's calculations relative to each other.

;	Manual editing
;	--------------
;	Lines/areas requiring manual editing are flagged with  ;<<<<<
;	*	You must manually edit the I/O assignments to match your controller hardware.
;	*	Lines with mEQU use absolute RAM allocations. You MUST move these to the start
;		of the program before any defXXX directives.

;---- Properties and methods ---------
;Methods:
;	Init		;Initializes the background task. Invoke with 'LaunchTask  THM_Init'

;Property SETs:	None

;Property GETs:
;
;	GET_Temperature	Returns in W the filtered temperature reading for the channel number in I
;			*** NB **** Don't forget to set I before calling THM_GET_Temperature!!!!!!!

;Revision history (newest on top)
;
;V1.0	060828		Initial release

fTHM_Temperature	defFLOAT	3		;<<<<<<<<<<<< Edit for however many thermistors you are using
fTHM_InstTemp		defFLOAT	3		;<<<<<<<<<<<< Edit for however many thermistors you are using
aTHM_Thermistor		EQU		0		;<<<<<<<<<<<< Edit for your hardware: the first thermistor channel
sTHM_Token		defSEM

THM_Init:
		LoadX		95			;<<<<<<<<<<<<<  Edit for selected polynomial
		AnOutF					;<<<<<<<<<<<<<  Edit to suit hardware
		Pause		100			;Allow analog output to settle
		fAnIn		aTHM_Thermistor
		GoSub		THM_PolyCalc
		fStore		fTHM_Temperature	;Bypass filter for the very first reading
THM_Loop:
		Pause		10			;100mS between samples
		NoJ:WaitForSF	sTHM_Token		;Wait until other channel(s) are finished
		NoJ:SetS	sTHM_Token		;Block other channels
		fAnIn		aTHM_Thermistor		;Read the thermistor
		GoSub		THM_PolyCalc		;Convert to 'C
		fStore		fTHM_InstTemp		;Save instantaneous value

		YieldTask				;Take a break before doing filtering

		fRecallW	fTHM_Temperature	;Start of filter
		fLoadQ		19			;<<<<<<<<<<<<<<<<<< Edit to change filter time constant
		fMul					; 19* accumulated value
		fRecallQ	fTHM_InstTemp
		fAdd					; 19*Old + New
		fLoadQ		0.05			;1/20 <<<<<<<<<<<<<<<<<< Edit to change filter time constant
		fMul
		fStore		fTHM_Temperature	;New filtered value
		YieldTask				;Take a break
		NoJ:ClrS	sTHM_Token		;Let other channel(s) have a go
		GoTo		THM_Loop

;------ Polynomial calculation. Convert normalized analog reading in W to degrees C.
;I have two version here for different thermistor configurations (different polynomials).
;You will almost certainly have to use a thermistor spreadsheet to establish your
;own polynomial. You want ThermstrNorm.xls or ThermstrHVAC.xls. These work on normalized
;analog readings from the fAnIn instruction.

;Polynomial for R25=10K, Rf=33K B=3877, T= -40'C to + 50'C
;'C = -6.540441E+02x^5 + 1.871267E+03x^4 - 2.160023E+03x^3 + 1.265438E+03x^2 - 4.497268E+02x + 8.502783E+01
;With 10-bit fAnIn resolution is better than 0.2'C -40'C to +40'C
fTHM_Scratch	defFLOAT

;;;THM_PolyCalc:
	NoJ:fStore	fTHM_Scratch
	fLoadQ		-6.540441E+02		;<<<<<<<< X^5 coefficient
	fMul

	fLoadQ		+1.871267E+03		;<<<<<<<< X^4 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		-2.160023E+0		;<<<<<<<< X^3 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		+1.265438E+03		;<<<<<<<< X^2 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		-4.497268E+02		;<<<<<<<< X^1 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		+8.502783E+01		;<<<<<<<< X^0 coefficient
	fAdd
	Return

;Polynomial for R25=10K, Rf=10K B=3877, T= +10 to +50 (Trainer board)
;'C = -7.092727E+01x5 + 2.806945E+02x4 - 4.793233E+02x3 + 4.418513E+02x2 - 2.752315E+02x + 1.128212E+02
;With 8-bit fAnIn resolution is b0.25

THM_PolyCalc:
	NoJ:fStore	fTHM_Scratch
	fLoadQ		-7.092727E+01		;<<<<<<<< X^5 coefficient
	fMul

	fLoadQ		+2.806945E+02		;<<<<<<<< X^4 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		-4.793233E+02		;<<<<<<<< X^3 coefficient
	fAdd
	fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		+4.418513E+02		;<<<<<<<< X^2 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		-2.752315E+02		;<<<<<<<< X^1 coefficient
	fAdd
	NoJ:fRecallQ	fTHM_Scratch
	fMul

	fLoadQ		+1.128212E+02		;<<<<<<<< X^0 coefficient
	fAdd
	Return 


;------ Property GET(s) --------------
;Get the temperature reading for the channel in I
****** Remember to set I *************
THM_GET_Temperature:
	IasJ:fRecallW	fTHM_Temperature
;<<<<<<<< The following converts to degrees F, if that's your thing
	fLoadQ		1.8	;<<<<<<<< Remove if you want degrees C
	fMUL			;<<<<<<<< Remove if you want degrees C
	fLoadQ		32	;<<<<<<<< Remove if you want degrees C
	fAdd			;<<<<<<<< Remove if you want degrees C
	Return

;^^^^^^^^^^ End of the actual example code ^^^^^^^^^^^^^

;-------------------
LoopCounter	defBYTE
LoopTimer	defTIME24

TestTime:	;Measure how fast MultiTrack cycles through the task queue
		STStart		LoopTimer
TT1:
		YieldTask
		DMGNZ		LoopCounter,TT1
		fSTTimeSince	LoopTimer
		fLoadQ		0.0256
		fSwap
		fDiv
		fLoadQ		-545
		fAdd
		OBLCD_SetCur	2,0
		OBLCD_fDispW	6,0
		OBLCD_Text	228,"S/Q"
		fRecallW		fTHM_Temperature	
		OBLCD_SetCur	0,0
		OBLCD_fDispW	5,5
		fAnIn		0
		OBLCD_Text	"  "
		OBLCD_fDispW	5,5
		GoTo		TestTime

