/* Thermostat Node Edward Cheung, Ph.D. Compiled with CCS's PCM C Compiler version 2.547 Tested with TechTools' IDE and PIC Emulator. Modification History - 6//1/99 Created. - 6/25/99 Flash led briefly if good network traffic - 6/26/99 Default after n seconds to SET_TEMP mode - Save working vars to nv memory (for power failure robustness) - 7/16/99 Compiled under Borland C++ with appropriate 16c77 header - Add hysteresis to thermostatic code - cumulative time stats - 7/17/99 Command decoder - 7/25/99 DS1820 support. ds1_ functions - 8/ 1/99 poll DS1820s in background - time delay to filter noise and reduce false starts and stops (using fewer calls to thermals()) - poll all DS1820's in system - fix clicking relays on init - save important vars to non volatile memory (for power fail robustness) - 8/29/99 Fixed bug with reset stats (caused PC timeout) Added filtering to 1wire temp measurements (max change of 1 degree per sample) To do - LED backlight control (see EX_PWM.C) Non volatile (RTC-65271) Address Map 0x0 - 0xD : real-time clock 0x0E : cool set point (start of working vars block) 0x0F : heat set point 0x10 : hvac mode 0x20 : cool set point (start of state store block) 0x21 : heat set point 0x22 : hvac mode 0xxx : (end of state store block) */ #define THERMAL_INTERVAL 10 // seconds between runs of thermal control function #define DS1_MAX 4 // number of 1 wire temp sensors #define CLOCK_HI 0 // if true, use 20mhz #define MIN_DELTA 5 // minimum delta between heat and cool set point via front panel control #include <16c77.h> #ifndef __BORLANDC__ #if CLOCK_HI //#use delay(clock=19660800) #use delay(clock=20000000) #else #use delay(clock=14318180) #endif #use rs232(baud=9600, bits=8, parity = N, xmit=PIN_C6, rcv=PIN_C7, enable=PIN_C5, brgh1ok,ERRORS) #define PAGE_1 #ASM BSF 03,5 #ENDASM #define PAGE_0 #ASM BCF 03,5 #ENDASM #BYTE PORTB = 6 // for switch input #BYTE PORTE = 9 // led test // portd is data bus. Note hardcoded set_tris_d statements below. // Unavoidable with byte wide I/O and PCM compiler. #BYTE RTC_DATA = 8 // see comment immediately above. #use FAST_IO(A) #use FAST_IO(B) #use FAST_IO(C) #use FAST_IO(D) #use FAST_IO(E) #endif #define WR_PIN PIN_B4 // RTC control lines #define RD_PIN PIN_B3 #define AD_PIN PIN_C0 #define NODE_ADDRESS 'T' // Dallas chip #define DS_READ 0x27 // tris data to read from DS1620 #define DS_WRITE 0x07 // tris data to write to DS1620 #define RST_PIN PIN_B7 #define CLK_PIN PIN_B6 #define DQ_PIN PIN_B5 #define DS_1WIRE PIN_A5 // commands to dallas chips #define DS_TEMP 0xAA #define DS_WRTH 0x01,9 #define DS_WRTL 0x02,9 #define DS_RDTH 0xA1 #define DS_RDTL 0xA2 #define DS_START 0xEE,0,0 #define DS_STOP 0x22,0,0 #define DS_WRCFG 0x0C,8 #define DS_RDCFG 0xAC #define DS_SRCRM 0xF0 // search ROM function #define DS_RDRM 0x33 // read ROM function #define DS_MTRM 0x55 // match ROM command // LCD display #define RS_PIN PIN_C4 // high:data, low:instruction #define RW_PIN PIN_C1 // high:read, low:write #define EN_PIN PIN_C3 // falling edge:latch data // LED #define RED 0 #define GREEN 1 #define BLUE 2 #define RED_PIN PIN_E0 #define GRN_PIN PIN_E1 #define BLU_PIN PIN_E2 // relays #define HEAT 0 #define COOL 1 #define FAN 2 #define OFF 3 #define AUTM 4 #define HEAT_PIN PIN_A1 #define COOL_PIN PIN_A2 #define FAN_PIN PIN_A0 // buttons #define TOP 0x1 #define MID 0x2 #define BOT 0x4 // prototypes void lcd_put(byte data,short rs); byte lcd_get(short rs); void lcd_init(void); short ds1_rst(void); void ds1_put(byte data); short ds1_bitin(void); byte ds1_get(void); void ds1_read(int id[8]); void ds_put(byte protocol,byte length,long data); void led_put(int select,short state); void rly_put(int select,short state); int rtc_get(long address,short rtc); void rtc_put(long address,int data,short rtc); void paint(void); void lcd_cursor(short visible); // global vars short click_go; // new switch state short timer_go; // timer for periodic actions short network; // if network alive then true short new_cmd; // true if new command/message from master byte mode; // current display mode #define SET_TEMP 0 // adjust temp set point #define SET_MODE 1 // change heating cooling mode #define SET_STAT 2 // status display byte prev_sw; // previous switch status byte heat_setpt; // heating set point byte cool_setpt; // cooling set point byte hvac_mode; // heating cooling mode, one of HEAT, COOL, FAN, OFF, AUTO byte stat_mode; // which status/internal parameter to show/modify, one of following: #define HOURS 0 // set hour and show time #define MINUT 1 // set minute #define MUNTH 2 #define DAYS 3 #define YEARS 4 #define HYSTER 5 // heating cooling hysteresis #define SAVER 6 // save all to nv memory #define RETRIVE 7 // retrieve from nv memory #define WIREID 8 // get 8 byte id of one 1-wire device attached #define COOL_T 9 // run time cooling #define HEAT_T 10 // run time heating (MUST be last stat_mode) byte hysteresis; // thermostat hysteresis byte gui_timer; // if 1, go to default state long cool_time; // amount of minutes cooling long heat_time; // amount of minutes heating long temp; // current inside temp byte cmd; // command byte from master byte arg; // argument byte from master byte thermal_cnt; // keeps track of when to run thermal controls signed int ds1_temps[DS1_MAX]; // arrays with temps from 1 wire sensors void init(void) { int x; output_low(HEAT_PIN); output_low(COOL_PIN); output_low(FAN_PIN); set_tris_a(0xF8); // relay control set_tris_b(DS_WRITE); // pushbuttons, rtc ctl, DS1620 set_tris_c(0x80); // other controls and serial port set_tris_d(0xff); // data bus set_tris_e(0x00); // leds output_low(PIN_C5); // serial port listen // RTC output_low(AD_PIN); output_high(WR_PIN); output_high(RD_PIN); rtc_put(0xA,0x20,TRUE); // start clock rtc_put(0xB,0x7,TRUE); // resume updates // DS1620 output_low(RST_PIN); output_high(CLK_PIN); ds_put(DS_START); PAGE_1 // page 1 output_high(DS_1WIRE); // configure as input to release 1-wire I/F PAGE_0 // page 0 // LCD output_low(EN_PIN); output_low(RS_PIN); output_low(RW_PIN); lcd_init(); // led and relays led_put(RED,FALSE); led_put(GREEN,FALSE); led_put(BLUE,FALSE); rly_put(HEAT,FALSE); rly_put(COOL,FALSE); rly_put(FAN,FALSE); // serial ISR enable_interrupts(global); enable_interrupts(int_rda); restart_wdt(); click_go = FALSE; new_cmd = FALSE; mode = SET_TEMP; prev_sw = 0; stat_mode = HOURS; network = 0; hysteresis = 2; gui_timer = 0; cool_time = 0; temp = 0; thermal_cnt = 0; heat_time = 0; setup_counters( RTCC_INTERNAL, RTCC_DIV_256); enable_interrupts(RTCC_ZERO); restart_wdt(); for (x=0;x=DS1_MAX) ds1_state = 0; // sample next unit ds1_trigger(ds1_state); // sample next temperature } void ds_put(byte protocol,byte length,long data) { int bit; output_high(RST_PIN); // issue protocol byte LSB first for (bit=0;bit<8;bit++) { output_low(CLK_PIN); if (protocol&0x01 == 0x01) output_high(DQ_PIN); else output_low(DQ_PIN); rotate_right(&protocol,1); output_high(CLK_PIN); } // write data bits for (bit=0;bit>9),rtc); // set data rtc_put_lo((address&0x1f),data,rtc); } } int rtc_get(long address,short rtc) { int data; if (rtc) { // set address register rtc_put_lo(0x00,(int)address,rtc); // indirect address register // get data register data = rtc_get_lo(0x01,rtc); // rtc data register } else { // set bank register rtc_put_lo(0x20,(address>>9),rtc); // get data data = rtc_get_lo((address&0x1f),rtc); } return data; } int rtc_test(void) { int data,x,errors; errors = 0; // low level write of xtended RAM, not battery backed for (x=0;x<10;x++) { rtc_put_lo(x,x,FALSE); rtc_put_lo(12,0xaa,FALSE); data = rtc_get_lo(x,FALSE); if (data != x) { errors++; } } // high level write of test data into RTC bank rtc_put_lo(0x00,0x00,TRUE); // indirect address register rtc_put_lo(0x01,0x00,TRUE); // rtc data register rtc_put_lo(0x00,0x01,TRUE); rtc_put_lo(0x01,0x01,TRUE); rtc_put_lo(0x00,0x02,TRUE); rtc_put_lo(0x01,0x02,TRUE); // get data from RTC bank rtc_put_lo(0x00,0x00,TRUE); data = rtc_get_lo(0x01,TRUE); if (data != 0x00) errors++; rtc_put_lo(0x00,0x01,TRUE); data = rtc_get_lo(0x01,TRUE); if (data != 0x01) errors++; rtc_put_lo(0x00,0x02,TRUE); data = rtc_get_lo(0x01,TRUE); if (data != 0x02) errors++; // high level test of XRAM bank for (x=0;x<200;x++) { rtc_put(x,x,FALSE); data = rtc_get(x,FALSE); if (data != x) errors++; } // high level test of RTC bank for (x=0;x<0x40;x++) { rtc_put(x,x,TRUE); data = rtc_get(x,TRUE); if ((data != x)&&(x!=0xC)&&(x!=0xd)) errors++; } return errors; } void rtc_save(void) { // save state into nonvolatile RAM rtc_put(0x20,cool_setpt,TRUE); rtc_put(0x21,heat_setpt,TRUE); rtc_put(0x22,hvac_mode,TRUE); } void rtc_retrieve(void) { // retrieve state from nonvolatile RAM cool_setpt = rtc_get(0x20,TRUE); heat_setpt = rtc_get(0x21,TRUE); hvac_mode = rtc_get(0x22,TRUE); } void led_put(int select,short state) { if (select==RED) output_bit(RED_PIN,state); else if (select==GREEN) output_bit(GRN_PIN,state); else if (select==BLUE) output_bit(BLU_PIN,state); } short rly_get(int select) { if (select==HEAT) return input(HEAT_PIN); else if (select==COOL) return input(COOL_PIN); else return input(FAN_PIN); } void rly_put(int select,short state) { if (select==HEAT) output_bit(HEAT_PIN,state); else if (select==COOL) output_bit(COOL_PIN,state); else if (select==FAN) output_bit(FAN_PIN,state); } byte sw_get(void) { int data; port_b_pullups(TRUE); delay_us(1); data = PORTB&0x7; port_b_pullups(FALSE); return data^0x7; } #if CLOCK_HI #define INTS_PER_FIRE 76 #else #define INTS_PER_FIRE 54 // 76.3 for one second interval at 20Mhz #endif #ifndef __BORLANDC__ #int_rtcc #endif void clock_timer(){ static int test=INTS_PER_FIRE; // network traffic indicator if (test==10 && network) { network = FALSE; // flash LED to indicate network present if (PORTE==0) // no LEDs on, turn on white PORTE = 0x7; else // LED off briefly PORTE = 0x0; } // periodic interrupt if (test<=0) { // wrap around var to test if period elapsed test=INTS_PER_FIRE; timer_go = TRUE; } test--; // sample switches if (prev_sw!=sw_get()) { // change of switch state prev_sw = sw_get(); click_go = TRUE; } } #ifndef __BORLANDC__ #int_rda #endif void serial_isr() { byte byte_in; static byte com_state=0; // process new received character byte_in=getc(); network = TRUE; // mark network alive switch (com_state) { case 0: if (byte_in==NODE_ADDRESS) // message for thermostat node com_state++; break; case 1: // check if from computer if (byte_in=='C') com_state++; else com_state=0; break; case 2: // check delimiter if (byte_in=='_') com_state++; else com_state=0; break; case 3: cmd = byte_in; com_state++; break; case 4: arg = byte_in; com_state++; break; case 5: // absorb com_state = 0; new_cmd = TRUE; break; default: com_state=0; } } // temperature regulation functions void thermals(long temp,int second) { if (mode == SET_TEMP) { // regulate temp if not setting any parameters if (temp>=(cool_setpt+(hysteresis+1)/2) && (hvac_mode==COOL||hvac_mode==AUTM)) { // cool rly_put(COOL,TRUE); led_put(BLUE,TRUE); } else if (temp<=(cool_setpt-hysteresis/2) && (hvac_mode==COOL||hvac_mode==AUTM)) { // not cooling rly_put(COOL,FALSE); led_put(BLUE,FALSE); } else { // deadband zone, keep previous status if (rly_get(COOL)) led_put(BLUE,TRUE); else led_put(BLUE,FALSE); } if (temp<=(heat_setpt-(hysteresis+1)/2) && (hvac_mode==HEAT||hvac_mode==AUTM)) { // heat rly_put(HEAT,TRUE); led_put(RED,TRUE); } else if (temp>=(heat_setpt+hysteresis/2) && (hvac_mode==HEAT||hvac_mode==AUTM)) { // not heating rly_put(HEAT,FALSE); led_put(RED,FALSE); } else { // deadband zone, keep previous status if (rly_get(HEAT)) led_put(RED,TRUE); else led_put(RED,FALSE); } if (hvac_mode==FAN) { // fan only rly_put(COOL,FALSE); rly_put(HEAT,FALSE); rly_put(FAN,TRUE); led_put(GREEN,TRUE); } else { // no fan rly_put(FAN,FALSE); led_put(GREEN,FALSE); } } } void send_byte(int data){ putchar('C'); putchar(NODE_ADDRESS); putchar('_'); restart_wdt(); putchar(data); putchar(13); set_tris_c(0x80); // other controls and serial port } void send_long(long data){ putchar('C'); putchar(NODE_ADDRESS); putchar('_'); restart_wdt(); putchar((byte)(data>>12)+'0'); putchar((byte)(data>>8)+'0'); putchar((byte)(data>>4)+'0'); restart_wdt(); putchar((byte)(data)+'0'); putchar(13); set_tris_c(0x80); // other controls and serial port } void show_id(void) { int id[8],x; ds1_read(id); lcd_pos(1,4); if (id[6]==0) // show compressed id, substitute 'z' for id[6] printf(lcd_print,"%2X%2X%2X%2X%2X%2Xz%2X",id[0],id[1],id[2],id[3],id[4],id[5],id[7]); else // show id without family id printf(lcd_print,"?%2X%2X%2X%2X%2X%2X%2X",id[1],id[2],id[3],id[4],id[5],id[6],id[7]); } void main(void) { int month,day,year,hour,minute,second,x; float fahr; // extra long delay for power up for (x=0;x<75;x++) { // extra delay restart_wdt(); delay_ms(5); } // do all inits init(); /* //x = lcd_get(TRUE); //lcd_put(0x01,FALSE); //rtc_test(); // rtc_put(0xB,0x81,TRUE); // suspend updates rtc_put(0xB,0x83,TRUE); // suspend updates rtc_put(0x08,6,TRUE); // month rtc_put(0x07,18,TRUE); // day rtc_put(0x09,99,TRUE); // year rtc_put(0x04,22,TRUE); // hour rtc_put(0x02,00,TRUE); // minute rtc_put(0x00,9,TRUE); // second rtc_put(0xA,0x20,TRUE); // start clock rtc_put(0xB,0x7,TRUE); // resume updates // Hardware limits in DS1620. For test make one count higher than ambient, then heat with finger // set low temp emergency level. ds_put(DS_WRTH,0x10); // 0x10 = 50F delay_ms(100); // writes to EEPROM can take 10msec // set high temp emergency level ds_put(DS_WRTL,0x40); // 0x40 = 90F x = sw_get(); */ // main executive loop while (1) { // stroke watchdog restart_wdt(); // new command if (new_cmd) { new_cmd = FALSE; switch (cmd) { case 'A': // get 1 wire temp, 0=outside send_byte(ds1_temps[arg-'0']+'0'); break; case 'T': // get temp send_byte(temp+'0'); break; case 'S': // heating cooling status if (rly_get(COOL)) send_byte('0'+COOL); else if (rly_get(HEAT)) send_byte('0'+HEAT); else if (rly_get(FAN)) send_byte('0'+FAN); else send_byte('0'+OFF); break; case 'H': // set heat set point heat_setpt = arg-'0'; send_byte(temp+'0'); thermal_cnt = 10; paint(); break; case 'I': // get heat set point send_byte(heat_setpt+'0'); break; case 'C': // set cool set point cool_setpt = arg-'0'; send_byte(temp+'0'); thermal_cnt = 10; paint(); break; case 'D': // get cool set point send_byte(cool_setpt+'0'); break; case 'U': // cume cool time send_long(cool_time); break; case 'V': // cume heat time send_long(heat_time); break; case 'R': // restore from nv memory rtc_retrieve(); send_byte(temp+'0'); break; case 'Z': cool_time = 0; heat_time = 0; send_byte(temp+'0'); break; case 'M': // set mode hvac_mode = arg-'0'; if (hvac_mode>AUTM) hvac_mode = OFF; rtc_put(0x10,hvac_mode,TRUE); send_byte(temp+'0'); paint(); break; case 'N': // get mode send_byte(hvac_mode+'0'); break; default: break; } } // periodic actions if (timer_go) { #ifndef __BORLANDC__ timer_go = FALSE; #endif if (gui_timer == 1) { gui_timer = 0; if (mode != SET_TEMP) { mode = SET_TEMP; paint(); } } else if (gui_timer>0) gui_timer--; // get time month = rtc_get(0x08,TRUE); day = rtc_get(0x07,TRUE); year = rtc_get(0x09,TRUE); hour = rtc_get(0x04,TRUE); minute = rtc_get(0x02,TRUE); second = rtc_get(0x00,TRUE); // get temperature temp = ds_get(DS_TEMP); fahr = 30.0 + (9.0*(float)temp)/10.0; // note built in offset due to bias temp = fahr + 0.5; // temperature in integer Fahrenheit // get temperature and filter ds1_run(); /* // check for new day if (hour==23 && minute==59) { // zero cume heating and cooling times heat_time = 0; cool_time = 0; } */ // keep track of run minutes if (second==0) { if (rly_get(COOL)) cool_time++; if (rly_get(HEAT)) heat_time++; } // regulate temperature if not setting parameters if (thermal_cnt <= 0) { thermals(temp,second); thermal_cnt = THERMAL_INTERVAL; } else { thermal_cnt--; // restore LEDs led_put(BLUE,rly_get(COOL)); led_put(RED,rly_get(HEAT)); if (hvac_mode == FAN) led_put(GREEN,TRUE); else led_put(GREEN,FALSE); } // display temps lcd_pos(14,2); printf(lcd_print,"%2ldF",temp); lcd_pos(12,3); printf(lcd_print,"%3dF",ds1_temps[0]); // status/parameter line lcd_pos(1,4); switch (stat_mode) { case HOURS: if (mode==SET_STAT) { printf(lcd_print,"Hour = %02U ",hour); } else { if (second!=0x81) printf(lcd_print,"%02U/%02U %02U:%02U:%02U",month,day,hour,minute,second); } break; case MINUT: if (mode==SET_STAT) { printf(lcd_print,"Minute = %02U ",minute); } else { if (second!=0x81) printf(lcd_print,"%02U/%02U %02U:%02U:%02U",month,day,hour,minute,second); } break; case MUNTH: if (mode==SET_STAT) { printf(lcd_print,"Month = %02U ",month); } else { if (second!=0x81) printf(lcd_print,"%02U/%02U %02U:%02U:%02U",month,day,hour,minute,second); } break; case YEARS: if (mode==SET_STAT) { printf(lcd_print,"Year = %02U ",year); } else { if (second!=0x81) printf(lcd_print,"%02U/%02U %02U:%02U:%02U",month,day,hour,minute,second); } break; case DAYS: if (mode==SET_STAT) { printf(lcd_print,"Day = %02U ",day); } else { if (second!=0x81) printf(lcd_print,"%02U/%02U %02U:%02U:%02U",month,day,hour,minute,second); } break; case HYSTER: printf(lcd_print,"Hyst=%d degrees",hysteresis); break; case SAVER: printf(lcd_print,"Save all data "); break; case RETRIVE: printf(lcd_print,"Retrieve data "); break; case WIREID: printf(lcd_print,""); // ID: break; case HEAT_T: printf(lcd_print,"Heating %2ld:%02ld ",heat_time/60,heat_time%60); break; case COOL_T: printf(lcd_print,"Cooling %2ld:%02ld ",cool_time/60,cool_time%60); break; default: break; } } // check pushbuttons if (click_go) { // new button state click_go = FALSE; gui_timer = 5; if (sw_get() == TOP) { // top switch depressed mode++; if (mode > SET_STAT) mode = SET_TEMP; } if (sw_get()==MID) { // middle switch depressed switch (mode) { case SET_TEMP: if ((hvac_mode==HEAT || hvac_mode==AUTM) && heat_setpt<90) { heat_setpt++; rtc_put(0xF,heat_setpt,TRUE); if (heat_setpt > (cool_setpt-MIN_DELTA)) { cool_setpt = heat_setpt+MIN_DELTA; rtc_put(0xE,cool_setpt,TRUE); } thermal_cnt = 10; } if ((hvac_mode==COOL || hvac_mode==AUTM) && cool_setpt<90) { cool_setpt++; rtc_put(0xE,cool_setpt,TRUE); thermal_cnt = 10; } break; case SET_MODE: hvac_mode++; if (hvac_mode>AUTM) hvac_mode = HEAT; rtc_put(0x10,hvac_mode,TRUE); break; case SET_STAT: stat_mode++; if (stat_mode == WIREID) { lcd_pos(1,4); printf(lcd_print,"Hit MOD for ID "); } if (stat_mode>HEAT_T) stat_mode = HOURS; break; default: break; } } if (sw_get()==BOT) { // botom switch depressed switch (mode) { case SET_TEMP: if ((hvac_mode==HEAT || hvac_mode==AUTM) && heat_setpt>60) { heat_setpt--; rtc_put(0xF,heat_setpt,TRUE); thermal_cnt = 10; } if ((hvac_mode==COOL || hvac_mode==AUTM) && cool_setpt>60) { cool_setpt--; rtc_put(0xE,cool_setpt,TRUE); if (cool_setpt < (heat_setpt+MIN_DELTA)) { heat_setpt = cool_setpt-MIN_DELTA; rtc_put(0xF,heat_setpt,TRUE); } thermal_cnt = 10; } break; case SET_MODE: // reset to default mode; mode = SET_TEMP; break; case SET_STAT: // change parameter chosen switch (stat_mode) { case HOURS: // set hour hour = rtc_get(0x04,TRUE); hour++; if (hour>23) hour = 0; rtc_put(0x04,hour,TRUE); break; case MINUT: // set minute, reset seconds minute = rtc_get(0x02,TRUE); minute++; if (minute>59) minute = 0; rtc_put(0x00,0x00,TRUE); rtc_put(0x02,minute,TRUE); break; case MUNTH: // set month month = rtc_get(0x08,TRUE); month++; if (month>12) month = 1; rtc_put(0x08,month,TRUE); break; case DAYS: // set day day = rtc_get(0x07,TRUE); day++; if (day>31) day = 0; rtc_put(0x07,day,TRUE); break; case YEARS: // set year year = rtc_get(0x09,TRUE); if (year==99) { year=00; } else { year++; if (year>10) year=99; } rtc_put(0x09,year,TRUE); break; case SAVER: rtc_save(); mode = SET_TEMP; stat_mode = HOURS; break; case RETRIVE: rtc_retrieve(); mode = SET_TEMP; stat_mode = HOURS; break; case WIREID: show_id(); break; case HYSTER: // change thermostat hysteresis hysteresis++; if (hysteresis>4) hysteresis = 1; break; case COOL_T: // zero cooling run time cool_time = 0; mode = SET_TEMP; stat_mode = HOURS; break; case HEAT_T: // zero heating run time heat_time = 0; mode = SET_TEMP; stat_mode = HOURS; break; default: break; } break; default: break; } } // redraw lcd screen paint(); } } } void paint(void) { // paint screen // top line lcd_pos(1,1); switch(hvac_mode) { case HEAT: printf(lcd_print,"Heat Set Pt %UF|",heat_setpt); break; case COOL: printf(lcd_print,"Cool Set Pt %UF|",cool_setpt); break; case FAN: printf(lcd_print," - Fan Only - |"); break; case OFF: printf(lcd_print," - Off - |"); break; default: printf(lcd_print,"Auto %UF<->%UF|",heat_setpt,cool_setpt); break; } // second and third lines switch(mode) { case SET_TEMP: lcd_pos(17,1); printf(lcd_print,"TSet"); lcd_pos(1,2); printf(lcd_print,"Inside temp | "); lcd_pos(1,3); printf(lcd_print,"Outside tmp |Up "); lcd_pos(16,4); printf(lcd_print,"|Down"); break; case SET_MODE: printf(lcd_print,"Mode"); lcd_pos(1,2); printf(lcd_print,"Inside temp | "); lcd_pos(1,3); printf(lcd_print,"Outside tmp |Next"); lcd_pos(16,4); printf(lcd_print,"|OK "); break; default: printf(lcd_print,"Stat"); lcd_pos(1,2); printf(lcd_print,"Inside temp | "); lcd_pos(1,3); printf(lcd_print,"Outside tmp |Next"); lcd_pos(16,4); printf(lcd_print,"|Mod "); break; } }