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