//**********************************************************************************************************************************
//Descrizione programma : Timer da 0 a 99 secondi
//Descrizione del funzionamento : Timer da 0 a 99 secondi con due display a 7 segmenti,le unita'
//su PORTD e le decine su PORTC.
//Allo start del conteggio viene attivato un rele connesso a RA0, alla fine del conteggio il
//rele viene disattivato.
//Per i display la decodifica BCD -> 7 seg viene realizzata dal PIC16F877. 
//Ci sono 3 pulsanti START (RB0), STOP (RB1) e SET (RB2). Se si preme SET si incrementano i display
//Se si preme START parte il conteggio, se si preme STOP viene tutto resettato (rele compreso) 
//anche se il conteggio non era terminato.

//**********************************************************************************************************************************
//Dati di sistema
//Fclock         : 4 MHz
//Fclock/16      : 250 Khz
//Tclock         : 4 uS
//Tistruzione    : 16 uS

//INCLUDE files
#include <pic.h>

//*********************************************************************************************************************************
//Configurazione bit di programmazione
//Oscillatore : XT
//Watchdog : OFF
//Power Up Timer : ON
//Code Protect : ALL
//Brown Out Detect : ON
//Low Voltage Program : Disable
//Data EE Protect : OFF
//Flash Program Write : Disable
//Background Debug : Disable

//0b 0000 0101 0100 0001
__CONFIG(0x0D41);
//


//*********************************************************************************************************************************
//Prototipi
void SystemInit (void);
void Delay (unsigned int);
void BinToBcd (unsigned char);
unsigned BcdTo7seg (unsigned char);
void CCP1Period (unsigned int);

//*********************************************************************************************************************************
//Simboli
#define RELE RA0
#define START RB0
#define STOP RB1
#define SET RB2
#define CCP1CONInit 0b00001011; compare mode special trigger event -->reset TMR1


//*********************************************************************************************************************************
//Tipo di segnale (analogico o digitale) sui PORTx
#define ADMode 0x06;   //tutto in digitale

//Configurazione modulo CCP1
#define CCP1CONInit 0b00001011  //compare mode, trigger special event

//Collegamenti a PORTA
//RA0 (OUT) --> RELE
//RA1 (OUT) --> NU
//RA2 (OUT) --> NU
//RA3 (OUT) --> NU
//RA4 (OUT) --> NU
//RA5 (OUT) --> NU
#define PortAInit 0x00;
#define TrisAInit 0x00;

//Colelgamenti a PORTB
//RB0 (IN)  <-- START 
//RB1 (IN)  <-- STOP
//RB2 (IN)  <-- SET
//RB3 (OUT) --> NU
//RB4 (OUT) --> NU
//RB5 (OUT) --> NU
//RB6 (OUT) --> NU
//RB7 (OUT) --> NU
#define PortBInit 0x07;
#define TrisBInit 0x07;

//Colelgamenti a PORTC
//RC0 (OUT) --> a1
//RC1 (OUT) --> b1
//RC2 (OUT) --> c1
//RC3 (OUT) --> d1
//RC4 (OUT) --> e1
//RC5 (OUT) --> f1
//RC6 (OUT) --> g1
//RC7 (OUT) --> NU
#define PortCInit 0x00;
#define TrisCInit 0x00;

//Colelgamenti a PORTD
//RD0 (OUT) --> a0
//RD1 (OUT) --> b0
//RD2 (OUT) --> c0
//RD3 (OUT) --> d0
//RD4 (OUT) --> e0
//RD5 (OUT) --> f0
//RD6 (OUT) --> g0
//RD7 (OUT) --> NU
#define PortDInit 0x00;
#define TrisDInit 0x00;

//Colelgamenti a PORTE
//RE0 (OUT) --> NU
//RE1 (OUT) --> NU
//RE2 (OUT) --> NU
#define PortEInit 0x00;
#define TrisEInit 0x00;

//Global var
unsigned char Time_Count;    //contatore
unsigned char BCD_L;         //unita'
unsigned char BCD_H;         //decine

