#include <12F683.h>
#device adc=8
//#device adc=10

#FUSES NOWDT,NOMCLR,PUT
//#FUSES INTRC_IO //4Mhz y 8Mhz Internos
#FUSES HS      //12Mhz Externos

//#use delay(clock=4000000)
//#use delay(clock=8000000)
#use delay(clock=12000000)

#use standard_io(a)

#include <stdlib.h>
#include <math.h>

//--- Constantes ---
#define SERVO        PIN_A1   //linea de control por PWM para el servo
#define ADC_POT      0        //canal adc que se usa para el potenciometro
#define ANTIREBOTE   5        //define el antirebote del pot (0 a 255)
//------------------

//--- Variables ---
int1 flagLeerADC = FALSE;        //indica si se tiene que leer el adc
int1 flagPulso_Alto = FALSE;     //indica si esta el pulso en alto
int1 flag0mS = TRUE;             //indica cuando empieza a contar el PWM
int1 flagX2 = FALSE;             //Cuenta 2 rtcc del tmr0
int1 flagX3 = FALSE;             //Cuenta 3 rtcc del tmr0
int8 ValorADC;                   //Lectura del ADC
int8 AnteriorADC;                //Lectura anterior del ADC
//int16 Posicion_Servo = 1500;     //donde se posiciona el servo segun la lectura del adc (4Mhz)
//int16 Posicion_Servo = 3000;     //donde se posiciona el servo segun la lectura del adc (8Mhz)
int16 Posicion_Servo = 4500;     //donde se posiciona el servo segun la lectura del adc (12Mhz)
//-----------------

//--- Funciones ---
void Calcular_Posicion(void);
//-----------------

// --- Timer 0 ---
#int_TIMER0 //cada 65mS se lee el ADC
void TIMER0_isr(void){        //timer que cuenta 65.356mS
//Timer de 8 bits --> 256 = 1 RTCC
//Pescaler de 1:256

/*
//4Mhz ---
//1 tick cada 256uS = 0.256mS
//1 RTCC cada 65.536mS
   flagLeerADC = TRUE;
// -------

//8Mhz ---
//1 tick cada 128uS = 0.1286mS
//1 RTCC cada 32.768mS (x2 = 65.536mS)
   if(flagX2 == TRUE){ //espera 2 rtcc
      flagX2 = FALSE;
      flagLeerADC = TRUE;
   }
   else
      flagX2 = TRUE;
// -------
*/

//12Mhz ---
//1 tick cada 85.3^uS = 0.0853^mS
//1 RTCC cada 21.8453mS (x3 = 65.536mS)
   if(flagX2 == TRUE)
      if(flagX3 == TRUE){   //espera 3 rtcc
         flagX2 = FALSE;
         flagX3 = FALSE;
         flagLeerADC = TRUE;
      }
      else
         flagX3 = TRUE;
   else
      flagX2 = TRUE;
// --------
}
// ---------------

// --- Timer 1 ---
#int_TIMER1 //cuenta 20mS para controlar el servo
void TIMER1_isr(void) {       //timer que cuenta 20mS
//Timer de 16 bits --> 65536 = 1 RTCC
//Pescaler de 1:1

/*
//4Mhz ---
//1 tick cada 1 uS
//1 RTCC cada 20mS (65536 - 45536 Ticks)

   set_TIMER1(45535); //Xtal 4Mhz
   flag0mS = TRUE;
// -------

//8Mhz ---
//1 tick cada 0.5 uS
//1 RTCC cada 20mS (65536 - 25536 Ticks)

   set_TIMER1(25535);
   flag0mS = TRUE;
// -------
*/

//12Mhz---
//1 tick cada 0.3^ uS
//1 RTCC cada 20mS (65536 - 5536 Ticks)

   set_TIMER1(5535);
   flag0mS = TRUE;
// -------
}
// ---------------

void main(void) {
   int16 ValTMR1;

   setup_adc_ports(sAN0|VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
   setup_timer_1(T1_INTERNAL);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   //setup_oscillator(OSC_4MHZ);   //4Mhz Internos
   //setup_oscillator(OSC_8MHZ);   //8Mhz Internos
   setup_oscillator(OSC_NORMAL); //12Mhz Externos


   set_adc_channel(ADC_POT);

	do {
//>-----------------------Movimiento del servo--------------------------------->

         //--- Calcula posicion servo segun lectura adc ---
         if(flagLeerADC == TRUE){
            Calcular_Posicion();
            flagLeerADC = FALSE;
         }
         //------------------------------------------------

         //--- Dispara pulso PWM cuando se completan 5 RTCC ---
   		if(flag0mS == TRUE){
   			flag0mS = FALSE;
            output_high(SERVO);
            flagPulso_Alto = TRUE;
   		}
         //----------------------------------------------------

         //--- Baja pulso PWM cuando corresponda ---
         //valTMR1 = get_TIMER1() -  45535; //4Mhz
         //valTMR1 = get_TIMER1() -  25535; //8Mhz
         valTMR1 = get_TIMER1() -  5535; //12Mhz

         //baja el pulso en el tiempo correspondiente a Posicion
         if((flagPulso_Alto == TRUE) && (valTMR1 > Posicion_Servo)){
            output_low(SERVO);
            flagPulso_Alto = FALSE;
         }
         //-----------------------------------------
//<----------------------------------------------------------------------------<

	} while(true);
}

void Calcular_Posicion(void){
   int Diferencia;
   
   ValorADC = read_adc();  //lee ADC
   
   //calcula la diferencia (en valor absoluto) entre el valor anterior y
   //el actual del adc, si es mayor a ANTIREBOTE, cambia la posicion del
   //servo. No utilice la funcion "ABS()" porque no me daba el resultado esperado
   if(ValorADC > AnteriorADC)
      Diferencia = ValorADC - AnteriorADC;
   else{
      if(AnteriorADC > ValorADC)
         Diferencia = AnteriorADC - ValorADC;
      else
         Diferencia = 0;
   }
         
   if(Diferencia > ANTIREBOTE){
      //Posicion_Servo = 500 + floor(ValorADC * 7.8);   //4Mhz
      //Posicion_Servo = 1000 + floor(ValorADC * 15.6); //8Mhz
      Posicion_Servo = 1500 + floor(ValorADC * 23.4); //12Mhz

      AnteriorADC = ValorADC;
   }
}
