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)     ;
}