### Temperaturement Measurmement using the Microchip Linear Active Thermistor

copyright, Peter H Anderson, Baltimore, MD, July, 2009

Introduction.

This discussion focuses on the Microchip MCP9701 Linear Active Thermistor. These are available for nominally \$0.25 in a convenient TO-92 package. The name linear active thermistor; the device uses an internal thermistor, but the use of an external voltage (active) results in a linear behaviour.

The operation is similar to an LM34 or LM35 with a voltage source and an output which is a linear function of temperature. That is, read an analog to digital converter and compute the temperature.

For the MCP9701, the Vout is 19.53 mV per degree C with a 0.400 volt offset to permit measuring negative temperatures. Thus;

```      Vout = Tc * 0.01953 + 0.400.  (1)
```
Thus, if Tc is -10.0, 0.0 and 25 degrees C, the corresponding voltages are 0.2047, 0.400 and 0.92825, respectively.

Assume the output of the MCP9701 is measured using a 10-bit A/D as are provided by most Microchip PICs, the PICAXE and the Arduino, with a Vref of 5.0 VDC.

```      Vout = Vref / 1024 * ADVal (2)
Vout = 5.0 / 1024 * ADVal  (3)
Vout = 0.00488 * ADVal (4)
```

Equating (4) and (1) and solving for Tc;

```     0.00488 * ADVal = Tc * 0.01953 + 0.400

Tc = 0.00488 / 0.01953 * ADVal - 0.4 / 0.01953

Tc = ADVal / 4 - 20.5

Tc_100 = 25 * ADVal - 2050
```

Note that Microchip has selected the 0.01953 (19.5 mV) coefficient as it is precisely four times the magnitude of each A/D band of 4.88 mV. The result is very simple calculations. Note that this ratio of 4 does not hold if the Vref on the processor is radically different than 5.0 VDC.

PIC6F886-I/SP using Sourceboost C

```// MCP9701.C Temperature Sensor - SourceBoost C
//
// PIC16F886 - debugged using an ICD2, MPLAB
//
// MPCP9701 temperature sensor on AN0 (term 2).
//
// Continually performs A/D AN0, calculates and display temperature in degrees C.
//
// copyright, P H Anderson, July 10, '09

#include <system.h>
#include <icd2.h>
#include <string.h>
#include <stdio.h>

#pragma DATA 0x2007, 0x28e4
#pragma DATA 0x2008, 0x3eff
#pragma CLOCK_FREQ 4000000

typedef unsigned char byte;

unsigned int ad_conv(byte channel, byte num);
void display_val(int X, byte places);
void print_str(char *s);
void asynch_setup(void);

char s[25]; // global to avoid constantly passing the string.

void main()
{
int Tc_100;

osccon = 0x61; // 4.0 MHz internal RC clock
anselh = 0x00;

ansel = 0x01;  // AN0 (term 2)

asynch_setup();
delay_s(1);
strcpy(s, "?f");
print_str(s);

while(1)
{
Tc_100 = 25 * adval - 2050;
display_val(Tc_100, 2);  // display with two sig digits after decimal point

delay_s(5);
}
}

unsigned int ad_conv(byte channel, byte num)
{  // assumes proper ansel bits have been set
// perfrom num A/D on the specified channel and averages.

unsigned int adval, sum = 0, avg;
byte n;
delay_ms(1);
for (n=0; n<num; n++)
{
{
}
}
avg = sum / num;
return(avg);
}

void asynch_setup(void)
{   // for UART, see Manual pages beginning at page 151
trisc.7 = 1;
trisc.6 = 1;    // TX
rcsta.SPEN = 1; // enable serial port
txsta.TXEN = 1; // enable transmitter
txsta.SYNC = 0; // asynchronous
txsta.BRGH = 1;

spbrg = 25; // 9600 baud at 4.0 MHz
}

void display_val(int X, byte places)
{
// Need to add provision for the number of places after the decimal point.
// This implementation assumes two places.

int whole, fract;
if (X < 0)
{
X = -X;
strcpy(s, "-");
print_str(s);

}
whole = X / 100; // more work here
fract = X % 100;
sprintf(s, "%d", whole);
print_str(s);
strcpy(s, ".");
print_str(s);
if (fract < 10)
{
strcpy(s, "0");
print_str(s);
}
sprintf(s, "%d", fract);
print_str(s);
strcpy(s, "?n");
print_str(s);
}

void print_str(char *s)
{
while(*s != '\0')
{
txreg = *s;
while(txsta.TRMT == 0)
{
}
++s;
}
}
```

Arduino

```// MCP9701.pde - Arduino
//
// Illustrates an interface with an MCP9701 temperature sensor.
//
// Continually measures the output of the MCP9701 on ADC0, calculates
// Tc_100 and displays.
//
// copyright, Peter H. Anderson, July, '09

void setup()
{
Serial.begin(9600);
delay(1000);
digitalWrite(7, LOW);
pinMode(7, OUTPUT);
}

void loop()
{
while(1)
{
digitalWrite(7, HIGH);
delay(100);
digitalWrite(7, LOW);
Tc_100 = 25 * ADVal - 2050;

whole = Tc_100 / 100;
fract = Tc_100 % 100;

Serial.print(whole);
Serial.print(".");
if (fract < 10)
{
Serial.print("0");
}
Serial.println(fract);

delay(1000);
}
}
```

PICAXE-08M

```' MCP9701_1.Bas (PICAXE-08M)
'
' Continually measures the temperature in degrees C using a Microchip MCP9701, typically costing
' a fraction of a dollar.
'
' Performs 64 measurements and averages the 10-bit A/D Value.
'
' The temperature in degrees C times 100 is 25 * ADVal - 2050.
'
' The temperature is then displayed in decimal format.
'
' Note that the resolution is 0.04 degrees C.
'
' If the temperature is less than 28.00 degrees C, a relay on Out1 is operated.  If
' greater than 35.0, the relay is released.
'
' This was tested on a PICAXE-08M and the program used 70 bytes (of 256), leading me to believe this
' concept could be expanded to four sensers with four realys using a PICAXE-18M or 20M for only a
' few dollars.
'
' For future improvement.  Negative temperatures.  Degrees F.
'
'  MCP9701			PICAXE-08M
'
'   Out (2) ------------ ADC4 (term 3)
'
' copyright, Peter H Anderson, Baltimore, MD, July, '09

Symbol Sum = W1
Symbol Tc_100 = W1

Symbol N  = B4

Symbol Whole = B5
Symbol Fract = B6

Main:

Sum = 0

For N = 1 to 64			' sum 64 readings
Next

ADVal = Sum / 64			' calculate the average

Tc_100 = Tc_100 - 2050

Whole = Tc_100 / 100		' Tc whole
Fract = Tc_100 % 100		' Tc tenths of a degree

SerTxD (#Whole, ".", #Fract, 13, 10)

If Tc_100 < 2800 Then OperateRelay

If Tc_100 > 3500 Then ReleaseRelay

Main_1:
Pause 1000
GoTo Main

OperateRelay:
High 1
GoTo Main_1

ReleaseRelay:
Low 1
GoTo Main_1

```