/*

   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 <ad74.h>   ;     // Use 16C74's AD converter routines
#include <math.h>;
#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
   {
    MEMBER day     { 55 ,  65 ,  175 , 185 }
    MEMBER night   {FUZZY { hours IS NOT day }}
    MEMBER morning {50,  60 , 80 , 90 }
    MEMBER evening { 160 ,170 ,190 , 200 }
    MEMBER nightsb {FUZZY { hours IS night AND hours IS NOT evening }}
   }

 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
   {
     MEMBER cold { -40, -40, 40, 60 }
     MEMBER cool { -40, -40, 55, 70 }
     MEMBER warm { 55 , 68 , 78, 82 }
     MEMBER hot  { 68 , 85, 150, 150 }

   }


  LINGUISTIC room  TYPE char  MIN -40  MAX +150
  {  
  MEMBER cold   { -40,   -40,  -8,  -5 }
  MEMBER normal { -3,  0,  3       }
  MEMBER hot    { 0 , 8, 150 , 150 }
  }

 CONSEQUENCE heat TYPE char MIN 0 MAX 255 DEFUZZ cg
 ACTION { Heat_On = (heat >= 128); }
 {
   MEMBER OFF      {   0 }
   MEMBER ON       { 255 }
 }

 CONSEQUENCE ac TYPE char MIN 0 MAX 255 DEFUZZ cg
 ACTION { AC_On = (ac >= 128); }
 {
   MEMBER OFF      {   0 }
   MEMBER ON       { 255 }
 }



 FUZZY room_control
   {
    IF room IS cold THEN
          ac   IS OFF
          heat IS ON

    IF room IS normal THEN
           ac   IS OFF
           heat IS OFF

    IF room IS hot THEN
           ac   IS ON
           heat IS OFF
    IF room IS cold AND hours IS morning THEN
           heat IS OFF
    IF room IS cold AND OutsideTemp IS hot THEN
           heat IS OFF
    IF room IS hot AND OutsideTemp IS cold THEN
           ac IS OFF
   }


// 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();
       }
    }

