/*
Programa creado: 
Edpilo

Nombre:
MTOUCH6.C

Objetivo:
Probar algoritmo de promedio en el tiempo, junto con los teclados de 12mm y 20mm acompañados del 
acrilico de 2mm y 3mm.


*/

#include <12F683.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,NOMCLR,NOPROTECT,NOBROWNOUT,NOCPD
#use delay(clock=8000000,RESTART_WDT)
#use rs232(baud=57600, xmit=PIN_A5,FORCE_SW)

#byte port_a=0x05
#byte ANSEL =0x9F
#byte estado=0x03
#byte trisio=0x85


// DEFINICION DE VARIABLES ESPECIALES
#define led 	   PIN_A5	
#define CARGAR_CAP PIN_A1
#define SENSOR1    PIN_A0
#define SENSOR2    PIN_A2
#define SENSOR3    PIN_A4
#define PIN_TX     PIN_A5 
#define in         1
#define out        0 

#define w		   0
#define f		   1 
#define z		   2
#define c		   0


//////////////// Variables ////////////////
signed int16  raw[3]={0,0,0};
signed int16  average[3]={0,0,0};
const int     trip[3]={15,13,15};
#define       hyst    4
byte          teclas=0;
char          key=0;
byte          index=0;


////////////////  subrutinas //////////////

//----------------------------------------------------------------
// config_sen_inC()                                                 //
//----------------------------------------------------------------
/*
*Parametros:
* opc = Pin del pic a configurar en TRISIO Y ANSEL 
* n   = Opcion de configuracion: 0 salida 1 entradas
*
*Descripción:
*Se configura el pin del microcontrolador ya sea como entrada o 
*salida, tanto analoga como digital. 
*
*
*/
void  config_sen_inC(int opc,int n)
{
	
	if(opc==0)
	  {
		if(n)  
		 {
		  bit_set(ANSEL,0);
		  bit_set(trisio,0);		  
		 }
		  
		else 
		{ 
		 bit_clear(ANSEL,0);
		 bit_clear(trisio,0);
		 }
      } 		
    
	else if(opc==1)
	  {
		if(n)  
		{
		  bit_set(*0x9F,1);
		  bit_set(trisio,1);		  
		 }
		else  
		{
		 bit_clear(*0x9F,1);
		 bit_clear(trisio,1);
		 }
		 
      } 		
	else if(opc==2)
	  {
		if(n)  
		{
		  bit_set(*0x9F,2);
		  bit_set(trisio,2);		  
		  }
		else  
		{
		 bit_clear(*0x9F,2);
		 bit_clear(trisio,2);
		 }
		  
      } 		
    		
	else if(opc==4)
	  {
		if(n)  
		{
		  bit_set(*0x9F,3);
		  bit_set(trisio,4);		  
		  }
		else  
		{
		 bit_clear(*0x9F,3);
		 bit_clear(trisio,4);
		 }
		  
      } 	
	
}


//----------------------------------------------------------------
// cargar_chold()                                                 //
//----------------------------------------------------------------
/*
*Descripción: 
* Codigo encargado de cargar el capacitor CHOLD de conversor A/D
* tarea que se realiza en 4 pasos como se describe a continuación:
* 
* 1 -Se debe dejar un pin del conversor A/D  para esta tarea, es recomendable
*    que sea el pin del voltaje de referencia Vref, previamente se debe haber 
*    cargado el voltaje de referencia para el conversor analogo digital para 
*    nuestro caso VDD y VSS. Ahora este pin se deja como salida digital para 
*    aplicar el VDD. 
* 2 -Se pone dicho en pin el alto
* 3 -Se selecciona el canal analogico de dicho pin  para poder cargar el capacito CHOLD
*    tarea que se realiza si en este pin se encuenta un voltaje alto. 
* 4 -Se da un tiempo para asegurar que el capacitor este plenamente cargado, en este caso      
*    se dio 8TAD.
*/   
void cargar_chold(void)
{
        config_sen_inC(1,out);          //1
        output_high(CARGAR_CAP);        //2          
        set_adc_channel(1);             //3    
        delay_us(16);                   //4

}





