CHIPTEMP{10} - An algorithm to calculate the PICaxe Chip temperature

AllyCat

Senior Member
Hi,

Here is my first formal description of an algorithm to accurately calculate the PICaxe's Chip Temperature using only the available on-chip hardware. It's presented as a subroutine within a test harness, for compatibility with PE5, but equally it might be wrtten as a macro and/or embedded within a larger program/subroutine. I've written much on the READINTERNALTEMP commands, for example the bugs (in PE5) and voltage sensitivity, etc., so here I will deal only with a calculation method for the chip temperature using "available" commands.

The complete temperature-measurement process can be divided into four stages:
1. ADC measurement(s) of the supply rail voltage (Vdd),
2. ADC measurement(s) of the on-chip temperature-sensing diodes,
3. Calculation of the temperature (gradient) in the desired units, and
4. Post-processing the result for calibration, filtering and display, etc..

I've already posted several code snippetts to measure the supply rail (e.g. for "10mV" and "1mV" resolution) and written much on the READINTERNALTEMP command. So I won't expand on the options here, but just include a compatible (PE5/PE6) bug-fixed version. Similarly, there are numerous possibilities for post-processing, for example averaging (to reduce spikes or noise), formatting in integer degrees C or F, etc., or even to one decimal place of resolution. Then display the result on the PE terminal (SERTXD..) , on a LCD (SEROUT..) or even via PWM to a DVM , so only a few examples can be shown here.

The algorithm may be optimised for any particular application, but here are just two versions; a basic CHIPTEMP routine and a higher resolution CHIPTEMP10 (named similarly to other PICaxe keywords). However, in this case the "10" suffix indicates that the integer result can be 10 times larger (and thus converted to a "one decimal place" result).

The basic calculation requires two fundamental input parameters, i.e. :
a. The Supply Rail Voltage and
b. A Temperature-related Voltage measurement (from 1. and 2. above).
Also, the temperature coefficient of the on-chip diodes is required (e.g. from a two-point calibration), but in most cases this can be a fixed constant (typically 1.24 mV/degree C for each diode). The algorithm also needs a few "switches", to indicate the number of diodes being used and the number of individual ADC measurements, etc., which are defined by additional program constants.

Last, but definitely not least, the temperature MUST be calibrated for every individual target chip. This is intentionally the last stage in the calculation, which ensures that the calibration is applied directly in integer degrees (or tenths in the case of the "decimal" version). Thus, a single calibration operation is sufficient: The first time the program is run, simply subtract the reported temperature from the actual (room) temperature and apply the numerical value directly to the appropriate "calibration constant", ITZ{10} , within the program.

So here are the two subroutines, with a test harness to demonstrate the integer and decimal versions, and also report the measured supply voltage, on the PE terminal emulator. The raw calculation consists of just three assignments which can be written in three lines of code, however the "10" version is spread over five lines, to accommodate more detailed comments. :

Code:
; CHIPTEMP{10} : A calculation algorithm for the internal chip temperature of M2 PICAXEs.
;  AllyCat,  February 2016.

#picaxe 20m2
#no_data
#terminal 4800

; Variables:
symbol tempb = b1			; Temporary/Local Byte, also for passing paramters etc.
symbol tempw = w1			; Temporary/Local Word, also for passing paramters, etc
symbol Vdd = w2				; PICAXE supply rail voltage in mV
symbol Vadd = w3			; Additional Word variable, sometimes needed for local calculations 

; Calibration Constants:
symbol ITZ10 = 5100		; Calibration offset temperature value in tenths of a degree C
symbol CALVDD20 = 52429		; Calibrate Vdd, nominally 1024 (ADC steps) * 1024 (FVR mV) / 20 (stepsize mV)
symbol CALVDD7 = 59919		; Adjust to calibrate Vdd, nominally 65536 * 32 / 5 / 7 (used in ReadVdd2) 
symbol TEMPCO = 124		; Temperature coefficient of one internal diode (mV/C * 100)
symbol DEMO = 2			; Multiplier to allow decimal resolution to be demonstrated (otherwise = 1)

; Constants for CHIPTEMP10 version (Can give decimal result)
symbol NVDD10 = 2 * DEMO	 	; Number of times Vdd is included (i.e. number of READINTERNALTEMPs)
symbol GRAD12 = 5461333 / TEMPCO	; Voltage / Temperature conversion factor for 12 diodes (655360/12)
symbol SLOPE10 = GRAD12		; Calibration Constant to convert mV into degrees (Fractional value * 65536)

; Constants for CHIPTEMP (integer result) version:
symbol NVDD = 2			; Number of times Vdd is included (i.e. number of READINTERNALTEMPs)
symbol ITZ = ITZ10 / 10		; Calibration temperature corresponding to zero diode voltage (C)
symbol GRAD6 = 1092267 / TEMPCO	; Voltage / Temperature conversion factor for 6 diodes (65536/6)
symbol SLOPE = GRAD6		; Calibration Constant to convert mV into degrees (Fractional value * 65536)

main:
do
; First measure the basic Vdd and Raw Chip Temperature voltages: 	
	call ReadVdd					; Get normal supply voltage in mV
	readinternaltemp IT_RAW_H,0,Vadd		; ADC value (steps) for 4 diodes (2 diodes with PE5)
	fvrsetup %10111010   				; Bugfix for PE5 (selects 4 diodes)
	readinternaltemp IT_RAW_L,0,tempw		; ADC value for 2 diodes (4 diodes with PE5)
	tempw = tempw + Vadd			; ADC value for 6 diodes (with 2 * Vdd measurements)
	Vadd = tempw				; Save value to use with CHIPTEMP10 routine later