//*********************************************************************************************************************************
//Main
void main(void)
{
 SystemInit();
 CCP1Period(62500);
 for (;;)
 {
  if (SET==0 && Time_Count<99)     //se spingo SET e count non e' arrivato a 99
  {
   Time_Count++;                 //incremento Time_Count
   Delay(2000);                  //piccola isteresi che serve se tengo premuto SET
  }

  if (Time_Count==0 || STOP == 0)  //se e' finito il countdown o premos STOP
  {
   Time_Count=0;           //azzero Time_Count
   RELE=0;                 //spengo il rele 
   TMR1ON==0;              //blocco il Timer1
  }

  BinToBcd(Time_Count);   //trasformo Time_Count in BCD
  PORTD=BcdTo7seg(BCD_L); //unita
  PORTC=BcdTo7seg(BCD_H); //decine
 }
 
}


//*********************************************************************************************************************************
//Definizione funzioni

void SystemInit (void)
{
 //Tipi di segnali sui portx
 ADCON1 = ADMode;

 //Inizializzazione PORTx
 PORTA = PortAInit;
 PORTB = PortBInit;
 PORTC = PortCInit;
 PORTD = PortDInit;
 PORTE = PortEInit;


 //Direzione PORTx
 TRISA = TrisAInit;
 TRISB = TrisBInit;
 TRISC = TrisCInit;
 TRISD = TrisDInit;
 TRISE = TrisEInit;

 //Registro INTCON
 GIE    = 1;  //abilita globalmente gli interrupt
 PEIE   = 1;  //abilita l'interrupt per le periferiche
 INTE   = 1;  //abilita l'interrupt su RB0/INT (START)
 CCP1IE = 1;  //abilita l'interrupt per il module CCP1

 //Registro OPTION
 RBPU    = 0; //pull up su PORTB
 INTEDG  = 0; //interrupt sul fronte di discesa di RB0/INT   
 T1CKPS1 = 1; //prescaler 1:4
 T1CKPS0 = 0; //    "      "
 T1OSCEN = 0; //oscillatore esterno disabilitato
 TMR1CS  = 0; //clock interno
 TMR1ON  = 0; //timer bloccato

 //Registro CCP1CON
 CCP1CON = CCP1CONInit;  //CCP1 genera flag di interrupt (CCP1IF) e resetta TMR1 
}

//ritardo
void Delay (unsigned int Value)
{
 unsigned int Rit;
 for (Rit=0; Rit<Value; Rit++);
}

//conversione binario BCD va ad agire direttamente su variabili globali
void BinToBcd (unsigned char Valore)
{
 BCD_H = Valore/10;   //conversione di base
 BCD_L = Valore%10;
}

//
unsigned BcdTo7seg (unsigned char digit)
{
 if (digit == 0)
 return (0b00111111);

 if (digit == 1)
 return (0b00000110);

 if (digit == 2)
 return (0b01011011);

 if (digit == 3)
 return (0b01001111);

 if (digit == 4)
 return (0b01100110);

 if (digit == 5)
 return (0b01101101);

 if (digit == 6)
 return (0b01111101);

 if (digit == 7)
 return (0b00000111);

 if (digit == 8)
 return (0b01111111);
 
 if (digit == 9)
 return (0b01101111);

 else
 return (0b00000000);
}

//scrittura del periodo in CCP1
void CCP1Period (unsigned int Periodo)
{
 CCPR1H = Periodo >> 8;   //ms byte
 CCPR1L = Periodo;        //ls byte, Periodo entra negli 8 bit di CCPR1L e taglia gli 8 bit sopra
}

//routine di interrupt
void interrupt CCP1InterruptService (void)
{
 if (CCP1IF)
  {
   CCP1IF = 0;   //riarma interrupt su CCP1
   Time_Count--; //decrementa time count
  }

 if (INTF)
  {
   INTF=0;    //riarma interrupt su RB0/INT
   RELE=1;    //rele on
   TMR1ON=1;  //timer avviato
  } 
}



