Bueno después de tanto buscar y leer algunos temas de ayuda de microchip por fin logre echar andar el proyecto de teclado de detección capacitiva y como en este foro he encontrado mucha ayuda pues lo menos que puedo es colaborar con toda la gente que propone sus temas y proyectos con el fin de ayudar a los demás.
Les dejo un programa con el PIC 16F887 para detección capacitiva, en el cual se emplean los dos comparadores que este trae en conjunto con el Timer1 para conteo de pulsos y el timer0 para control del periodo, como se observa en al figura despues del codigo.
Este información está disponible en las notas de ayuda de microchip
Nota AN110, AN1102, AN1103 y AN1101. Basado en esta información se realizo el programa tanto para el PIC16F887, con detección por frecuencia junto con latch SR como por CVD para el PIC12F683. El esquematico esta en la nota en la que dejo el hipervinculo, aunque en este caso no se monto la LCD.
Aqui el programa para el PIC16F887 en CCSc
/*
NOMBRE:
--------
MTOUCHFF.C
Realizado por:
--------------
Edpilo
Objetivo:
----------
Este programa se hace con el fin de implementar detección capacitiva implementando frecuencia, este método
se basa en la idea de tener una frecuencia base y un contador de pulsos. Se crea un periodo fijo en el
cual se toma un conteo de pulsos que en promedio es el mismo si la frecuencia no cambia, ese es el principio
fundamenta, ya que al cambiar la frecuencia disminuye el conteo de pulsos, por esta razón siempre se emplean 2
timer; en el primero se fija el periodo y en el segundo se realiza el conteo de pulsos.
Esto se logra aprovechando que las teclas generan una capacitancia parasita mas la capacitancia producida al colocar
el dedo en la placa este cambia la capacitancia y por ende la frecuencia.
NOTA:
-Para entender el concepto completo dirigirse a las notas de microchip
AN1101, AN1102, AN1103 y AN1104
-La trama de datos se ha organizado para poder emplear la herramienta de microchip
mtouch CVD framework PIC16F.
*/
#include <16F887.h>
#fuses INTRC,WDT,NOPROTECT,BROWNOUT,PUT,NOLVP,NOFCMEN,NOIESO,NODEBUG
#use delay(clock=8000000,restart_wdt)
#use RS232(BAUD=115200, BITS=8, PARITY=N, XMIT=PIN_C6, RCV=PIN_C7, RESTART_WDT,ERRORS)
#byte port_a=5
#byte port_b=6
#byte port_c=7
#byte port_d=8
#byte port_e=9
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
#byte INTCON=0X0B //Registro de control de interrupciones
#byte CM1CON0=0x107 //Registro de control del comparador 1
#byte CM2CON0=0X108 //Registro de control del comparador 2
#byte CM2CON1=0X109 //Registro de control 2 del comparador 2
#byte VRCON=0X097 //Registro de control del voltaje de referencia del comparador
#byte SRCON=0X185 //Registro de control del latc SR
#byte ANSEL=0X188 //Registro de control de configuracion de entradas analogas
#byte ANSELH=0X189 //Registro de control 2 de entradas analogas.
//////////////////////////////////// VARIABLES ///////////////////////////////////////////
//-------------------- hardware
#define led PIN_B2
#define led4 PIN_B4
#define led3 PIN_B5
#define led2 PIN_B6
#define led1 PIN_B7
#define pul PIN_B0
//---------------------constantes hardware
#define hyst 14
//----------------------Variables ram
signed long int average[4]={0,0,0,0};
long int lecturas[4]={0,0,0,0};
long int trip[4]={23,34,33,16}; //La diferencia entre el maximo y valor minimo con el dedo presionado y a esta se le sac el 80%.
long int raw=0;
int index=0;
short bandera=0;
int prueba=0;
//Banderas para indicar si hay no presionado boton
struct {
byte BTN0:1;
byte BTN1:1;
byte BTN2:1;
byte BTN3:1;
}Buttons;
//En la siguiente variables se organizan los bits de cada registro de control de los comparadores.
/*Para el comparador 1:
En cada caso se activa el comparador(C1ON) y se hace que su salida sea invertida (C1POL). Igualmente se seleciona el
canal con el mux para cada comparador (Recordar que esta familia trae 2 comparadores con cuatro entradas),
para que cada pin C12INx- del comparador 1 se conecte con C1VIN- del comparador 1.
Muy importante el bit(C1R), con el cual se selecciona tanto la referencia externa pin (C1Vin+) como la interna
C1Vref. En este caso se ha configura internamente a la salida de C1Vref, este voltaje de referencia se fija con
el registro VRCON aprosimadamente en 2/3 de Vdd.
Para el comparador 2.
Igua que en el anterior en cada caso se activa el comparador (C2ON), se hace que su salida sea no invertida (C2POL), se
habilita la salida del comparador (C2OUT); cuidado, se debe configura A5 o el pin que corresponda como salida. Este comparador tambien
es posible conectarle su voltaje de referencia tanto extenamente (C2IN+) como internamente(V2REF), en este caso (C2R) se configura
para que para que el pin C2IN+(RA2) se conecte con C2VIN del comparador o le que seria que la referencia sera externa. En este caso
se conecta el oscilador RC tal cual como se encuentra en las datasheet AN1101, AN1102,AN1103 y AN1104 de microchip.
*/
//C12INx
int COMP1[4] = {0x94, 0x95, 0x96, 0x97};
int COMP2[4] = {0xA0, 0xA1, 0xA2, 0xA3};
///////////////////////////////////////////////////////////////////////////////
/*
Subrutina para configurar los diferentes registros empleados para la deteccion capacitiva.
*/
void config_hard()
{
setup_adc_ports(sAN0|sAN1|sAN2|sAN9|sAN10); //Se configura en el registro ANSEL y ANSELH las entradas analogas.
set_tris_a(0b00000111); //RA0,RA1 (C12IN<0:1>) y RA2 (C2IN+) como entradas el resto salidas
set_tris_b(0b00001011); //RB2 y RB3 como entradas analogas (C12IN<3:2>) el resto salidas
set_tris_c(0b10000001); //RC0 entrada (T1CKI), RC7 entrada (rs232), el resto salidas
set_tris_d(0); //salidas
set_tris_e(0); //salidas
CM1CON0=COMP1[0]; //Se configura el canal C12IN0
CM2CON0=COMP2[0]; //Se configura el canal C12IN0
CM2CON1=0X20; //Se conecta CVref a la entrada de C1Vin+ del comparador 1
SRCON=0XF0; //En este registro se comfigura para que la salida del comparador 2 se conecte con /Q y el comparador 1 con Q y ambos
//empleen el latch SR.
VRCON=0X86; //Se activa Vref para el comparador 1 (VREN), se activa (VRR) para alto rango formula con la que se determina
//el votaje de referencia para este caso: Vdd/4 + (VR<3:0>/32)*Vdd => 5/4+(6/32)*5=2.1875, VR se puede cambiar
//segun la tolerancia de los componentes RC empleados.
SETUP_TIMER_0(T0_INTERNAL | RTCC_DIV_64); //Se configura el timer 0 con un prescaler de 32 (4) segun recomendacion AN1103
SETUP_TIMER_1(T1_EXTERNAL|T1_DIV_BY_1 ); //Se activa el timer 1 para conteo de pulsos reloj externo sin prescaler.
//SETUP_TIMER_1(T1_EXTERNAL|T1_GATE|T1_DIV_BY_1 );
Buttons.BTN0 = 0;
Buttons.BTN1 = 0; //Bandera de botone en ceros
Buttons.BTN2 = 0;
Buttons.BTN3 = 0;
port_b=0;
port_a=0;
port_c=0;
port_d=0;
port_e=0;
}
//---------------------------------------------------
void enviar(void)
{
restart_wdt();
printf("00000; ");
//printf("%05Ld; %05Ld; %05Ld; %05Ld\r\n",average[0],average[1],average[2],average[3]); //Se envia esta trama para realizar los calculos
//printf("%05Ld; %05Ld; %05Ld; %05Ld\r\n",lecturas[0],lecturas[1],lecturas[2],lecturas[3]); //deatos crudos sin promedio de cada lectura
printf("%05Ld; %05Ld; %05Ld; %05Ld\r\n",average[2],lecturas[2],average[3],lecturas[3]); //para verificar promedio y datos crudos de dos botones.
bandera=0;
}
///////////////////////////////////////////////////////////////////////////////
void main()
{
config_hard();
output_high(LED);
delay_ms(10);
output_low(LED);
INTCON=0; //No olvidar emplear esta instruacción antes de configurar cualquier vector de interrupción
set_timer1(0);
set_rtcc(0);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RTCC);
while(true)
{
restart_wdt(); //Codigo para activar los leds de cada tecla
if(Buttons.BTN0)
output_high(LED1);
else
output_low(LED1);
if(Buttons.BTN1)
output_high(LED2);
else
output_low(LED2);
if(Buttons.BTN2)
output_high(LED3);
else
output_low(LED3);
if(Buttons.BTN3)
output_high(LED4);
else
output_low(LED4);
if(bandera)
enviar();
if(input(pul)) //Entrada digital para pulsador
{
output_high(LED2);
delay_ms(50);
output_low(LED2);
delay_ms(50);
output_high(LED2);
delay_ms(50);
output_low(LED2);
delay_ms(50);
}
}
}
////////////////////////////// INTERRUPCIONES /////////////////////////////////////
#INT_RTCC
void isr_timero(void)
{
restart_wdt();
raw=GET_TIMER1();
lecturas[index]=raw;
//prueba++;
if (raw < (average[index] - trip[index]) ) //si
{
// Button Pressed
// 1. Se setea el flag del Button segun el numero del index
// 2. No se requiere realizar el codigo del promedio en esta acción
// 1
switch(index)
{
case 0:
Buttons.BTN0 = 1;
break;
case 1:
Buttons.BTN1 = 1;
break;
case 2:
Buttons.BTN2 = 1;
break;
case 3:
Buttons.BTN3 = 1;
break;
}
}
else if (raw > (average[index] - (trip[index] - hyst)))
{
// Button unpressed
// 1. se borra el flag de Boton segun el numero del index
// 2. Se continua cargando datos al algorito de promedio en el tiempo (Promedio movil)
// 1
switch(index)
{
case 0:
Buttons.BTN0 = 0;
break;
case 1:
Buttons.BTN1 = 0;
break;
case 2:
Buttons.BTN2 = 0;
break;
case 3:
Buttons.BTN3 = 0;
break;
}
// 2
average[index] = average[index] + (raw-average[index])/16;
}
if(index < 3)
index++;
else
{
index=0;
bandera=1;
}
CM1CON0=COMP1[index];
CM2CON0=COMP2[index];
set_timer1(0);
set_rtcc(0);
}
/*
PARA TENER EN CUENTA EN LA CONFIGURACIÓN
Nota:
Como el timer1 puede ser controlado externamente por T1G o por el comparador 2, se debe tener cuidado en la configuración de los
siguientes registros, si no se desea inhabiliar el Timer1 durante un conteo involuntariamente por RB5/T1G, este pin se debe dejar como salida en ceros, de
lo contrario si este pin se coloca en alto el timer1 no cuenta, con las siguiente configuracion.
Solución:
---------
Luego es posible dejar este pin como entrada y de esta manera no se inhabilitara el timer1 por conteo, al terminar de usar timer1
el pin se puede configurar como sea.
Opcion 1
si CM2CON1=0B00100010
||
| - CSYNC=0 Salida sincrona con flanco de bajado timer1
---T1GSS=1 Fuente de disparo externa T1G
y con
T1CON=0B01000111
| |||
| || --TMRON=1 Timer1 habilitado
| | ---TMR1CS=1 Fuente de reloj externo
| --- T1SYNC=1 No sincronizado
--------TMR1GE=1 Conteo del timer 1 controlado por la funcion de disparo (Gate function) SETUP_TIMER_1(T1_EXTERNAL|T1_GATE|T1_DIV_BY_1 );
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Opcion 2
O se puede evitar inhabilitar timer1 por conteo por RB5/T1G con la siguiente configuracioa pero el pin RB5/T1G se vera afectado por la convinacion comparador2 y timer1, si el pin esta configurado
como salida. Por lo tanto se debe tener cuidado con el hardware conectado a este pin ya que al ponerlo en alto, se ve reflejada la salida del comparador 2 por este pin.
si CM2CON1=0B00100000
||
| - CSYNC=0 Salida sincrona con flanco de bajado timer1
---T1GSS=0 fuente de disparo timer1 es SYNCC2OUT
y con
T1CON=0B01000111
| |||
| || --TMRON=1 Timer1 habilitado
| | ---TMR1CS=1 Fuente de reloj externo
| --- T1SYNC=1 No sincronizado
--------TMR1GE=1 Conteo del timer 1 controlado por la funcion de disparo (Gate function) SETUP_TIMER_1(T1_EXTERNAL|T1_GATE|T1_DIV_BY_1 );
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Opcion 3
Tambien con esta otra configuración, con la cual esta este programa.
si CM2CON1=0B00100000
||
| - CSYNC=0 Salida sincrona con flanco de bajado timer1
---T1GSS=0 fuente de disparo timer1 es SYNCC2OUT
y con
T1CON=0B00000111
| |||
| || --TMRON=1 Timer1 habilitado
| | ---TMR1CS=1 Fuente de reloj externo
| --- T1SYNC=1 No sincronizado
--------TMR1GE=0 Timer1 configurado para conteo SETUP_TIMER_1(T1_EXTERNAL|T1_DIV_BY_1 );
*/