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