//----------------------------------------------------//
//    Digitaler Thermostat mit 2 Kelvin Hysterese     //
//                                                    //
//    Autor: Bernhard Hanf                            //
//    Version: 1.0                                    //
//    Datum: 31.07.2003                               //
//                                                    //
//----------------------------------------------------//
//    LED Anode 1   (B0)                              //
//    LED Anode 2   (B1)                              //
//    LED Anode 3   (B2)                              //
//    Schaltausgang (B3)                              //
//    Poti          (A0)                              //
//    1-Wire Data   (A4)                              //
//    LED seg a     (C0)                              //
//    LED seg b     (C1)                              //
//    LED seg c     (C2)                              //
//    LED seg d     (C3)                              //
//    LED seg e     (C4)                              //
//    LED seg f     (C5)                              //
//    LED seg g     (C6)                              //
//    LED seg dp    (C7)                              //
//----------------------------------------------------//


#include <16F872.h>
#use     delay(clock = 4000000)
#fuses   XT, NOWDT, NOLVP


#define  stelle1   PIN_B0
#define  stelle2   PIN_B1
#define  stelle3   PIN_B2
#define  schalter  PIN_B3
#define  owdata    PIN_A4


// 7-Segmentanzeige           gfedcba
byte CONST LED_MAP[10] = { 0b11000000,    // 0
                           0b11111001,    // 1
                           0b10100100,    // 2
                           0b10110000,    // 3
                           0b10011001,    // 4
                           0b10010010,    // 5
                           0b10000011,    // 6
                           0b11111000,    // 7
                           0b10000000,    // 8
                           0b10010000,};  // 9

byte  st1 = 0;
byte  st2 = 0;
byte  st3 = 0;

int8  toggle = 0;
int8  adzae = 0;
int8  temp_ist;
int8  soll_neu;
int8  soll_alt;
int16 potizae = 0;
char  flags = 0;
#bit  messen = flags.1
#bit  potiflag = flags.2

// Prototypen ----------------------------------------------------------------
int   OWTouchReset(void);             // 1-Wire Reset
void  OWWriteBit(int);                // 1-Wire Write Bit
int   OWReadBit(void);                // 1-Wire Read Bit
void  OWWriteByte(int);               // 1-Wire Write Byte
int   OWReadByte(void);               // 1-Wire Read Byte
int   OWTouchByte(int);
int   ReadTemp(void);                 // 1-Wire Read Temperatur


//------------------------------------------------------------------------------
#int_TIMER0
void TIMER0_isr(void)                 // alle 5ms Überlauf
{  set_timer0(100);                   // Timer neu stellen
   if(toggle == 1)                    // 1. Stelle ausgeben
   {  output_high(stelle2);           // 2. Stelle ausschalten
      output_high(stelle3);           // 3. Stelle ausschalten
      output_c(LED_MAP[st1]);         // 7-Segmentwert ausgeben
      output_low(stelle1);            // 1. Stelle einschalten
      toggle = 2;                     // beim nächsten ISR 2.Stelle
   }
   else if(toggle == 2)               // 2. Stelle ausgeben
   {  output_high(stelle1);           // 1. Stelle ausschalten
      output_high(stelle3);           // 3. Stelle ausschalten
      output_c(LED_MAP[st2] & 0b01111111);// Punkt einschalten
      output_low(stelle2);            // 2. Stelle einschalten
      toggle = 3;                     // beim nächsten ISR 3.Stelle
   }
   else                               // 3. Stelle ausgeben
   {  output_high(stelle1);           // 1. Stelle ausschalten
      output_high(stelle2);           // 2. Stelle ausschalten
      output_c(LED_MAP[st3]);         // 7-Segmentwert ausgeben
      output_low(stelle3);            // 3. Stelle einschalten
      toggle = 1;                     // beim nächsten ISR 1.Stelle
   }

   if(potizae > 0)
      potizae--;                      // Anzeigezeit neuer Sollwert
   else
      potiflag = FALSE;               // neuen Sollwert nicht mehr anzeigen

   adzae++;
   if(adzae > 99)                     // alle 500ms AD-Wandlung
   {  messen = TRUE;                  // nächste Messung freigeben
      adzae = 0;                      // Zähler rücksetzen
   }
}


