/* Fuzzy logic example showing the use of linguistic variables (c) 1995, 2001 Byte Craft Limited Waterloo, Canada N2J 4E4 Walter Banks */ #include <16c74.h> ; // Use the Microchip PIC16c74 #include ; // Use 16C74's AD converter routines #include ; #include "fuzzc.h" char __IDOM[2]; #pragma portrw portb @ 6; // external control port. #define C_const 122 #define F_const 220 #define C_offset -11662 /* -45.5C * 256 */ #define F_offset -12800 /* -50F * 256 */ /* define the control bits that drive the relays */ #define Heat_On PORTB.0 #define AC_On PORTB.1 #define Fan_On PORTB.2 #define Humid_On PORTB.3 #define fifty // powerline frequency #ifdef fifty #define rollover 100 #else #define rollover 120 #endif /* This home environment control system bases its control on the following parameters. OutsideTemp InsideTemp Time InsideHumidity TemperatureSP HumiditySp */ char ticks; // 1/60 sec tics roll over at 120 // 1/50 sec tics roll over at 100 char seconds; // actually two seconds 180 = 6 min // hours; .1 hour 0 .. 240 for a day // The crisp value hours resolves the day into // 6 minute intervals which fits nicely into // a sigle byte. // // CRISP variable hours has the the following // Linguistic definitions. // // day starts at 5:30 am is truly day at 6:30 am and // begins to end at 5:30 pm (17:30) and is no // long day at 6:30PM (18:30) . // // night is not day // // morning starts at 5:00am is morning by 6:00am // begins to end at 8:00am over by 9:00am // // evening starts at 4:00PM (1600) goes to 8:00pm // // nightsb Night set back: The time of the night // that is not evening. // /* LINGUISTIC hours TYPE char MIN 0 MAX 240 */ /* { */ char hours ; /* MEMBER day { 55 , 65 , 175 , 185 } */ /* 1-| ............... | . . | . . | . . 0-| ........ ........ ---------------------------------- 0 60 120 180 240 */ char hours_day (char __CRISP) { if (__CRISP < 55) return(0); else { if (__CRISP <= 65) return(((__CRISP - 55) * 25) + 2); else { if (__CRISP <= 175) return(255); else { if (__CRISP <= 185) return((( + 185 - __CRISP) * 25) + 2); else return(0); } } } } /* MEMBER night {FUZZY { hours IS NOT day }} */ char hours_night (char __CRISP) { return(F_NOT(hours_day(hours)) ); } /* MEMBER morning {50, 60 , 80 , 90 } */ /* 1-| .... | . . | . . | . . 0-| ........ ..................... ---------------------------------- 0 60 120 180 240 */ char hours_morning (char __CRISP) { if (__CRISP < 50) return(0); else { if (__CRISP <= 60) return(((__CRISP - 50) * 25) + 2); else { if (__CRISP <= 80) return(255); else { if (__CRISP <= 90) return((( + 90 - __CRISP) * 25) + 2); else return(0); } } } } /* MEMBER evening { 160 ,170 ,190 , 200 } */ /* 1-| ... | . . | . . | . . 0-| ...................... ...... ---------------------------------- 0 60 120 180 240 */ char hours_evening (char __CRISP) { if (__CRISP < 160) return(0); else { if (__CRISP <= 170) return(((__CRISP - 160) * 25) + 2); else { if (__CRISP <= 190) return(255); else { if (__CRISP <= 200) return((( + 200 - __CRISP) * 25) + 2); else return(0); } } } } /* MEMBER nightsb {FUZZY { hours IS night AND hours IS NOT evening }} */ char hours_nightsb (char __CRISP) { __IDOM[1] = hours_night(hours) ; __IDOM[0] = F_NOT(hours_evening(hours)) ; __IDOM[0] = F_AND(__IDOM[1],__IDOM[0]); return(__IDOM[0]); } /* } */ /* Fuzzy Sets for hours 1-| .................. | .. . .. . | . . . . . | .. . . . . 0-| ........ . . . ...... ---------------------------------- 0 60 120 180 240 */ void time (void) /* called each 1/60 or (1/50) of a second */ { if (++ticks >= rollover) { ticks = 0; if (++seconds >= 180) { seconds = 0; if (++hours >= 240) { // new day hours = 0; } } } } /* LINGUISTIC OutsideTemp TYPE char MIN -40 MAX 150 */ /* { */ char OutsideTemp ; /* MEMBER cold { -40, -40, 40, 60 } */ /* 1-| .............. | . . | . . | . . 0-| . ................ ---------------------------------- -40 8 55 103 150 */ char OutsideTemp_cold (char __CRISP) { { if (__CRISP <= 40) return(255); else { if (__CRISP <= 60) return((( + 60 - __CRISP) * 12) + 7); else return(0); } } } /* MEMBER cool { -40, -40, 55, 70 } */ /* 1-| ................. | . . | . . | . . 0-| . .............. ---------------------------------- -40 8 55 103 150 */ char OutsideTemp_cool (char __CRISP) { { if (__CRISP <= 55) return(255); else { if (__CRISP <= 70) return(( + 70 - __CRISP) * 17); else return(0); } } } /* MEMBER warm { 55 , 68 , 78, 82 } */ /* 1-| ... | . . | . . | . . 0-| ................. ............ ---------------------------------- -40 8 55 103 150 */ char OutsideTemp_warm (char __CRISP) { if (__CRISP < 55) return(0); else { if (__CRISP <= 68) return(((__CRISP - 55) * 19) + 4); else { if (__CRISP <= 78) return(255); else { if (__CRISP <= 82) return((( + 82 - __CRISP) * 63) + 1); else return(0); } } } } /* MEMBER hot { 68 , 85, 150, 150 } */ /* 1-| ............ | . . | . . | . . 0-| ................... . ---------------------------------- -40 8 55 103 150 */ char OutsideTemp_hot (char __CRISP) { if (__CRISP < 68) return(0); else { if (__CRISP <= 85) return((__CRISP - 68) * 15); else { return(255); } } } /* } */ /* Fuzzy Sets for OutsideTemp 1-| ................. ............... | . . .. .. . | . . .. .. . | . .. . . . 0-| .................... ............ ---------------------------------- -40 8 55 103 150 */ /* LINGUISTIC room TYPE char MIN -40 MAX +150 */ /* { */ char room ; /* MEMBER cold { -40, -40, -8, -5 } */ /* 1-| ...... | . . | . . | . . 0-| . ........................... ---------------------------------- -40 8 55 103 150 */ char room_cold (char __CRISP) { { if (__CRISP <= -8) return(255); else { if (__CRISP <= -5) return(( - 5 - __CRISP) * 85); else return(0); } } } /* MEMBER normal { -3, 0, 3 } */ /* 1-| . | . | . | .. 0-| ................................. ---------------------------------- -40 8 55 103 150 */ char room_normal (char __CRISP) { if (__CRISP < -3) return(0); else { if (__CRISP <= 0) return((__CRISP + 3) * 85); else { { if (__CRISP <= 3) return(( + 3 - __CRISP) * 85); else return(0); } } } } /* MEMBER hot { 0 , 8, 150 , 150 } */ /* 1-| ......................... | . . | . . | . . 0-| ........ . ---------------------------------- -40 8 55 103 150 */ char room_hot (char __CRISP) { if (__CRISP < 0) return(0); else { if (__CRISP <= 8) return((__CRISP * 31) + 3); else { return(255); } } } /* } */ /* Fuzzy Sets for room 1-| ...... .......................... | . . .. . | . ... . | . .. . 0-| ................................. ---------------------------------- -40 8 55 103 150 */ /* CONSEQUENCE heat TYPE char MIN 0 MAX 255 DEFUZZ cg */ /* ACTION { Heat_On = (heat >= 128); } */ /* { */ char heat ; int fa_heat, fc_heat; /* MEMBER OFF { 0 } */ /* 1-| . | . | . | . 0-| *................................ ---------------------------------- 0 64 128 191 255 */ void heat_OFF (char __DOM) { fc_heat += __DOM; fa_heat += (__DOM * (0)); } /* MEMBER ON { 255 } */ /* 1-| . | . | . | . 0-| ................................* ---------------------------------- 0 64 128 191 255 */ void heat_ON (char __DOM) { fc_heat += __DOM; fa_heat += (__DOM * (255)); } /* } */ void fd_heat (void) { if (fc_heat == 0) heat = 0; else heat = fa_heat / fc_heat; Heat_On = (heat >= 128); } /* CONSEQUENCE ac TYPE char MIN 0 MAX 255 DEFUZZ cg */ /* ACTION { AC_On = (ac >= 128); } */ /* { */ char ac ; int fa_ac, fc_ac; /* MEMBER OFF { 0 } */ /* 1-| . | . | . | . 0-| *................................ ---------------------------------- 0 64 128 191 255 */ void ac_OFF (char __DOM) { fc_ac += __DOM; fa_ac += (__DOM * (0)); } /* MEMBER ON { 255 } */ /* 1-| . | . | . | . 0-| ................................* ---------------------------------- 0 64 128 191 255 */ void ac_ON (char __DOM) { fc_ac += __DOM; fa_ac += (__DOM * (255)); } /* } */ void fd_ac (void) { if (fc_ac == 0) ac = 0; else ac = fa_ac / fc_ac; AC_On = (ac >= 128); } /* FUZZY room_control */ void room_control (void) { fa_ac = 0; fc_ac = 0; fa_heat = 0; fc_heat = 0; /* { */ /* IF room IS cold THEN */ /* ac IS OFF */ /* heat IS ON */ __IDOM[0] = room_cold(room) ; ac_OFF( __IDOM[0] ); heat_ON( __IDOM[0] ); /* IF room IS normal THEN */ /* ac IS OFF */ /* heat IS OFF */ __IDOM[0] = room_normal(room) ; ac_OFF( __IDOM[0] ); heat_OFF( __IDOM[0] ); /* IF room IS hot THEN */ /* ac IS ON */ /* heat IS OFF */ __IDOM[0] = room_hot(room) ; ac_ON( __IDOM[0] ); heat_OFF( __IDOM[0] ); /* IF room IS cold AND hours IS morning THEN */ /* heat IS OFF */ __IDOM[1] = room_cold(room) ; __IDOM[0] = hours_morning(hours) ; __IDOM[0] = F_AND(__IDOM[1],__IDOM[0]); heat_OFF( __IDOM[0] ); /* IF room IS cold AND OutsideTemp IS hot THEN */ /* heat IS OFF */ __IDOM[1] = room_cold(room) ; __IDOM[0] = OutsideTemp_hot(OutsideTemp) ; __IDOM[0] = F_AND(__IDOM[1],__IDOM[0]); heat_OFF( __IDOM[0] ); /* IF room IS hot AND OutsideTemp IS cold THEN */ /* ac IS OFF */ __IDOM[1] = room_hot(room) ; __IDOM[0] = OutsideTemp_cold(OutsideTemp) ; __IDOM[0] = F_AND(__IDOM[1],__IDOM[0]); ac_OFF( __IDOM[0] ); /* } */ fd_ac (); fd_heat (); } // DOMtoCRISP // This function takes a Degree of Membership value and // a full scale CRISP value and returns the CRISP // equivalent char DOMtoCRISP(char DOM, char CRISP) { unsigned long result; result = ( DOM * CRISP ) / (F_ONE - F_ZERO); return result; } // convert the reading from an A/D to // the temerature in degres F char convert_temp (char temp) { return ((((long)temp * F_const) + F_offset) >> 8); } char room_temp,SPtemp,SBtemp; void main (void) { SPtemp = 71; // This is the nominal room set point // It can (should) be set interactively // with a keypad and LCD display SBtemp = 3; // Night setback temperature. Init_A2D(); while(1) { /* room_temp is the current room temperature room is the error in the room temperature from the desired setting. The room set point is the thermostat setting less the night setback if needed. The night setback is a linguistic variable that varies between fuzzy zero and fuzzy one. The transistion between day time temperature and night time temperature is linear and smooth at the end of the evening. */ room_temp = convert_temp(ReadAD(0));; room = DOMtoCRISP(hours_nightsb(hours),SBtemp); room = room_temp - SPtemp - room; /* room_control call a fuzzy function that that evaluates all the control statements and then activates two consequences either airconditioning or furnace. */ room_control(); } }