Measuring Temperature using an NTC Thermistor
/* Program Therm_2.C (Flashlite V25)
**
** Measures temperature using a 10K NTC Thermistor in a voltage divider
** arrangement as illustrated.
**
** (1) V_therm = Vref/4096 * ad_val
** (2) V_therm = r_therm / (r_therm + 10.0K) * V_ref
**
** equating these and solving for r_therm;
**
** (3) r_therm = 10,0K / ((4096/ad_val) - 1)
**
** The temperature is then calculated using a two point model;
**
** (4) T_Kelvin = 1/(a + b*ln(r_therm))
** (5) T_C = T_K - 273.15
**
** Note that the program checks to see if calibration file "therm.dta"
** exists and if so, these values of "a" and "b" are used. Otherwise,
** default values are used.
**
**
** Flashlite TLC2543
**
** P2.3 (SDI) <--------------------------- D_OUT
**
** P2.2 (SDO) ---------------------------> D_IN
** P2.1 (CLK) ---------------------------> CLK
** P2.0 (/CS) ---------------------------> /CS
**
** +5
** |
** 10K Fixed
** |
** |----------------- AIN0
** 10K NTC +
** | V_therm
** GRD -
**
**
** copyright, Peter H. Anderson, Baltimore, MD, Sept, 00
*/
#include <stdio.h>
#include <dos.h>
#include <math.h>
#define SEG 0xf000
#define P2_OFFSET 0xff10
#define PM2_OFFSET 0xff11
#define PMC2_OFFSET 0xff12
typedef unsigned char byte;
#define SDI 3
#define SDO 2
#define CLK 1
#define NOT_CS 0
/* #define D */ /* used for debugging */
float calc_temperature(float ad_val_avg);
float ad_meas_avg(byte far *p, byte channel, byte bipolar, int num_samps);
unsigned int ad_meas(byte far *p, byte channel, byte bipolar);
byte spi_io(byte far *p, byte o_byte);
void put_bit(byte far *p, byte bit_num, byte state);
byte get_bit(byte far *p, byte bit_num);
void delay_short(byte d);
void main(void)
{
byte far *p2, *pm2, *pmc2;
byte dirs, channel;
float ad_val_avg, T_C;
p2 = MK_FP(SEG, P2_OFFSET);
pm2 = MK_FP(SEG, PM2_OFFSET);
pmc2 = MK_FP(SEG, PMC2_OFFSET);
*pmc2 = 0x00; /* not special purpose */
dirs = 0xf8; /* lower three bits are outputs */
*pm2 = dirs;
put_bit(p2, NOT_CS, 1); /* disable to device */
put_bit(p2, CLK, 0); /* clock at zero */
while(1)
{
ad_val_avg = ad_meas_avg(p2, 0, 0, 100);
/* perform 100 unipolar A/D meas on channel 0 and return the average*/
T_C = calc_temperature(ad_val_avg);
printf("%.2f\n", T_C);
delay(500);
}
}
float calc_temperature(float ad_val_avg)
{
float r_therm, a, b, T_K, T_C;
FILE *f;
r_therm = 10.0e3/(4096.0/ad_val_avg - 1.0);
f = fopen("therm.dta", "rt");
if (f!=NULL) /* if there is a calibration file */
{
fscanf("%f %f", &a, &b);
fclose(f);
}
else
{
a=0.000623; b=0.000297; /* else, use a default */
}
T_K = 1.0 / (a = b*log(r_therm));
T_C = T_K - 273.15;
return(T_C);
}
float ad_meas_avg(byte far *p, byte channel, byte bipolar, int num_samps)
{
float sum=0.0;
int n, ad_val;
for(n=0; n<num_samps; n++)
{
ad_val = ad_meas(p, channel, bipolar);
sum+=(float) ad_val;
}
return(sum/num_samps);
}
unsigned int ad_meas(byte far *p, byte channel, byte bipolar)
/* perform measurement on specified channel */
{
byte high_byte, low_byte;
unsigned int ad_val;
put_bit(p, NOT_CS, 0);
delay_short(20);
high_byte = spi_io(p, (channel << 4) | 0x0c + bipolar);
low_byte = spi_io(p, 0x00);
put_bit(p, NOT_CS, 1);
put_bit(p, NOT_CS, 0);
delay_short(20);
high_byte = spi_io(p, (channel << 4) | 0x0c + bipolar);
low_byte = spi_io(p, 0x00);
put_bit(p, NOT_CS, 1);
#ifdef D
printf(".. %2x %2x\n", high_byte, low_byte);
#endif
ad_val = high_byte;
ad_val = (ad_val << 8) | low_byte; /* result is in high 12 bits */
ad_val = ad_val >> 4; /* now in low 12 bits */
return(ad_val);
}
byte spi_io(byte far *p, byte o_byte)
{
byte i_byte, n;
for(n=0; n<8; n++)
{
if (o_byte & 0x80) /* most sign bit first */
{
put_bit(p, SDO, 1);
}
else
{
put_bit(p, SDO, 0);
}
put_bit(p, CLK, 1); /* data sent on rising edge */
i_byte = (i_byte << 1) | get_bit(p, SDI) ;
/* read in the middle of the clock pulse */
put_bit(p, CLK, 0);
o_byte = o_byte << 1;
}
return(i_byte);
}
void put_bit(byte far *p, byte bit_num, byte state)
{
byte mask_0, mask_1;
mask_1 = 0x01 << bit_num;
mask_0 = ~mask_1;
if (state == 0)
{
*p = *p & mask_0;
}
else
{
*p = *p | mask_1;
}
}
byte get_bit(byte far *p, byte bit_num)
{
byte mask_1;
mask_1 = 0x01 << bit_num;
if (*p & mask_1)
{
return(1);
}
else
{
return(0);
}
}
void delay_short(byte d)
{
while(--d) ;
}