//------------------------------------------------------------------------------
void main()
{  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_32);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(RA0_ANALOG );            // nur RA0 als Analogeingang

   enable_interrupts(INT_TIMER0);
   enable_interrupts(global);
   while(1)
   {  if(messen)
      {  temp_ist = ReadTemp();             // DS1820 einlesen
         temp_ist -= 1;                     // Korrekturwert (1 == 0,5K)
         if ((temp_ist % 2) == 1)           // 0,5K Auflösung
            st3 = 5;                        // Anzeige xx,5
         else
            st3 = 0;                        // Anzeige xx,0
         temp_ist /= 2;                     // Bitstellen halbieren

         set_adc_channel(0);                // (0 - 255 Bit)/4 = 63Bit
         soll_neu = (read_adc() / 4) + 20;  // 20°C - 83°C

         if(soll_neu > temp_ist)
            output_high(schalter);          // Heizen
         else
            output_low(schalter);           // nicht Heizen

         if(potiflag)                       // neuen Sollwert anzeigen?
         {  st1 = soll_neu / 10;            // 1. Stelle berechnen
            st2 = soll_neu % 10;            // 2. Stelle berechnen
            st3 = 0;                        // 3. Stelle auf 0 setzen
         }
         else
         {  if(soll_alt ==  soll_neu)       // Flackerfrei
            {  st1 = temp_ist / 10;         // 1. Stelle berechnen
               st2 = temp_ist % 10;         // 2. Stelle berechnen
            }
            else
            {  potizae = 400;               // Wertänderung
               potiflag = TRUE;             // es wurde am Poti gedreht
               soll_alt = soll_neu;         // neuen Wert übernehmen
               st1 = soll_neu / 10;         // 1. Stelle berechnen
               st2 = soll_neu % 10;         // 2. Stelle berechnen
               st3 = 0;                     // 3. Stelle auf 0 setzen
            }
         }
         messen = FALSE;
      }
   };
}


//------------------------------------------------------------------------------
// 1-Wire Reset erzeugen, 1 wenn kein Slave da ist, return 0 wenn einer da
//------------------------------------------------------------------------------
int OWTouchReset(void)
{  int result;
   output_bit(owdata, 0x00);        // PIN für 480us auf Low ziehen
   delay_us(480);                   // min 480us
   output_bit(owdata, 0x01);        // Bus freigeben
   delay_us(70);                    // min 60us
   result = input(owdata) & 0x01;   // schauen ob Slave auf 0 zieht
   delay_us(420);                   // min 420us
   return result;                   // Return Slave Präsenz
}


//------------------------------------------------------------------------------
// 1-Wire Bit schreiben. Provide 10us recovery time.
//------------------------------------------------------------------------------
void OWWriteBit(int bit)
{  if (bit)
   {  // Write ‘1’ bit
      output_bit(owdata, 0x00);     // PIN für 6us auf Low ziehen
      delay_us(6);                  // min 1us
      output_bit(owdata, 0x01);     // Bus freigeben
      delay_us(64);                 // min 60us
   }
   else
   {  // Write ‘0’ bit
      output_bit(owdata, 0x00);     // PIN für 60us auf Low ziehen
      delay_us(60);                 // min 60us
      output_bit(owdata, 0x01);     // Bus freigeben
      delay_us(10);                 // min 1us und 10us recovery
   }
}


//------------------------------------------------------------------------------
// 1 Bit vom 1-Wire Bus lesen and rückgeben. Provide 10us recovery time
//------------------------------------------------------------------------------
int OWReadBit(void)
{  int result;
   output_bit(owdata, 0x00);        // PIN für 6us auf Low ziehen
   delay_us(6);                     // min 1us
   output_bit(owdata, 0x01);        // Bus freigeben
   delay_us(9);                     // min 14us
   result = input(owdata) & 0x01;   // Sample the bit value from the slave
   delay_us(55);                    // Complete the time slot 45us and 10us recovery
   return result;
}


//------------------------------------------------------------------------------
// Daten Byte senden
//------------------------------------------------------------------------------
void OWWriteByte(int data)
{  int loop;
   for (loop = 0; loop < 8; loop++)  // Jedes Bit schreiben, LS-bit first
   {  OWWriteBit(data & 0x01);
      data >>= 1;                    // shift the data byte for the next bit
   }
}


//------------------------------------------------------------------------------
// Daten Byte lesen und rückgeben
//------------------------------------------------------------------------------
int OWReadByte(void)
{  int loop, result=0;
   for (loop = 0; loop < 8; loop++)
   {  result >>= 1;                 // shift the result to get it ready for the next bit
      if (OWReadBit())              // if result is one, then set MS bit
         result |= 0x80;
   }
   return result;
}


//------------------------------------------------------------------------------
// Write a 1-Wire data byte and return the sampled result.
//------------------------------------------------------------------------------
int OWTouchByte(int data)
{  int loop, result=0;
   for (loop = 0; loop < 8; loop++)
   {  result >>= 1;                 // shift the result to get it ready for the next bit
      if (data & 0x01)              // If sending a ‘1’ then read a bit else write a ‘0’
      {  if (OWReadBit())
         result |= 0x80;
      }
      else
         OWWriteBit(0);
      data >>= 1;                   // shift the data byte for the next bit
      }
return result;
}


//------------------------------------------------------------------------------
// Read and return the Integrated Current Accumulator
//------------------------------------------------------------------------------
int ReadTemp(void)
{  if (owTouchReset())        // Reset the 1-Wire bus
      return 0;               // Return if no devices found
   owWriteByte(0xCC);         // Skip ROM command, single device select
   owWriteByte(0x44);         // Begin Messung

   owTouchReset();            // Reset the 1-Wire bus
   owWriteByte(0xCC);         // Skip ROM command, single device select
   owWriteByte(0xBE);         // Send Read memory command

   return owReadByte();       // nur LSB einlesen 0 - 85°C
}