; Now the basic integer calculation:				
	call ChipTemp			; Input parameters in tempw & Vdd, result in tempw (or b2)
	sertxd(cr,lf,#tempw,"C ")			; Report the basic integer calculation (CHIPTEMP)

; Now the "High Resolution" version:
	call ReadVdd2				; Higher accuracy measurement of Vdd (in mV)
	sertxd("Vdd= ",#Vdd,"mV ")				; Report the supply voltage		
	tempw = Vadd * DEMO		; Recover value and Multipy to demonstrate decimal result
	Vadd = 0				; Zero unless a FVR was used as an ADC reference voltage
	call ChipTemp10			; Input parameters in tempw,Vdd (& Vadd),result in tempw

; Split the result into decimal parts and report:
	tempb = tempw // 10					; Decimal part of result
	tempw = tempw / 10					; Integer part of result
	sertxd(#tempw,".",#tempb,"C")			; Report the temperature in degrees C
	pause 3000
loop	

ChipTemp10: ; Generic Chip Temperature calculation 
	tempw = tempw * 16 ** Vdd	; Number of ADC steps * Vdd (stepsize) / 4.(Max 4 * ADC values)
	tempw = tempw * 2 + Vadd * 2	; Add the ADC steps referenced to FVR2048 (= mV/2) and double
	tempw = Vdd * NVDD10 - tempw 	; Subtract from sum of Vdds  
	tempw = tempw ** SLOPE10	 	; Scale to degrees (or degrees * 10)
	tempw = ITZ10 - tempw			; Calibrate to reference temperature (e.g. zero C)
	return				; Returns tempw = deg C * 10 (if appropriate constants are used)
	
ChipTemp:
	tempw = tempw * 16 ** Vdd * 4	; Number of ADC steps * Vdd (stepsize), Max 4 * ADC values.
	tempw = Vdd * NVDD - tempw ** SLOPE	 ; Subtract from number of Vdds and Scale to degrees
	tempw = ITZ - tempw			; Calibrate to reference temperature (0C;-40C;-273C,etc.)
	return						; Returns tempw = deg C (or as calibrated) 

ReadVdd:
	adcconfig 0		; Bugfix (omission from CALIBADC) if ADC has been referenced by FVR
	calibadc10 tempw				; Measure FVR1024 relative to Vdd
	Vdd = CALVDD20 / tempw * 20	; Calculate the Vdd in mV
 	Vdd = Vdd + 20 		; Round up the constant to make integer/decimal results more consistent
	return
		
ReadVdd2:
	fvrsetup fvr2048				; Will be used as ADC reference voltage 
	dacsetup $80				; Enable DAC with Vdd reference
	daclevel 10				; Highest to accommodate Vdd = 6v (if FVR = 2048) 
	Vdd = 0					; Prepare to accumulate the Vdd measurement
	for b1 = 1 to 7 				; 7 x samples allows ** to calibrate up to 6000 mV result	
		adcconfig 3			; FVR reference for ADC
		readdac10 tempw			; Note this command uses DAC (not ADC)
		Vdd = Vdd + tempw		; Accumulate scaled Vdd = loops * 1024 * 5 * Vdd / 32 
	next b1
	Vdd = Vdd ** CALVDD7			; Calibrate to mV units (multiplier < 1 )
	return
An explanation of the calculation method will follow in a second post, due to exceeding the forum word limit (again), ;)

Cheers, Alan.
 

AllyCat

Senior Member
Part 2 : How it works.

Hi again,

As with all my software now, I have reserved b1 and w1 as "Temporary" or "Local" variables, and for passing parameters to and from subroutines. Thus in the listing above, "tempw" receives a value from READINTERNALTEMP (or equivalent), passes it on to CHIPTEMP{10} and then receives the temperature result, perhaps to be passed on to a formatting and/or "print" routine. However, Vdd is a sufficiently important variable for the subroutine (and potentially useful elsewhere) that it has a dedicated variable. Some of the modules require an additional temporary/local word variable (Vadd) and for returning a simple integer temperature result, "tempb" may be preferred to "tempw".

1. The first stage of the CHIPTEMP{10} subroutine calculates the voltage (relative to ground) on the (lower end of the) temperature sensing diodes. This is done by multiplying the value returned by the ADC by its "step size" (which is proportional to the supply rail, i.e. stepsize = Vdd / 1024).

In the "10" suffixed version, there is also the opportunity to add in another ADC value (Vadd) measured against a "fixed" ADC stepsize, i.e. referenced to the "Fixed Voltage Reference" (FVR). This "10" version assumes 2mV/step (i.e. the use of FVR2048 divided into 1024 steps), but is dependent on the specific choice of supply voltage.

2. Unfortunately, the on-chip diodes are arranged to "hang down" from the supply rail (Vdd) so the second stage of calculation must subtract the previous measured/calculated voltage from Vdd (multiplied by the number of measurements which were made) to obtain the voltage across the diodes themselves.

The above value is then scaled (to integer degrees or tenths) by a factor determined from the number of diodes and their tempertature coefficient (i.e. degrees per mV). To achieve good accuracy, this uses the ** operator, which requires the effective calibration factor (multiplier) to be less than unity (i.e. no more than 65535 / 65536). Thus a "0.1 degree" resolution result needs an input totalling at least 10 mV/C (or a minimum of 8 diodes, assuming a tempco of 1.25 mV/diode/degreeC).

3. The third stage is to subtract the previously-obtained value from an "offset" constant which represents the (theoretical) temperature when there would be a zero voltage drop across the diodes (typically around 500 degrees C or 900 degrees F ! ). However, this is also the point in the calculation at which a negative result (if appropriate) can arise (it is correctly reported as a "twos complement" value). Therefore, it may be better to adopt a "suppressed zero" reference such as -40 degrees (same in C and F) or -55 degrees C (limit of a DS 18B20 sensor). This is particularly relevant if the data is to be averaged, because 2's complement values cannot be simply summed and divided.


The remainder of the listing is intended as a demonstration/test, not as definitive program code. The problem is that there is a large number of permutations of "candidate" code for the four basic program modules, so it is difficult to define a single "optimum" version (or even several) :

However, a "minimum code size" version does have several unique features (including operation over the entire range of 14/20M2 supply voltages) and happens to give quite reasonable resolution and (post-calibration-) accuracy (within 2 or 3 degrees C) over the full range. It occupies less than 40 bytes of program code space (comparable to a single READNTERNALTEMP _xVx command), but only by "working around" the bugs in PE5 (not when using PE6 because the "bugfixed" code in PE6 is rather inefficient in code size).

So here is my present version which can be usefully put at the top of any (M2) program to give a warning not only of any unexpected reboots, but also of a low supply voltage and perhaps of (previous) excessive power dissipation.

Code:
symbol tempw = w1
symbol Vdd = S_W2
symbol CALVDD20 = 52429		; Adjust to calibrate Vdd, nominally 1024 * 1024 / 20 = 52429
symbol ITZERO = 500		; Adjust to calibrate to room temperature (+/- 1 unit per degree C)
symbol TEMPCO = 124		; Temperature coefficient of the on-chip diodes (mV/C * 100)
symbol SLOPE2 = 3276800 / TEMPCO		; 65536 divided by number of diodes (2) and Tempco (mV/C)

#define USEPE5				; Delete for PE6 or AxePad 1.5.1			
ChipTempMin:				; About 35 bytes with PE5 (excluding the SERTXD output line)
	calibadc10 tempw					; Measure FVR1024 relative to Vdd
	Vdd = CALVDD20 / tempw * 20			; Calculate the Vdd in mV 
#ifdef USEPE5
	readinternaltemp IT_RAW_H,0,tempw		; Read voltage for two diodes
#else
	readinternaltemp IT_RAW_L,0,tempw		; Read voltage for two diodes
#endif
	tempw = tempw * 64 ** Vdd			; Number of ADC steps * Vdd (stepsize)
	tempw = Vdd - tempw ** SLOPE2		; Subtract from Vdd and Scale to degrees
	tempw = ITZERO - tempw			; Calibrate to reference temperature (0C, or -40, etc.)
	sertxd(cr,lf,"Vdd=",#Vdd,"mV,",#w1,"C")	; Report Vdd and Temperature
return
At the other extreme, a "High Resolution" version can achieve around 0.2 degree C resolution, but requires up to 200 bytes of codespace. Note that the "12 diodes" version shown in the demo code above is a "cheat" because simply multiplying the voltage across 6 diodes by 2 does not actually double the measurement resolution. My "real" High Res. version doesn't use the READINTERNALTEMP commands at all, but is coded in an "assembler" fashion (using POKE/PEEKSFR commands). This has a subsidiary advantage that the same program code compiles correctly in both PE5 or PE6, but it is sufficiently complex that a separate thread/post is more appropriate.

Sadly, the "best" construct to achieve an obvious target of 1 degree (C or F) nominal resolution is not easy to define. My new "ReadVdd" routine has simplified the supply voltage measurement for the "medium-accuracy" requirement, but it is still difficult to determine to what extent "averaging" of multiple values can produce a genuine increase in resolution.

In due course, more "complete" versions of program code may be added to this thread, or perhaps some of the others linked above, where appropriate.

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

More than two years on, so maybe it's time for an update and cross-linking to a later related topic. Also, with hindsight, my description above does look rather overwhelming, so perhaps a little more KISS this time. ;)

Hippy has recently devised a method (in post #17 here) which allows a program to automatically detect whether READINTERNALTEMP was generated by the (flawed but compact) PE5 or by PE6. However, the method requires a considerable number of (pre-compiler) #commands (up to ~20 for the generalised version), and still can't discriminate between different compiler versions in AxePad, so it doesn't really meet my ideals. :(

Also, the PE6 "patch" consumes a large number of program bytes, so it seems simpler to just ignore the READINTERNALTEMP command and determine the raw temperature voltage directly, by using just a few SFR commands. Therefore, below is a revised "Universal" program which can employ any version of Editor/Compiler and any supply voltage, either for a general purpose "bootup test header" or in the form of a subroutine.

Code:
; PICaxe Chip temperature measurement for ANY Vdd (<2 - 6 volts)
; AllyCat March 2018
#picaxe 20m2					; Or any other M2
#no_data
; #define MINCODE   				; Saves about 12 bytes of program code

symbol tempw = w1				; Temporary Word variable (byte-addressable)
symbol Vdd = s_w2				; Measured Supply voltage (normally in mV)
symbol CALVDD18 = 58254			; ** Trim value to calibrate Vdd, nominally 1024 * 1024 / 18 = 58254
symbol ITZEROC = 505			; ** Adjust to calibrate to room temperature (+/- 1 unit per degree C)
symbol TEMPCO = 124				; Temperature coefficient of each on-chip diode (mV/C * 100)
symbol SLOPE2C = 3276800 / TEMPCO		; 65536 divided by number of diodes (2) and Tempco (mV/C)
; SFR addresses
symbol ADRESL 	= $3B		     	 	; ADC result Low byte
symbol ADRESH 	= $3C				; ADC High byte
symbol ADCON0 	= $3D				; ADC control register 0
symbol ADCON1   = $3E				; ADC control register 1
symbol FVRCON 	= $57		   	   	; FVR & Temperature sensor Control Register (same as FVRSETUP)

ChipTempU:					; Universal Chip Temperature (sub)routine to use ANY supply voltage 
	calibadc10 tempw			; Measure FVR1024 relative to Vdd [~3 bytes]

#ifdef MINCODE					; Save ~12 program bytes by measuring the Vdd less precisely
	Vdd = CALVDD18 / tempw * 18		; Calculate the Vdd in mV (resolution 18mV = ~2 degC)
#else	  					; [~22 bytes]
	Vdd = tempw / 2 + CALVDD18 / tempw	; Calculate Vdd in steps of 18mV (rounded up by LSb/2)
	calibadc10 tempw			; Measure FVR1024 relative to Vdd again
	Vdd = CALVDD18 / tempw + Vdd * 9	; Merge the Vdds into mV (resolution 9mV = ~1 degC)
#endif

rawinternaltemp_L:  				; [~8 bytes]
	pokesfr ADCON1, %10010000 	   	; Right justify result (0 - 1023); clock/8; REFerence = Vdd
	pokesfr FVRCON, %10100000 		; 2 diode Temperature sensor ON [$20] & (optional) FVR ON [$80]        
;	fvrsetup $A0 	 		 	; Can be used as an alternative to POKESFR FVRCON,$A0
readitemp:  					; [~13 bytes]
	pokesfr ADCON0, %01110101 		; Select Temperature input and Turn ADC On
	pokesfr ADCON0, %01110111 		; Start conversion
	peeksfr ADRESL,WORD tempw		; Read lower and upper bytes into tempw and fall into chiptemp
chiptemp:	  				; [~19 bytes]
	tempw = tempw * 64 ** Vdd		; Number of ADC steps * stepsize (= Vdd / 1024)
	tempw = Vdd - tempw ** SLOPE2C		; Subtract from Vdd and Scale to degrees
	tempw = ITZEROC - tempw			; Calibrate to reference base temperature (0C, or -40, etc.)
; return					; If used as a subroutine
	sertxd(cr,lf,"Vdd=",#Vdd,"mV,",#w1,"C")	; Report Vdd and Temperature [~20 bytes]
Just one compilation option (in addition to the essential calibration stage) which can save about 12 program bytes at the expense of slightly reduced accuracy. The program measures across only two sensing diodes and since the ADC is referenced to the supply rail, the resolution step size is increased at higher supply voltages. For example at Vdd = 5v the ADC resolution is ~5mV/step, but the tempco only 2.5 mV/degree C, so around 2 degrees resolution at best.

Then, the "sensitivity" to the supply rail voltage is about 110 degrees C per volt whilst the best resolution that can be achieved for the Vdd, using a single pass, is 17 mV (i.e. ~2 degrees C): A limiting factor is PICaxe's 16 bit integer division, but a simple trick is to add the "rounded up" value from a second computation (by first adding half of the divisor to the numerator) to double the result. Furthermore, the CALIBADC10 value contains some "noise", particularly at higher Vdds, so it's worthwhile to also repeat this measurement, since it adds only ~3 bytes to the program. Thus the supply rail measurement increments can be halved to around 9 mV, equivalent to an offset of 1 degree C.

Still to come, a few more variations to give an overall resolution of 1 degree C (and perhaps F).

Cheers, Alan.
 

PhilHornby

Senior Member
Have I missed the bit where you describe how to calibrate this?

I get this on a 14M2 :-
Code:
Vdd=4869mV,65524C
The voltage is within the realms of reason, but I can't make out what the temperature reading is trying to tell me :confused:
 

techElder

Well-known member
I heard it was extremely cold there this weekend, but I didn't think it was cold enough for the Celsius scale to do a PICAXE "wraparound!" :D
 

AllyCat

Senior Member
Hi,

Thanks for taking an interest.

Last, but definitely not least, the temperature MUST be calibrated for every individual target chip. This is intentionally the last stage in the calculation, which ensures that the calibration is applied directly in integer degrees (or tenths in the case of the "decimal" version). Thus, a single calibration operation is sufficient: The first time the program is run, simply subtract the reported temperature from the actual (room) temperature and apply the numerical value directly to the appropriate "calibration constant", ITZ{10} , within the program.
It's reporting a (16-bit two's-complement) temperature of -12 degrees C. Update ITZ by adding 12 plus the estimated room temperature and run it again. That's all that should be needed, unlike the PICaxe's READINTERNALTEMP which wraps backwards to different arbitrary values (in the region of 5000) dependent on the voltage used.

As Microchip say in their new Application Note (linked in my "related topic" in #3), "Generally this equation will produce an uncalibrated temperature value that is within 100°C of the actual temperature." ;)

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

Another two years on, so it's time for another "update". I've now looked in more detail at the newer Application Note AN2092 which I've discussed in this thread so here are a few revisions to the programs above. The problem remains that there is an enormous number of variations that can be employed in the supply rail measurement and in the temperature calculation, so it's only practical to show a few examples.

Firstly, this "minimum code size" version has an additional benefit that it functions over the full range of PICaxe supply voltages, although it should give better accuracy with lower supply rails. However, some enhancements require only a small number of additional code bytes so may offer a better compromise, but the absolute minimum size may be adequate for some applications. For example, compensating for the temperature coefficients of some external components such as a crystal oscillator (frequency) or diode forward (voltage) drop.

Just a few initialisation options are included: If PE5 is available, then the compiled code can be about 12 bytes smaller, but the "normal" (PE6 compatible) version will also work correctly with PE5. The reasons have been explained in previous posts above and elsewhere. Before running the program, adjust the ESTIMATEDVDD value, it's not essential but should improve the temperature tracking (and will affect any subsequent calibration). If required, any fractional part of a volt may be trimmed into the resulting VDDTCO value.

The "Zero" calibration is intentionally set high to avoid an uncalibrated program generating a negative result. Even this simplest version does correctly calculate a two's complement (negative) temperature, but does not display it as a negative value (i.e. with a minus sign). After the first run, subtract a suitable value (i.e. 1 unit per degree C error) from {IT}ZEROC to calibrate to the estimated Room Temperature; It is not necessary to calibrate the CALVDD18 value to use just the CHIPTEMP function. The basic subroutine compiles to less than 50 program bytes with the full "test harness" of less than 100 bytes. As said several times already in this thread, it is ESSENTIAL to calibrate every individual PICaxe chip before use as a temperature sensor.

Code:
; Minimised PICaxe Chip temperature measurement for ANY valid Vdd <2 to 6 volts (<4v preferable)
; AllyCat, March 2018, Revised July 2020.
#picaxe 14m2                                ; Or any other M2
#no_data
#terminal 4800        
; #define USEPE5                            ; Reduces code size if PE5 is available (saves ~12 bytes)
symbol ESTIMATEDVDD = 4                    ; ** To optimise the assumed temperature coefficient **
symbol CALVDD18= 58750                    ; ** Trim to calibrate Vdd, nominally 1024 * 1024 / 18 = 58254 **
symbol ITZEROC = 582                     ; ** Adjust to calibrate to room temperature (+/- 1 unit per deg C) **
symbol ZEROC = ITZEROC + 75       ; Increase ZEROC to avoid generating a negative value before calibration
symbol tempb = b1                             ; Temporary Byte variable
symbol tempw = w1                            ; Temporary Word variable (byte and bit-addressable)
symbol Vdd = s_w2                              ; Measured Supply voltage (normally in mV)
symbol VDDTCO    = ESTIMATEDVDD * 13    ; (Negative) Volts * PP100k/C (e.g. 4 * 130ppm)
symbol TEMPCO    = 275 - VDDTCO            ; Temperature coefficient of two diodes and VDD (-mV/C * 100)
symbol SLOPE     = 6553600 / TEMPCO    ; C/mV (fractional) multiplier = 65536 divided by Tempco (mV/C)
; SFR addresses
symbol ADRESL     = $3B                         ; ADC result Low byte
symbol ADRESH     = $3C                        ; ADC result High byte
symbol ADCON0     = $3D                        ; ADC control register 0
symbol ADCON1  = $3E                        ; ADC control register 1
symbol FVRCON     = $57                       ; FVR & Temperature sensor Control Register (same as FVRSETUP)

main:
do
    call chiptempM
    sertxd(cr,lf,"Vdd= ",#Vdd )
    sertxd("mV , ",#tempw," C")                ; Report Vdd and Temperature
    pause 5000
loop
 
ChipTempM:                      ; Minimised Chip Temperature (sub)routine to use ANY valid supply voltage
    calibadc10 tempw                        ; Measure FVR1024 relative to Vdd
    Vdd = CALVDD18 / tempw * 18        ; Calculate the Vdd in mV (resolution 18mV = ~2 degC)
#IFDEF USEPE5
    readinternaltemp IT_RAW_H,0,tempw ; ADC value (steps) for 2 diodes (bugfixed for PE5)
#ELSE
rawitemp_L:
    pokesfr ADCON1, %10010000            ; Right justify result (0 - 1023); clock/8; REFerence = Vdd
    pokesfr FVRCON, %10100000             ; 2 diode Temperature sensor ON [$20] & (optional) FVR ON [$80]        
readitemp:
    pokesfr ADCON0, %01110101             ; Select Temperature input and Turn ADC On
    pokesfr ADCON0, %01110111             ; Start conversion
    peeksfr ADRESL,WORD tempw            ; Read lower and upper bytes into tempw and fall into chiptemp
#ENDIF
chiptemp: 
    tempw = tempw * 64 ** Vdd            ; Number of ADC steps * stepsize (= Vdd / 1024)
    tempw = Vdd - tempw ** SLOPE        ; Subtract from Vdd and Scale to degrees
    tempw = ZEROC - tempw                ; Calibrate to reference base temperature (0C, or -40, etc.)    
return

#IFDEF USEPE5                                ; Trap for erroneous use of PE6
#define stop #error *** DO NOT SELECT "USEPE5" WITH PE6 ! ***
stop
#ENDIF
The next version will add code to measure the supply voltage to a higher resolution, to compensate for the non-linear curvature of the temperature coefficient over a wide temperature range, and to report negative values correctly signed, etc..

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

Here is an extended version of the above program, but still using only two sensing diodes so that it can work down to the lowest supply voltages (and up to the highest but with reduced temperature resolution). The first change is that it uses a (sub)routine to measure the supply rail more accurately. The previous program could resolve to only a band of 18mV which introduces a "dither" to the calculated temperature over a range of about 3 degrees C. The version below resolves to a band of about 6mV so should reduce the dither to around 1 degree. It uses a combination of methods I've described before, basically "oversampling" (i.e. accumulating multiple measurements) and using the DAC (programmable voltage divider) to introduce "noise" to spread the voltage signal across several ADC threshold levels to prevent becoming "locked" between steps.

Unfortunately, it's not possible to improve the voltage measurement across the two sensor diodes very much: Because the diodes "hang down" from the supply rail, it's necessary to apply the full supply voltage across the ADC reference chain (i.e. around 4 mV/step, even using READADC10). Also, it's not possible to use the FVR without seriously affecting the range of supply voltages that can be used. For example, the "Six Sigma" graph in AN2092 indicates that the voltage drop across 2 diodes could range from 0.6 to 1.6 volts, which suggests that the maximum supply rail when using FVR2048 would be 2.05 + 0.6 = 2.65 volts. Four diodes could drop 1.2 to 3.2 volts, so the "only" supply rail that might be used is about 3.2 volts, possibly useful, but the present issue is the poor resolution at the higher supply voltages. With the temperature coefficient of two diodes being about 2.2 mV/C and an ADC resolution around 5 mV, a temperature resolution of no better than 2 degrees C has to be expected at the higher voltages.

Another addition is the "one liner" compensation for the non-linear part of the temperature coefficient. But I will describe that in my separate thread in the Active Forum because its calculation may be of more general interest. This compensation may affect the extremes of the temperature range by up to 5 degrees C, but the central section between zero and 60 degrees C hardly at all (if using a one degree displayed resolution). Finally, the program supports the addition of an 18B20 precision temperature sensor to assist calibration, which can be plugged in to almost any three "spare" port pins, except any "Input Only" (or "Output Only" for the data line) pins.

So here is probably about the "best" that can be done using only two sensing diodes (i.e. for supply voltages below approximately 3.5 volts).
Code:
; "Universal" PICaxe Chip temperature measurement for ANY valid Vdd <2 to 6 volts (<4v preferable)
; AllyCat, March 2018, Revised July 2020.

#picaxe 14m2                                ; Or any other M2
#no_data
#terminal 4800
#define USE18B20                            ; To assist calibration
symbol ESTIMATEDVDD = 4                    ; ** Nominal supply voltage (to compensate for FVR tempco) **
symbol ZEROC = 585                        ; ** Adjust to calibrate to room temperature (+/- 1 unit per deg C) **
symbol VDDTCO = ESTIMATEDVDD * 13    ; Supply Volts * PP100k/C (e.g. 4 * 130ppm) **
symbol CALVDD2 = 57826                    ; 64 / 34 levels @ 2mV/step  =(65536 + 57826) / 65536
symbol tempb = b1                            ; Temporary byte variable
symbol tempw = w1                           ; Temporary Word variable (bit and byte-addressable)
symbol Vdd = s_w2                            ; Measured Supply voltage (normally in mV)
symbol TEMPCO = 275 - VDDTCO             ; Temperature coefficient of both diodes and VDD (-mV/C * 100)
symbol SLOPE = 6553600 / TEMPCO       ; C/mV (fractional) multiplier - 65536 divided by Tempco (mV/C)
; SFR addresses
symbol ADRESL = $3B                      ; ADC result Low byte
symbol ADRESH = $3C                     ; ADC High byte
symbol ADCON0 = $3D                    ; ADC control register 0
symbol ADCON1 = $3E                        ; ADC control register 1
symbol FVRCON = $57                     ; FVR & Temperature sensor Control Register (same as FVRSETUP)
#IFDEF USE18B20
    low c.0                                    ; Earth the 18B20
    high c.4                                    ; Power the 18B20
    pullup $200                              ; C.1 = 18B20 Data line
#ENDIF

main:
do
    call readVdd2
    call chiptempU
    sertxd(cr,lf,"Vdd=",#Vdd," mV, ")  ; Report Vdd
    tempb = tempw                          ; Don't corrupt the 2's complement value
    if tempw > 32767 then                ; Negative temperature
        tempb = -tempw                     ; Negate 
        sertxd("-")                            ; Report negative value
    endif
    sertxd(#tempb," C")                   ; Report (signed) Temperature
    call show18B20
    pause 5000
loop

ReadVdd2:
    fvrsetup fvr2048                        ; Will be used as ADC/DAC reference voltage 
    dacsetup $80                            ; Enable DAC with Vdd reference
    adcconfig 3                                ; FVR reference for ADC                                
    Vdd = 0                                    ; Prepare to accumulate the Vdd measurements
    for tempb = 7 to 10                    ; 10 is Highest level to accommodate Vdd = 6v (if FVR = 2048)     
        daclevel tempb                        ; "Randomise" the pot-divided sample
        readdac10 tempw                     ; Note this command uses DAC (not ADC)
        Vdd = Vdd + tempw                    ; Accumulate scaled Vdd = 4 loops of 1023max * Vdd / 32 
    next tempb
    Vdd = Vdd ** CALVDD2 + Vdd            ; Calibrate to mV units (1 < coefficient < 2)
return

ChipTempU:                                    ; Universal Chip Temperature (sub)routine to use ANY supply voltage
rawinternaltemp_L:                          ; [~8 bytes]
    pokesfr ADCON1, %10010000            ; Right justify result (0 - 1023); clock/8; REFerence = Vdd
    pokesfr FVRCON, %10100000             ; 2 diode Temperature sensor ON [$20] & (optional) FVR ON [$80]        
readitemp:                                  ; [~13 bytes]
    pokesfr ADCON0, %01110101             ; Select Temperature input and Turn ADC On
    pokesfr ADCON0, %01110111             ; Start conversion
    peeksfr ADRESL,WORD tempw            ; Read lower and upper bytes into tempw and fall into chiptemp
    tempw = tempw * 64 ** Vdd            ; Number of ADC steps * stepsize (= Vdd / 1024)
    tempw = Vdd - tempw ** SLOPE        ; Subtract from Vdd and Scale to degrees
    tempw = ZEROC - tempw                ; Calibrate to reference base temperature (0C, or -40, etc.)    
; Non-linear compensation:  T * T * 0.00075 - T * 0.067 + 1.5  becomes T * T * 737 / 65535 - T + 23 / 15    
    tempw = tempw * tempw ** 737 - tempw + 23 / 15 + tempw    ; Add Non-linear component  [~13 bytes]
return

show18B20:
#IFDEF USE18B20
    sertxd(" , 18B20= ")
    readtemp12 c.1,tempw
    if tempw > 32767 then                ; It's a negative temperature
        sertxd("-")
        tempw = -tempw
    endif
    tempb = tempw AND 15 * 10 / 16    ; Decimal (fractional) part
    tempw = tempw / 16                    ; Integer part
    sertxd(#tempw,".",#tempb," C") 
#ENDIF
return
So now for the "proof of the pudding", not quite literally. I loaded exactly the above program into a 14M2 and put it in and out of the freezer over a period of a few hours, recording the SERTXD output on the PE6 terminal emulator (which has a much larger buffer than PE5). Then I transferred the file to Excel (or LibreOfficeCalc to be precise), selected the appropriate columns, hit the graph button and clipped the results, attached below. The Left graph compares the ChipTemp with the 18B20 over several hours and on the Right is an X-Y scatter diagram of the measured battery voltage against temperature. More obvious in real time than in the graphs, the PICaxe chip temperature lagged the 18B20 quite significantly as shown by the lower amplitude and more rounded ripple of the thermostat/compressor cycles. A freezer is quite a good calibration tool as it creates a usefully large temperature difference (over 40 degrees C) and is reasonably stable because of its thermal insulation. But of course the first requirement for calibration is to perform it over the same range that the sensor will actually be used!

It can be seen that even my latest calibration data is still almost 10% short of the actual temperature range, but the second diagram is revealing. I had been surprised how stable were my NiMH cells in the freezer, but here they were located outside it (and the current drain very low). So their voltage can be considered constant and the measurement actually indicates the temperature coefficient of the PICaxe Fixed Voltage Reference. This highlights another application for the Chiptemp algorithm, it can be used to improve the "accuracy" of the FVR when making precise voltage measurements. We know that the temperature range was around 45 degrees and the voltage range is about 38 mV in the scatter diagram, so the temperature coefficient is 38 / 45 = 0.85 mV/C, or about 220 ppm/C. That's more than 50% greater than the data sheet suggests (but not as high as some of the 78{L}05 data sheets) and pushes the effective "diode" tempco down to almost exactly 1 mV/C each. With that value applied in the program, the calibration should be close to "perfect", but it's becoming clear that some more two-point calibration measurements are needed.

FreezerTest200712A.png

My next version of the program is planned to use the four series diodes, which should both improve the resolution and reduce the effects of the "unstable" supply rail voltage.

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

Here is perhaps the "final" version of my CHIPTEMP algorithm/program. It's based on the original CHIPTEMP10 (above) but I've revised the Calibration Constants, added the Non-Linear compensation, optional use of the FVR4096 as a voltage reference, conversion to degrees F and DS18B20 support for calibration. It still uses an internal (computational) resolution of 0.1 C, but it's unlikely that the raw hardware can achieve that in practice, so I have renamed it CHIPTEMP4. The "4" is intended to show the number of diodes used for sensing, but it's also a better indicator of the increased resolution available, and the minimum supply Voltage that can be used. The PICaxe Manual specifies 4.0 volts but the, normally very pessimistic, Microchip datasheet 3.6 volts, and in practice probably 3.3 volts, or a little lower, should be possible (particularly if the lowest temperatures will not be encountered). However, the compilation option which uses the FVR4096 reference needs a higher Vdd, probably around 4.5 volts (4.1 volts reference with some allowance for tolerances and headroom).

The primary purpose of the USEFVR option is to measure the (4) diodes' voltage drop against a "different" reference voltage (in addition to Vdd) to "spread" or randomise the 1024 levels available in the ADC. Thus, this option accumulates three measurements (one across 2 diodes, two across 4 diodes) to give an "independent" voltage across 10 diodes. The alternative version accumulates only two voltages (across 2 and 4 diodes) but then doubles it to give a sufficiently large value for the "0.1 C" calculation. It's possible that physically duplicating those measurements would add a little more (desirable) "randomness", at the expense of additional program size. Another advantage of adding the values for both 2 and 4 diodes is that the "bug" in PE5 (which swaps the 2 and 4 diode modes) can be ignored when both are being read and combined. Therefore, if no FVR reference is to be used, the resident READINTERNALTEMP command can be employed (in place of the direct SFR access method), although no reduction in program size occurs with PE6.

A modified version of the READVDD subroutine is shown, to give slightly better resolution, but the (faster) version above should be adequate for most purposes. The earlier version accumulates four voltages at DAC (divider) output levels of 10, 9 , 8 and 7 = 34 where each level can add up to about another 100 ADC steps, so a calibration multiplier of between 1.0 and 2.0 is required to give a mV value up to 6,000 (6v). The later version accumulates values for all levels from 1 .. 11, a total of 66 levels, so a multiplier of < 1.0 can be used to calibrate in single mV steps. Strictly, the largest nominal Vdd that can be measured (accurately) is 32 / 11 * 2.048 volts = 5.94 volts, and the maximum calibration range is +3%, but they are unlikely to be an issue in practice. A slightly higher resolution might be achieved using my CALIBADC15 routine, followed by the "double word" division (31 / 16 bits), but that's probably an unnecessary complication, unless the highest supply resolution is required for another purpose.

In this version, the Non-Linear compensation receives a value in tenths of a C (i.e. 10 times larger) which would overflow a 16-bit word calculation. The easiest solution is to scale down to use the previous formula, but the input value is signed (two's complement) which needs to be taken into account, and also the compensation result must not be negative before it is scaled-down (i.e. divided) by a factor of 3/2.

In some respects the Fahrenheit scale is more useful than Centigrade (Celsius), with almost double the resolution of an integer value and temperatures rarely negative. Therefore, I originally planned to create a simpler program to work "natively" in degrees F, i.e. with calibration constants directly in degrees F (which is quite feasible) without the complication of displaying a decimal point or negative sign. However, all the raw calibration data is supplied in C, including the new Non-Linear correction formula, and a domestic freezer can achieve negative F temperatures. Therefore, I just devised a (signed) C to F conversion routine, or a similar resolution could be displayed by using a "half" symbol / digit with the Centigrade scale.

The output from all these program versions has a tendency to "dither" between values, because most introduce some "noise" to improve the resolution, but there is no filtering between consecutive measurements. This was intentional because filtering (or averaging) the displayed result will tend to hide the basic behaviour and performance of the algorithm, which is currently of interest. Also the timescale (i.e. the time constant) and degree of filtering can be very dependent on the requirements for any particular application, so that must be for the developer / user to decide. The "decimal" (fractional) part of the result does give additional headroom for rounding, or to add hysteresis to a displayed result and / or multiple iterations can be added and averaged to produce a "smoother" and perhaps higher resolution final result.

The complete program was slightly above the forum's 10,000 character limit, but it's highly commented and "White Space(s)" appears to add considerably to the calculated size, so its listing must wait for the next post:

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

Here is the "final" program :
Code:
; CHIPTEMP4 : A calculation algorithm for the internal chip temperature using 4 diodes in M2 PICAXEs.
;  AllyCat, February 2016, Revised July 2020.  Minimum Vdd ~3.3v (or ~4.4v if FVR is used)

#picaxe 14m2           ; Or any other M2  ** MUST be calibrated before Use **
#no_data
#terminal 4800
#define USE_FVR     ; [~same code size] ; ** Include FVR ADC measurement (10 diodes total), Vdd min = 4.4v **
#define USE18B20    ; [adds ~64 bytes]  ; ** To assist temperature calibration **
; Calibration Constants:                ; ** Adjust to calibrate Vdd, testing configuration and tempcos **
symbol CALVDD11  = 63550                ; 66 levels / 64 @ 2mV/step [64/66 * 65536 = 63550]
#IFDEF USE_FVR                          ; Uses 2 + 4 (Ref Vdd) + 4 (Ref FVR4096) = 10 diode drops (3 samples)
symbol ITZ10     = 6295                 ; ** Calibration offset temperature value in tenths of a degree C **
symbol NVDDA     = 3                    ; ** Accumulated Number of times Vdd is included (number of RITs) **
symbol VDDTCO    = 5 * 20               ; ** (Negative) Supply tempco:  Volts * PP100k/C (e.g. 5 * 130ppm) **
symbol NDIODE    = 10                   ; ** Accumulated number of diodes measured **
#ELSE                                   ; Uses 2 + 4 * 2 = 12 diode drops (4 samples)
symbol ITZ10     = 6460                 ; ** Calibration offset temperature value in tenths of a degree C **
symbol NVDDA     = 4                    ; ** Accumulated Number of times Vdd is included (number of RITs) **
symbol VDDTCO    = 5 * 20               ; ** (Negative) Supply tempco: Volts * PP100k/C (e.g. 4 * 130ppm)  **
symbol NDIODE    = 12                   ; ** Accumulated number of diodes measured **
#ENDIF
symbol TMPCOD    = 138 * NDIODE         ; Accumulated Tempco of all diode measurements
symbol TMPCOV    = VDDTCO * NVDDA       ; Supply tempco * number of measurements
symbol TMPCO     = TMPCOD - TMPCOV      ; Effective tempco for accumulated measurements (mV/C * 100)
symbol INVTCO  = $4000000 / TMPCO       ; Inverse temperature coefficient (C/mV) scaled 0.1C/mV
; SFR addresses
symbol ADRESL  = $3B                    ; ADC result Low byte
symbol ADRESH  = $3C                    ; ADC High byte
symbol ADCON0  = $3D                    ; ADC control register 0
symbol ADCON1  = $3E                    ; ADC control register 1
symbol FVRCON  = $57                    ; FVR & Temperature sensor Control Register (same as FVRSETUP)
; Variables:
symbol tempb   = b1                     ; Temporary/Local Byte, also for passing parameters etc.
symbol tempw   = w1                     ; Temporary/Local Word, also for passing parameters, etc.
symbol Vdd     = w2                     ; PICaxe supply rail voltage in mV
symbol wa      = w3                     ; Auxiliary Word variable, required for some local calculations
symbol waLo    = b6                     ; Low byte of WA
symbol waHi    = b7                     ; High byte of WA
    pause 1000
    sertxd(cr,lf,"Tempco=",#TMPCO)
    sertxd(" / ",#NDIODE," , Slope= ",#INVTCO)
#IFDEF USE18B20
    low c.0                              ; ** Ground the 18B20 pin **  
    high c.4                             ; ** Power the 18B20 pin **
    pullup $200                          ; ** C.1 = 18B20 Data line **
#ENDIF
main:
do                                       ; First measure the basic Vdd and Raw Chip Temperature voltages:
    call ReadVdd11                       ; Higher accuracy measurement for Vdd (in mV)
    sertxd(cr,lf,"Vdd= ",#Vdd," mV ")    ; Report the supply voltage
    call chiptemp4                       ; Measurement uses 4 temperature-sensor diodes
    tempb = "c"                          ; Temperature Units symbol (uncompensated)
    call showST                          ; Report Uncompensated Temperature
    call NLcomp10                        ; Add Non-Linear compensation
    call showSTC                         ; Report Compensated temperature
convCF:                                  ; Convert and Report integer temperature in F
    tempw = tempw + 400 * 9 / 50 - 40    ; Convert C*10 to degrees F
    tempb = tempw                        ; Don't corrupt 2's complement result
    if tempw > 32767 then                ; Negative temperature
        tempb = -tempw : sertxd("-")     ; Negate and report
    endif
    sertxd(#tempb," F ")                 ; Report (only) Integer value and scale
    call show18B20
    pause 5000
loop
chiptemp4:                               ; Read chiptemp using 4 diodes (minimum Vdd ~3.3 volts)
#IFDEF USE_FVR                           ; FVR version must use SFR commands (otherwise optional)
readitemp:
    pokesfr ADCON1,%10010000             ; Right justify result (0 - 1023); clock/8; REFerence = Vdd
    pokesfr FVRCON,%10100000             ; Enable 2 diodes sensor [$20] & (optional) FVR [$80]      
rawinternaltemp_L:                       ; Read voltage with 2 diodes
    pokesfr ADCON0,%01110101             ; Select Temperature input and Turn ADC On
    pokesfr ADCON0,%01110111             ; Start conversion
    peeksfr ADRESL,WORD tempw            ; Read lower and upper bytes into tempw
rawinternaltemp_H:                       ; Read voltage with 4 diodes
    pokesfr FVRCON,%10110011             ; Enable 4 diodes sensor [$30] & FVR4096 [$83]      
    pokesfr ADCON0,%01110101             ; Select Temperature input and Turn ADC On
    pokesfr ADCON0,%01110111             ; Start conversion
    peeksfr ADRESL,WORD wa               ; Read lower and upper bytes into wa
    tempw = tempw + wa                   ; Combine the 2 and 4 diodes values for better resolution
fvrreference:                            ; Read voltage for 4 diodes referenced to 4v FVR
    pokesfr ADCON1,%10010011             ; Right justify result (0 - 1023); clock/8; REFerence = FVR     
    pokesfr ADCON0,%01110101             ; Select Temperature input and Turn ADC On
    pokesfr ADCON0,%01110111             ; Start conversion
    peeksfr ADRESL,WORD wa               ; Read referenced to FVR into wa and fall into chiptemp  
#ELSE    /USE_FVR                        ; Use the resident commands (uses more bytes with PE6)
    readinternaltemp IT_RAW_H,0,wa       ; ADC value (steps) for 4 diodes (2 diodes with PE5)
    fvrsetup %10111010                   ; Bugfix for PE5 if required (selects 4 diodes)  
    readinternaltemp IT_RAW_L,0,tempw    ; ADC value for 2 diodes (4 diodes with PE5)
    tempw = tempw + wa * 2               ; Combine & double for 12 diodes (measurement includes Vdd * 4 )
    wa = 0                               ; Zero unless a FVR was (also) used
#ENDIF
ChipTemp10:                              ; Input parameters are in Vdd, tempw & wa, result in tempw
    tempw = tempw * 16 ** Vdd            ; Number of ADC steps * stepsize (Vdd/4096) (Max 4 ADC values)
    tempw = tempw + wa * 4               ; Add any ADC steps referenced to FVR4096 (mV*4) & scale to mV
    tempw = Vdd * NVDDA - tempw          ; Subtract from sum of Vdds
    tempw = tempw ** INVTCO              ; Scale to degrees * 10
    tempw = ITZ10 - tempw                ; Calibrate to reference temperature (e.g. zero C)
return                                   ; Returns tempw = deg C * 10
; Compensation =  T * T * 0.00075 - T * 0.067 + 1.5 : becomes: T * T ** 737 - T + 24 / 15 (T in degrees C)
NLcomp10:                                ; Non-linear compensation for input temperature C * 10
    wa = tempw / 10                      ; Assume positive value to calculate using 1 degree units
    if tempw > 32767 then                ; It's negative (can only divide positive numbers)
        wa = -tempw / 10                 ; Do a valid division (of a positive number)
        wa = -wa                         ; Reinstate 2's complement (negative) value
    endif
     wa = wa * wa ** 737 - wa + 24 ** 43691 ; Calculate the non-linear compensation (divisor =1.5)
     tempw = tempw + wa                  ; Add in the compensation (degrees * 10)
return
showSTC:                                 ; Report temperature to 1 decimal place (with units)
    tempb = "C"                          ; Temperature scale (ASCII)
showST:                                  ; Report Signed Units.Tenths + "tempb"
    wa = tempw                           ; Don't corrupt the two's complement result
    if tempw > 32767 then                ; It's negative
        wa = -wa : sertxd("-")           ; Negate and Report sign
    endif
    wa = wa / 10 * 246 + wa              ; Split Temperature * 10 into waHi = Units : waLo = Tenths
    sertxd(#waHi,".",#waLo," ",tempb," "); Report the temperature with 1 decimal place & scale
return
ReadVdd11:
    fvrsetup fvr2048                     ; Will be used as ADC reference voltage
    dacsetup $80                         ; Enable DAC with Vdd reference
    adcconfig 3                          ; FVR reference for ADC  
    Vdd = 0                              ; Prepare to accumulate the Vdd measurement
    for tempb = 1 to 11                  ; 11 * samples allows accumulation up to 6000 steps (mV)
        daclevel tempb                   ; 11 can accommodate Vdd up to 5.9 v (if FVR = 2.048 v)       
        readdac10 tempw                  ; Note this command uses DAC (not ADC)
        Vdd = Vdd + tempw                ; Accumulate scaled Vdd levels * 1024 * 4 * Vdd / 32
    next tempb                           ; Total 66 levels
    Vdd = Vdd ** CALVDD11                ; Calibrate to mV units (scale factor < 1 )
return
show18B20:
#IFDEF USE18B20
    sertxd(" : 18B20= ")
    readtemp12 c.1,tempw
    if tempw > 32767 then                ; It's a negative value
        sertxd("-") : tempw = -tempw
    endif
    tempb = tempw and 15 * 10 / 16       ; Decimal (fractional) part
    tempw = tempw / 16                   ; Integer part
    sertxd(#tempw,".",#tempb," C")
#ENDIF
return
Cheers, Alan.
 
Last edited:
Top