Interfacing with a Dallas DS1821 Thermometer / Thermostat


/* DS1821_1.C  Flashlite V25
**
** Illustrates and interface with the Dallas DS1821 Thermometer /
** Thermostat.
**
** Checks to see if DS1821 is in Thermostat mode.  If so, the DS1821
** is toggled to the communications mode.
**
** If the device is found, the current values of THF, TLF, T/R, POL,
** and _1SHOT bits in the DS1821 status register are displayed.  The
** current values of T_H and T_L are also displayed.
**
** New values of the above are programmed into the DS1821 and this is
** by again reading the settings and displaying them.
**
** The program then goes into a continual loop measuring and displaying
** temperature
**
**
** Flashlite V25               DS1821 (TO-220)
** P2.1  ----------------------- VDD (term 1)
** P2.0  ----------------------- DQ (term 3)
**
**                               GRD (term 2)
**
** Note that a 4.7K pullup resistor to +5V is required on the DQ lead.
**
** copyright, Peter H. Anderson, Baltimore, MD, Sept, '00
*/

#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <ctype.h>

#define SEG 0xf000

#define P2_OFFSET 0xff10
#define PM2_OFFSET 0xff11
#define PMC2_OFFSET 0xff12

#define PRESENT 1

#define FALSE 0
#define TRUE !FALSE

#define _1SHOT 0x01     /* status bits in DS1821 */
#define POL 0x02
#define THERMOSTAT 0x04
#define TLF 0x08
#define THF 0x10


typedef unsigned char byte;

byte find_and_configure_device(void);

signed char _1821_make_meas(void);
byte _1821_get_status(void);
void display_status(byte status_setting);
void _1821_program_status(byte config);

byte _1821_get_T_H(void);
byte _1821_get_T_L(void);

void _1821_program_T_H(byte T_H);
void _1821_program_T_L(byte T_L);

void _1821_toggle_mode(void);

byte  _1821_presence(void);
     /* same as init except returns PRESENT if presence pulse detected */
byte _1w_in_byte(void);
void _1w_out_byte(byte d);
void _1w_pin_hi(void);
void _1w_pin_low(void);

byte far *p2, *pm2, *pmc2;    /* note global */

void main(void)
{

   byte _1821_exists, T_H_setting, T_L_setting, status_setting;
   float T_C;

   p2 = MK_FP(SEG, P2_OFFSET);
   pm2 = MK_FP(SEG, PM2_OFFSET);
   pmc2 = MK_FP(SEG, PMC2_OFFSET);

   *pmc2 = 0x00;

   _1821_exists = find_and_configure_device();
   /* detect if device exists and if so, config in communications mode */
   if (!_1821_exists)
   {
       printf("Device not found.\n");
       exit(0);
   }

   /* implied else */

   printf("Device found!\n");

   printf("Current settings;\n");
   /* THF, TLF, T/R, POL and _1SHOT bits */
   status_setting = _1821_get_status();
   display_status(status_setting);

   T_H_setting = _1821_get_T_H();  /* current value of high trip point */
   printf("TH = %3d  ", (signed char) T_H_setting);

   T_L_setting = _1821_get_T_L();   /* low trip point */
   printf("TL = %3d  ", (signed char) T_L_setting);
   printf("\n");

   sleep(2);      /* pause to admire */

   /*program status register, THF and TLF  */
    _1821_program_status(THERMOSTAT | _1SHOT | POL);
    _1821_program_T_H(5);
    _1821_program_T_L(-3);

   /* now verify this */
   printf("New Settings are;\n");
   status_setting = _1821_get_status();
   display_status(status_setting);

   T_H_setting = _1821_get_T_H();
   printf("TH = %3d  ", (signed char) T_H_setting);

   T_L_setting = _1821_get_T_L();
   printf("TL = %3d  ", (signed char) T_L_setting);
   printf("\n");

   sleep(2);      /* pause to admire */

   printf("Now displaying temperature\n");

   while(1)    /* continual loop */
   {
      /* make measurement and display */
      T_C = (float) _1821_make_meas();
      printf("T_C = %.1f\n", T_C);
      sleep(1);
   }
}


byte find_and_configure_device(void)
/* finds DS1821 and configures in communications mode
** returns TRUE if found
*/
{
   int x;
   *p2 = 0x00;   /* no power */
   *pm2 = 0xfd;
   printf("Insert DS1821 in Circuit and hit any key to continue:");
   getch();
   printf("\n");

   *p2 = 0x02;    /* power the DS1821 */
   delay(1000);  /* wait for device to settle */

   if ((*(p2) & 0x01) == 0) /* probably in thermostat mode */
   {
      _1821_toggle_mode();
      x = _1821_presence();
      if (x == !PRESENT)
      {
          return(FALSE);
      }

      else
      {
         return(TRUE);
      }
   }
   else  /* may already be in communications mode */
   {
       x = _1821_presence();
       if (x == PRESENT)
       {
          return(TRUE);
       }
       else
               /* if not present may be in thermostat mode*/
       {
          _1821_toggle_mode();
          x = _1821_presence();
          if (x == PRESENT)
          {
             return(TRUE);
          }
          else
          {
             return(FALSE);
          }
       }
   }
}

