An Implementation of Dallas DS1821 Thermostat Programmer
/* DS1821_2.C Flashlite V25, DS1821 Thermostat Programmer
**
** This is an implementation of a system to permit a user to custom
** program a DS1821 thermometer. It was developed for agricultural
** applications including both thermostat and alarm applications.
**
** The low cost of the DS1821 ($2.50 in quantities of 100) makes it
** attractive in applications where other thermostat and alarm
** arrangement are not feasible.
**
**
** The user is prompted to connect the DS1821 to be programmed.
**
** The program 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 user is presented with a menu.
**
**
** The user is prompted to either read the values of T_H, T_L and POL
** currently stored in the DS1821, to set a new value of T_H, T_L or POL,
** to display the new values to be programmed, to display the THF and TLF
** falgs, to perform a continual temperature measurement, to save the new
** parameters to the DS1821 or to quit.
**
** When saving, the THF and TLF flag bits are set to zero and T/R is set
** to 1 such that when the DS1821 again boots, it will boot in the
** thermostat mode.
**
** Note that Quitting without Saving will result in the programmed
** settings not being modified.
**
** Flashlite V25 DS1821 (TO-220)
** P2.1 (term 25) ----------------------- VDD (term 1)
** P2.0 (term 26) ------------------------ DQ (term 3)
** GRD (term 2)
**
** Note that a 4.7K pullup resistor to +5V is required on the DQ lead.
**
** The program also illustrates the use of getch(), toupper(), flashall(),
** and kbhit().
**
** copyright, Peter H. Anderson, Baltimore, MD, Sept, '00
*/
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <ctype.h>
typedef unsigned char byte;
byte find_and_configure_device(void);
byte fetch_and_program_settings(void);
byte _1821_make_meas(void);
byte _1821_get_status(void);
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 if presence pulse */
byte _1w_in_byte(void);
void _1w_out_byte(byte d);
void _1w_pin_hi(void);
void _1w_pin_low(void);
#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
byte far *p2, *pm2, *pmc2; /* note global declaration of pointers */
void main(void)
{
byte _1821_exists, T_H_setting, T_L_setting, POL_setting, op;
p2 = MK_FP(SEG, P2_OFFSET);
pm2 = MK_FP(SEG, PM2_OFFSET);
pmc2 = MK_FP(SEG, PMC2_OFFSET);
*pmc2 = 0x00;
while(1)
{
_1821_exists = find_and_configure_device();
/* detect if device exists and if so, config in comm mode */
if (!_1821_exists)
{
printf("Device not found.\n");
printf("Enter \"X\" to exit. Any other key to continue.");
op = getch();
flushall();
if (toupper(op) == 'X')
{
exit(0);
}
}
else
{
printf("Device found.\n");
fetch_and_program_settings(); /* menu */
printf("Done\n");
printf("Enter \"X\" to exit. Any other key to continue.");
op = getch();
printf("\n");
flushall();
if (toupper(op) == 'X')
{
exit(0);
}
}
}
}
byte fetch_and_program_settings(void)
{
/* menu */
signed char T_H_new, T_L_new, POL_new, x, op;
signed char T_H_current, T_L_current, POL_current, T_C;
/* set proposed settings to the current programmed settings */
POL_new = (_1821_get_status() & 0x02) >> 1;
T_H_new = (unsigned char) _1821_get_T_H();
T_L_new = (unsigned char) _1821_get_T_L();
while(1)
{
printf("Enter \"C\" to display Current programmed settings\n");
printf("Enter \"N\" to display New settings to be programmed\n");
printf("Enter \"H\" to set T_HI_new\n");
printf("Enter \"L\" to set T_LO_new\n");
printf("Enter \"P\" to set POL_new\n");
printf("Enter \"M\" to Measure temperature\n");
printf("Enter \"F\" to View Flags\n");
printf("Enter \"S\" to Save new settings\n");
printf("Enter \"Q\" to Quit and toggle to thermostat mode\n");
flushall(); /* clear out any character that may be in keyboard */
scanf("%c", &op);
op=toupper(op);
switch(op)
{
case 'C': /* Current programmed settings */
POL_current = (_1821_get_status() & 0x02) >> 1;
T_H_current = (unsigned char) _1821_get_T_H();
T_L_current = (unsigned char) _1821_get_T_L();
printf("Current Programmed Settings:\n");
printf(" POL = %d\n", POL_current);
printf(" T_H = %d\n", T_H_current);
printf(" T_L = %d\n", T_L_current);
break;
case 'N': /* Proposed new settings */
printf("New Settings:\n");
printf(" POL_new = %d\n", POL_new);
printf(" T_H_new = %d\n", T_H_new);
printf(" T_L_new = %d\n", T_L_new);
break;
case 'H': /* High trip point */
printf("Enter T_H (-55 to 125): ");
scanf("%d", &T_H_new);
if ((T_H_new < -55) || (T_H_new > 125));
{
printf("Invalid T_H\n");
}
break;
case 'L': /* Low trip point */
printf("Enter T_L (-55 to 125): ");
scanf("%d", &T_L_new);
if ((T_L_new < -55) || (T_L_new > 125));
{
printf("Invalid T_L\n");
}
break;
case 'P': /* Thermostat active state */
printf("Enter POL (0 or 1): ");
scanf("%d", &POL_new);
if ((POL_new < 0) || (POL_new > 1))
{
printf("Invalid value of POL - %d\n", POL_new);
}
break;
case 'M': /* Measure temperature */
printf("Hit any key to halt\n");
while (!kbhit())
{
T_C = _1821_make_meas();
printf("T_C = %d\n", T_C);
}
getch(); /* clear out the keybaord */
break;
case 'F': /* Display THF and TLF flag bits */
x = _1821_get_status();
if (x & THF)
{
printf("THF = 1 ");
}
else
{
printf("THF = 0 ");
}
if (x & TLF)
{
printf("TLF = 1\n");
}
else
{
printf("TLF = 0\n");
}
break;
case 'Q': /* Quit */
_1821_toggle_mode(); /* toggle to thermostat mode */
printf("Quit\n");
return(1);
case 'S': /* Save new settings to DS1821 */
if (T_H_new <= T_L_new)
{
printf("Invalid. T_H is less than T_L\n");
break;
}
else
{
printf("Saving.\n");
x = THERMOSTAT | _1SHOT + (POL_new << 1);
/* THF, TLF are zero */
_1821_program_status(x);
_1821_program_T_H((byte)T_H_new);
_1821_program_T_L((byte)T_L_new);
break;
}
default:
printf("Invalid Command\n");
break;
} /* end of switch */
} /* end of while 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;
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 /* it 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);
}
}
}
}
byte _1821_make_meas(void)
{
/* measure temperature */
byte 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)
{
/* fetch programmed 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)
{
/* fetch programmed value of low trip point */
byte val;
_1821_presence();
_1w_out_byte(0xa2); /* read T_L */
val = _1w_in_byte();
return(val);
}
byte _1821_get_status(void)
{
/* fetch 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)
{
/* Program 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)
{
_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)
{
_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)
{
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;
}