/*************************************************************************** * Temp-Rat : Temperature monitoring device with serial comms, * relay control, and 2*7segmant display * * Code written for an Amtel 89C2051 * * Written: Tim Johnson * * Ver Date Who What * 1 9/06/97 TJ Initial Version * 10/7/97 TJ Invert OverTemp Led **************************************************************************/ #include #include "HT51.h" #include "51types.h" #include "hw.h" #include "globs.h" #include "main.h" #include "access.h" #include "eeprom.h" /* Lookup table contains vaules solving the following equation for Clock Ticks: (for vt = 2.74 to 3.35) T = 0.0022 Vt = temperature sensor voltage Vr = 2.49 volts reference Vcc = 5 Volts R1 = 39k R2 = 220k Vamp = Amplified voltage diff = (R2/R1)(Vt-Vr) time = T * (ln(1- ( Vamp / Vcc ) Clock Ticks = time * (4000000 / 12) */ #define NUM_LOOKUP 63 const WORD lookup[NUM_LOOKUP] = { 243, //1 degree 255, 266, 278, 291, 303, 316, 328, 342, 355, 368, 382, 396, 411, 425, 440, 455, 471, 487, 503, 520, 537, 554, 572, 590, 609, 628, 648, 668, 689, 711, 733, 756, 779, 803, 829, 855, 882, 910, 939, 969, 1001, 1034, 1069, 1105, 1144, 1184, 1227, 1272, 1321, 1373, 1429, 1489, 1555, 1627, 1708, 1798, 1901, 2021, 2164, 2342, 2578, //62 degrees 0xffff }; /*************************************************************************** * search_lookup_up : Function to search the lookup table... * **************************************************************************/ BYTE search_lookup(WORD value) { BYTE i; i = 0; //find number closest to value in lookup table while (lookup[i] < value) { i++; } return (i); } /*************************************************************************** * read_temperature : Function to read the temperature from the temperature sensor * **************************************************************************/ BYTE read_temperature(void) { BYTE timer_old_hi; BYTE timer_old_lo; WORD timer; CHARGE = 0; //wait for cap to discharge completely delay_ms(250); // save the old timer count and reset timer to start TR0 = 0; timer_old_hi = TH0; timer_old_lo = TL0; TH0 = 0; TL0 = 0; TR0 = 1; // start timer again CHARGE = 1; // begin charging comparison capacitor while(!COMPARE) { } TR0 = 0; // stop timer as soon as cap value is equivalent timer = TL0 + (TH0 << 8); //Set timer back to what it was: we loose time, but who cares? TH0 = timer_old_hi; TL0 = timer_old_lo; TR0 = 1; CHARGE = 0; return (search_lookup(timer)); } /*************************************************************************** * main : main function... * **************************************************************************/ void main() { BYTE temp; BYTE curr_temp; BYTE minute_max; //max temperature over a minute //INITIALISE //setup default state of outputs nPOWER = 1; // ensure power is off nOVERTEMP = 1; CHARGE = 0; // discharge Cap ANIN0 = 1; // analogue input to cap ANIN1 = 1; // analogue input to temp sensor EEPROM_EN = 0; // CS of eeprom chip SELECT1 = 0; // BCD digit 1 SELECT2 = 0; // BCD digit 2 //set up timer and serial port // t0 as 16 bit timer : mode 1 : for general timing // t1 as 8 bit timer : mode 2 : auto reload serial TMOD = T1M1_H | T0M0_H; ROM_VECTOR(T0_INT, Timer_ISR); // setup timer 1 for baud rate determination PCON = SMOD_H; //set SMOD bit in PCON register : baud rate doubler TH1 = B1200; // reload value for timer 1 //load an initial delay timer TH0 = H_MILLISEC >> 8; TL0 = H_MILLISEC & 0xFF; // setup serial port for mode 1 operation //Enable serial port interupts ROM_VECTOR(SCON_INT, Serial_ISR); SCON = SM1_H | SM2_H | REN_H; //Set up TCON register:turn timers on, ex0 is edge triggered TCON = TR1_H | TR0_H | IT0_H; //setup Override switch interrupt ROM_VECTOR(EX0_INT, Override_ISR); //Set up interrupt priorities IP = PT0_H; //timer 0 at high priority //turn interrupts on //IE register IE = EA_H | ES_H | ET0_H | EX0_H; // default options mode = NORMAL; //reset the eeprom memory if D2 = 1; D3 = 0; if (!D2) { load_defaults(); show_num(0); while (1) // stay in this state { }; } rx_buf = 0; //ensure serial buffer is empty //setup initial counters and flags flash_cd = FLASH_PERIOD; sec_count = SEC_VAL; min_count = MIN_VAL; sample_count = SAMPLE_TIME; minute_flag = TRUE; sample_flag = TRUE; //startup message show_num(VERSION); send_string(MSG_TITLE); send_byte(CR); delay_ms(250); delay_ms(250); //read in all variables from the Eeprom off_time = access(SEL_OFF_TIME, ACT_GET, NOVAL); show_num(off_time); delay_ms(250); delay_ms(250); on_time = access(SEL_ON_TIME, ACT_GET, NOVAL); show_num(on_time); delay_ms(250); delay_ms(250); max_temp = access(SEL_MAX_TEMP, ACT_GET, NOVAL); show_num(max_temp); delay_ms(250); delay_ms(250); power_off_cd = 0; power_on_cd = 0; minute_max = 0; //the main forever loop... for (;;) { switch (mode) { // command mode: read/set params case COMMAND: { switch (rx_buf) { case 'i': // show all options //show Off Time rx_buf = 0; timeout_cd = MODE_TIMEOUT; send_string(MSG_OFF_TIME); send_byte(':'); send_num(off_time); send_byte(CR); // show power on time send_string(MSG_ON_TIME); send_byte(':'); send_num(on_time); send_byte(CR); // show the max operating temperature send_string(MSG_TEMP); send_byte(':'); send_num(max_temp); send_byte(CR); if (!nOVERRIDE) { send_string(MSG_OVERRIDE); send_byte(CR); } send_byte(CR); break; case 'p': // set power off time rx_buf = 0; timeout_cd = MODE_TIMEOUT; mode = SET_OFF_TIME; break; case 'b': // set power on time rx_buf = 0; timeout_cd = MODE_TIMEOUT; mode = SET_ON_TIME; break; case 'q': // quit configuration rx_buf = 0; send_string(MSG_OK); send_byte(CR); timeout_cd = 0; mode = NORMAL; // ensure the temperature is measured imeadiatly minute_flag = TRUE; sample_flag = TRUE; break; case 't': // set the over-temperature rx_buf = 0; timeout_cd = MODE_TIMEOUT; mode = SET_TEMP; break; case 'm': // display the title first time rx_buf = 0; timeout_cd = MODE_TIMEOUT; power_on_cd = 0; //reset power on/off countdowns power_off_cd = off_time; send_string(MSG_TITLE); send_byte(CR); break; default: break; } break; } // critical temperature setting case SET_TEMP: { send_string(MSG_TEMP); //send prompt send_byte('?'); temp = get_num(); //get the number send_byte(CR); send_num(temp); send_byte(':'); send_string(MSG_SURE); mode = COMMAND; if (get_key() == 'y') { access(SEL_MAX_TEMP, ACT_SET, temp); max_temp = temp; send_byte(CR); send_string(MSG_OK); } send_byte(CR); break; } // power off delay setting case SET_OFF_TIME: { send_string(MSG_OFF_TIME); send_byte('?'); temp = get_num(); //get the number send_byte(CR); send_num(temp); send_byte(':'); send_string(MSG_SURE); mode = COMMAND; if (get_key() == 'y') { access(SEL_OFF_TIME, ACT_SET, temp); off_time = temp; send_byte(CR); send_string(MSG_OK); } send_byte(CR); break; } // power ON delay setting case SET_ON_TIME: { send_string(MSG_ON_TIME); send_byte('?'); temp = get_num(); //get the number send_byte(CR); send_num(temp); send_byte(':'); send_string(MSG_SURE); mode = COMMAND; if (get_key() == 'y') { access(SEL_ON_TIME, ACT_SET, temp); on_time = temp; send_byte(CR); send_string(MSG_OK); } send_byte(CR); break; } // normal operation case NORMAL: { // check if comms is active and user wants to go into menu mode if (rx_buf == 'm') { mode = COMMAND; } // measure the temperature every so often, and display if (sample_flag) { sample_flag = FALSE; curr_temp = read_temperature(); //returns 0->63 curr_temp += read_temperature(); curr_temp += read_temperature(); curr_temp += read_temperature(); curr_temp = curr_temp / 4; show_num(curr_temp); if (curr_temp > minute_max) { minute_max = curr_temp; } } // only send the temperature every minute if (minute_flag) { minute_flag = FALSE; // check temperature is not too big if (minute_max > max_temp) { over_temp_flag = TRUE; } else { over_temp_flag = FALSE; nOVERTEMP = TRUE; } send_byte(MSG_TEMPRAT); send_num(minute_max); send_byte(CR); minute_max = 0; // ignore over temp if in override mode if (nOVERRIDE && over_temp_flag) { //setup power on time delay power_on_cd = on_time; // has power down delay been done? if (power_off_cd == 0) { nPOWER = 1; } else { // send power off countdown to host send_byte(MSG_POWER); send_num(power_off_cd); send_byte(CR); } } else { // switch power back on if (!nOVERRIDE || (power_on_cd == 0)) { power_off_cd = off_time; power_on_cd = 0; nPOWER = 0; } else { send_byte(MSG_ON); send_num(power_on_cd); send_byte(CR); } } } break; } } } } /*************************************************************************** * get_key : gets a key from the serial port * **************************************************************************/ BYTE get_key(void) { BYTE temp; rx_buf = 0; while(rx_buf == 0) { } temp = rx_buf; rx_buf = 0; send_byte(temp); return temp; } /*************************************************************************** * get_num : gets 2 digit number from serial port * **************************************************************************/ BYTE get_num(void) { BYTE in_key; BYTE number; number = 0; // get the 1st digit in_key = get_key(); if (in_key != CR) { number = in_key - '0'; in_key = get_key(); //second digit if (in_key != CR) { in_key = (in_key - '0'); number = (number * 10) + in_key; } } return number; } /************************************************************************** * delay_ms : delays for any number of miliseconds * *************************************************************************/ void delay_ms(BYTE ms) { while (ms != 0) { DELAY1((BYTE)(CPU_CLOCK/24*0.001)); // 1msec ms--; } } /************************************************************************** * show_num : display 2 digit number to 2*7 segment displays via BCD (4511) * *************************************************************************/ void show_num(BYTE num) { BYTE digit; digit = (num / 10); if (digit == 0) // hide the first digit if zero { D0 = 1; D1 = 1; D2 = 1; D3 = 1; } else { D0 = digit & 0x01; D1 = (digit & 0x02) ? 1 : 0; //these lines mean : if (digit & xx) then 1, else 0 D2 = (digit & 0x04) ? 1 : 0; D3 = (digit & 0x08) ? 1 : 0; } SELECT1 = 0; delay_ms(1); SELECT1 = 1; digit = (num % 10); D0 = digit & 0x01; D1 = (digit & 0x02) ? 1 : 0; D2 = (digit & 0x04) ? 1 : 0; D3 = (digit & 0x08) ? 1 : 0; SELECT2 = 0; delay_ms(1); SELECT2 = 1; } /*************************************************************************** * Serial_ISR : Serial interrupt routine * * Purpose : clear serial interrupts. Store incoming byte in a buffer **************************************************************************/ interrupt void Serial_ISR(void) { if (RI) { RI = 0; rx_buf = SBUF; } if (TI) { TI = 0; tx_flag = 0; } } /*************************************************************************** * Override_ISR : Override switch interrupt * * Purpose: cause sampling to occur ASAP. **************************************************************************/ interrupt void Override_ISR(void) { minute_flag = TRUE; sample_flag = TRUE; } /*************************************************************************** * Timer_ISR : timer interrupt * * Purpose: counts intervals **************************************************************************/ interrupt void Timer_ISR(void) { //reload timer vals TR0 = 0; TH0 = H_MILLISEC >> 8; TL0 = H_MILLISEC & 0xFF; TR0 = 1; sec_count--; if (sec_count == 0) { sample_count--; if (sample_count == 0) { sample_count = SAMPLE_TIME; sample_flag = TRUE; } sec_count = SEC_VAL; min_count--; if (min_count == 0) { min_count = MIN_VAL; // set flag to mark the minute minute_flag = TRUE; // decrement counters every minute if (power_off_cd > 0) { power_off_cd--; } if (power_on_cd > 0) { power_on_cd--; } //timeout on editing modes if (timeout_cd > 0) { timeout_cd--; } else { mode = NORMAL; //return to normal mode if timeout occured } } } //setup flashing flag flash_cd--; if (flash_cd == 0) { flash_cd = FLASH_PERIOD; flash_flag = !flash_flag; } //flash a warning light if (over_temp_flag) { nOVERTEMP = flash_flag; } } /************************************************************************* * send_byte() : send a single byte down the serial link * *************************************************************************/ void send_byte(BYTE ch) { tx_flag = 1; SBUF = ch; while(tx_flag == 1) {} } /************************************************************************* * send_string() : sends a string down the serial link * ************************************************************************/ void send_string(char *s) { BYTE s_idx; /* copy string to tx buffer, ignore null */ for(s_idx = 0; s[s_idx] != 0; s_idx++) { send_byte(s[s_idx]); } } /************************************************************************* * send_num() : sends a BYTE number down the serial link * *************************************************************************/ void send_num(BYTE num) { BYTE digit; digit = (num / 10); send_byte('0' + digit); digit = (num % 10); send_byte('0' + digit); }