signed char _1821_make_meas(void)
{
/* performs a 1 shot temperature measurement */
   signed val;
   _1821_presence();
   _1w_out_byte(0xee);  /* start a temperature */
   delay(1000);   /* wait for it to complete */

   _1821_presence();
   _1w_out_byte(0xaa);  /* read temperature */
   val = _1w_in_byte();
   return(val);
}

byte _1821_get_T_H(void)
{
/* read value of high trip point */
   byte val;
   _1821_presence();
   _1w_out_byte(0xa1);  /* read T_H */
   val = _1w_in_byte();
   return(val);
}

byte _1821_get_T_L(void)
{
/* read value of low trip point */
   byte val;
   _1821_presence();
   _1w_out_byte(0xa2);  /* read T_L */
   val = _1w_in_byte();
   return(val);
}

void display_status(byte status_setting)
{
   if (status_setting & THF)
   {
      printf("THF = 1  ");
   }
   else
   {
      printf("THF = 0  ");
   }

   if (status_setting & TLF)
   {
      printf("TLF = 1  ");
   }
   else
   {
      printf("TLF = 0  ");
   }

   if (status_setting & THERMOSTAT)
   {
      printf("T/R = 1  ");
   }
   else
   {
      printf("T/R = 0  ");
   }

   if (status_setting & POL)
   {
      printf("POL = 1  ");
   }
   else
   {
      printf("POL = 0  ");
   }

   if (status_setting & _1SHOT)
   {
      printf("1SHOT = 1  ");
   }
   else
   {
      printf("1SHOT = 0  ");
   }

   printf("\n");
}

byte _1821_get_status(void)
{
/* fetch DS1821 status register */
   byte val;
   _1821_presence();
   _1w_out_byte(0xac);  /* read status register */
   val = _1w_in_byte();
   return(val);
}

void _1821_program_T_H(byte T)
{
/* set high trip point */
   _1821_presence();
   _1w_out_byte(0x01);  /* write T_H */
   _1w_out_byte(T);
   delay(50);   /* wait for EEPROM to program */
}

void _1821_program_T_L(byte T)
{
/* set low trip point */
   _1821_presence();
   _1w_out_byte(0x02);  /* write T_L */
   _1w_out_byte(T);
   delay(50);   /* wait for EEPROM to program */
}

void _1821_program_status(byte config)
{
/* set status register */
   _1821_presence();
   _1w_out_byte(0x0c);  /* write status */
   _1w_out_byte(config);
   delay(50);   /* wait for EEPROM to program */
}

void _1821_toggle_mode(void)
/* bring V_DD low and pulse DQ low 16 times */
{
   byte n;

   *p2=0x03;
   *pm2 = 0xfc;
   *p2 = 0x01;     /* bring DQ to a one and V_DD to zero */

   for(n=0; n<16; n++)
   {
      *p2=0x00;
      *p2=0x01;
   }
   *p2 = 0x02;  /* bring V_DD back high */
   *pm2 = 0xfd;
   delay(50);  /* and wait a bit */
}

byte  _1821_presence(void)
{
/* brings DQ low for 500 usecs and then back to high Z.  Returns
** PRESENT if presence pulse dected from DS1821 */
   byte i, j;
   _1w_pin_low();
   for(i=167; i>0; i--)  ;    /* bring low for 500 us */

   _1w_pin_hi();
   for (j=0; j<100; j++)
   {
      if ((*(p2) & 0x01) == 0)  /* if it goes to zero, it is present */
      {
         for(i=167; i>0; i--)  ;
         return(PRESENT);
      }
   }
   return (!PRESENT);   /* DS1821 never went to zero */
}

byte _1w_in_byte()
{
   byte m, n, i_byte=0, temp;
   for (n=0; n<8; n++)
   {
      *p2 = 0x02;  /* zero in least sig bit pos */
      *pm2 = 0xfc;   /* make it an ouput */
      *pm2 = 0xfd;   /* back to high z */

      temp = *p2;

      if (temp & 0x01)
      {
        i_byte=(i_byte>>1) | 0x80;  /* least sig bit first  */
      }
      else
      {
        i_byte=i_byte >> 1;
      }
      for(m=19; m>0; m--)  /* 60 us */  ;
   }
   return(i_byte);
}

void _1w_out_byte(byte d)
{
   byte m, n;

   for(n=0; n<8; n++)
   {
      if (d&0x01)
      {
         *p2 = 0x02;
         *pm2 = 0xfc;
         *pm2 = 0xfd;
         for(m=19; m>0; m--)  /* 60 us */  ;
      }

      else
      {
         *p2 = 0x02;
         *pm2 = 0xfc;
         for(m=19; m>0; m--)  /* 60 us */  ;
         *pm2 = 0xfd;
      }
      d=d>>1;
   }
}

void _1w_pin_hi(void)
{
   *pm2 = 0xfd;
}

void _1w_pin_low(void)
{
   *p2 = 0x02;
   *pm2 = 0xfc;
}