//----------------------------------------------------------------
// tecla(int n)                                                 //
//----------------------------------------------------------------
/*
*Parametros: 
*  n-> tiene el valor de la tecla que se desea verificar
*
* Descripcion:
*  Este codigo quiza es el mas importante del programa ya que en este
*  se implementa el principio del sensado capacitivo empleando CVD.
*  Este se realiza en 7 pasos los cuales describire a continuacion:
*
*  1- Se caraga el capacitos de muestreo del A/D CHOLD
*  2- Se pone el pin del sensor a leer en bajo, el cual inicialmente debe estar configurado en el TRISIO como salida
*  3- Se da un tiempo pequeño de establecimiento "determinado por pruebas"
*  4- Se configura el pin del sensor como entrada analoga tonto en el TRISIO  como en ANSEL
*  5- Se elije el canal analogo al que corresponde dicho pin.
*  6- Se realiza la lectura lo mas rapido posible despues de haber seleccionado el canal se obtine mejor resultado 
*     que esperando un poco. Es posible emplear tambien la interrupción de finalización de lectrua A/D.
*  7- Se dejea el otra ves como salida tanto en le TRISIO como en ANSEL.       

*/
void tecla(int n)
{    
     if(n==0)
     {        
        cargar_chold();           //1
        output_low(SENSOR1);	  //2            
        delay_us(2);              //3
        config_sen_inC(0,in);     //4                                         
        set_adc_channel(0);       //5                                     
        raw[0]=read_adc();        //6
        config_sen_inC(0,out);    //7             
     }           
     else if(n==1)
     {
        cargar_chold();           
        output_low(SENSOR2);	              
        delay_us(2);        
        config_sen_inC(2,in);   //12us                                        
        set_adc_channel(2);                                            
        raw[1]=read_adc();                                   
        config_sen_inC(2,out);              
     }   
     else if(n==2)
     {                
        cargar_chold();   
        output_low(SENSOR3);	             
        delay_us(2);        
        config_sen_inC(4,in);                                           
        set_adc_channel(3);                                             
        raw[2]=read_adc();
        config_sen_inC(4,out);             

     }   
        
}        
//----------------------------------------------------------------
// scan_tecla(int t) 
//----------------------------------------------------------------
/*
*  Este codigo se encarga de verificar si hay tecla presionada 
*  
*/
void scan_tecla(int t)
{
            tecla(t);   //160us              
            //se verifica si hay tecla presionada            
            if (raw[t] < (average[t] - trip[t]) )               //Tecla presionada
                {
                  key=t+'1';
                }    
            else if(raw[t] > (average[t] - (trip[t] - hyst)))  //no hay tecla presionada 
                { 
                   average[t] = average[t] + (raw[t] - average[t])/16;             
                }                           

}


//-------------------------------------------------
//Este codigo verifica cada ves las tres teclas, el objetivo es el mantenimiento 
//del algoritmo del promedio movil en este caso para 16 medidas. Por lo tanto 
//el tiempo que se puede tardar escaneando una ves las tres teclas toma
//al rededor de 438us, mas el tiempo del calculo 585us el resultado 1.023ms
//mas el tiempo de los dos bulcles for, el proceso toma 1.07ms.

void scan_teclas(int b)
{
  int i,j;    
  for(j=0;j<b;j++)         //cuantas veces se verificaran las tres teclas 
  { 
        for(i=0;i<3;i++)   //Este codigo scanea tecla por tecla, para cada llamada 
           {           
                tecla(i);  
                average[i] = average[i] + (raw[i] - average[i])/16;               
           }      
  }     
  
}



//////////////////////// PROGRAMA PRINCIPAL /////////////////////////////////
void main(void)
{

  setup_oscillator(OSC_8MHZ);     //frecuencia de oscilación.
  setup_comparator(NC_NC_NC_NC);  //Se deshabilita el comparador
  setup_adc(ADC_CLOCK_INTERNAL);  //Se configura ANSEL <6:4> reloj interno
  SETUP_ADC_PORTS(VSS_VDD);       //CONFIGURO VDD COMO VOLTAJE DE REFERENCIA, el resultado es lo mismo colocando referencia externa
  SETUP_ADC_PORTS(NO_ANALOGS);    //INICIALMENTE TODAS LAS ENTRADAS DIGITALES
  
  set_tris_a(0x00);             
  port_a=0;                     //Este pic me permite configurar el TRISIO como salidas o entradas digitales, todo depende de ANSEL
                                //Por lo tanto se dejan todos los pines como salida
  output_high(PIN_TX);           
  delay_ms(10);                 //Tiempo mantenimiento pic. 
  
  scan_teclas(16);              //Escaneo 16 veces cada tecla. Tiempo aproximado 17.24ms, paro no observar el tiempo de carga.                            
 
                                               
  while(true)
  {
        scan_teclas(1);           //Se lee una ves todass las letra antes de verificar tecla oprimida.
        scan_tecla(index);        //Tiempo 405us 

       //1A
       //------------------------------------------------------------------------------------//
       //  Si "key" diferente de cero se envia el codigo de la tecal 1,2 o 3 en ASCII al PC  //
       //------------------------------------------------------------------------------------//
       if(key != 0)
        {
          putc(key);
          key=0;
        }  
        index=(index+1) % 3; //Mascara 
        //1B
        

/*      
        //.......................................................................  
        //  Codigo para poder ver en MTOUCH GUI.
        //  Para emplear este codigo se debe inhabilitar el 
        //  codigo desde 1A hasta 1B, para ver el resultado en el PC. de lo contrari
        //  solo se vera el codigo de la tecla presionada. 
        //.......................................................................
        if(index < 2)
        {
          index++;
        }
        else
        {
             printf("00000; ");
             //printf("%05Ld; %05Ld; %05Ld\r\n",average[0],average[1],average[2]);	//1-  Promedio teclas 
             printf("%05Ld; %05Ld; %05Ld\r\n",average[0],raw[0],average[1]);	    //2-  Lectura actual de las teclas
             index=0;        
        }
        
*/

 
                                     
	  
	}
  
   
 
 }
 
/////////////////////////////////////////////////////// 

 
 /*///////////////// Concluciones 

 
- El resultado con el teclado con planos de tierra tanto de teclas de 12mm se comporto bien con recubrimiento acrílico
  de 2mm y con resultados aceptables  para 3mm se debía presionar un poco más duro la tecla.
   
- Para el caso del teclado de 20mm se obtuvieron muy buenos resultados para los acrílicos de 3mm y 2mm.

- Ahora es posible implementar cualquier algoritmo para mejorar la detección por ejemplo en superficies con mucho punto de 
  roció, o en el caso de emplear superficies metálicas, recordar no emplear laminas metálicas mayores a 1mm ya que el tamaño 
  del botón resulta muy grande.  

 
 
 */