En este proyecto experimentamos con la tecnología mTouch de Microchip, que incorporan algunos de sus micros y que permite leer sensores capacitivos.
Los sensores capacitivos nos ofrecen la posibilidad de diseñar interfaces de usuario muy versátiles gracias a que son capaces de detectar la pulsación de un dedo a través de un material que los recubra, como puedes comprobar con el metacrilato y el papel que he usado en el vídeo más abajo.
Además, usando esta técnica se consiguen paneles perfectamente herméticos válidos para la intemperie ya que la humedad no puede pasar a través de los sensores.
La familia de micros de Microchip que incorpora esta tecnología es esta:
En mi caso, elegí un 16LF727 para mi prototipo:
Como se puede comprobar, la PCB está realizada en una única cara, y sólo tiene dos puentes. Esto facilita su rápida fabricación y montaje.
Para poder diseñarla a una sola cara, tuve que colocar los Touchpads y los leds en los pines que "geográficamente" más me interesaban, y esto no coincide con el orden de los mismos en el esquemático. Por ello el esquema ha quedado algo desordenado:
unsigned char indice; unsigned long lectura[8]; // lectura de cada sensor unsigned long promedio[8]; // promedio leído de cada sensor unsigned long umbral; // umbral que debe superar para que se considere pulsado unsigned long promedio_alto; // variable temporal de promedio alto unsigned long promedio_bajo; // variable temporal de promedio bajo
typedef struct{ // Estructura de información de los sensores unsigned char rebotes; unsigned char Pulsado:1; unsigned char SePulso:1; unsigned char Soltado:1; } TIPO_SENSOR;
setup_timer_2(T2_DIV_BY_16,0xB4,15);// Timer2 activo, prescaler 1:16 setup_timer_1(T1_GATE_INVERTED); // TMR1 activo, asociado a capacitivo, sin prescaler T1GCON = 0b11100010; // Timer1 gate activo, y asociado al Timer2
CPSCON0 = 0b10001100; // Activamos los sensores capacitivos CPSCON1 = 0x04; // Empezamos por el sensor nº 4, el primero de los que usamos indice = 0;
TMR1GIF = 0; // Borramos el flag de interrupción TMR1GIE = 1; // Activamos la interrupción del Timer1 Gate enable_interrupts(GLOBAL); // Activamos la gestión de interrupciones
for(i=0; i<8; i++) Sensor[i] = 0; // Inicialización de variables
/************************************************************************************* RUTINA DE INTERRUPCIÓN *************************************************************************************/
#INT_DEFAULT void GestionDeInterrupciones() { if (TMR1GIF && TMR1GIE) { // Interrupción del Timer1 Gate TMR1GIF = 0; // Borramos el flag de interrupción TMR1ON = 0; // Paramos el timer1
// Cálculo de la media móvil de los últimos 4 ciclos lectura[indice] = promedio_alto = get_timer1() * 4; promedio_bajo = promedio[indice] / 4; umbral = promedio[indice]>>SENSIBILIDAD;
// Si ha pulsado, veremos que el Timer se ha acortado, por debajo del promedio - umbral if (promedio_alto < promedio[indice] - umbral) { // Chequeo repetitivo para evitar rebotes if(Sensor[indice].rebotes < ANTIRREBOTES) Sensor[indice].rebotes++; if(!Sensor[indice].SePulso && Sensor[indice].rebotes == ANTIRREBOTES) { Sensor[indice].Pulsado = 1; Sensor[indice].SePulso = 1; } } else { // Si no ha pulsado y estamos en ciclo de rebotes if(Sensor[indice].rebotes > 0) Sensor[indice].rebotes--; if(Sensor[indice].SePulso && Sensor[indice].rebotes == 0) { Sensor[indice].SePulso = 0; Sensor[indice].Soltado = 1; } // Al promedio acumulado le restamos el valor antiguo y le metemos el nuevo promedio[indice] += promedio_alto/4 - promedio_bajo; } set_timer1(0); // Iniciamos la cuenta en el Timer1 TMR1ON = 1; // Activamos nuevamente el Timer1 indice ++; // Pasamos al siguiente sensor indice &= 0x07; // La máscara nos permite contar de 0 a 7 CPSCON1 = indice+4; // Sumamos 4 porque nuestros sensores son del 4 al 11 } }
/************************************************************************************* PROGRAMA PRINCIPAL *************************************************************************************/ void main() { unsigned char i;
inicializacion();
while (true) { // bucle infinito for(i=0; i<8; i++) { // recorremos los 8 sensores if(Sensor[i].Pulsado) { // se ha detectado pulsación switch(i) { // encendemos el led que corresponda case 0: output_high(LED0); break; case 1: output_high(LED1); break; case 2: output_high(LED2); break; case 3: output_high(LED3); break; case 4: output_high(LED4); break; case 5: output_high(LED5); break; case 6: output_high(LED6); break; case 7: output_high(LED7); break; } Sensor[i].Pulsado = 0; // trabajo realizado, borramos el indicador } else if(Sensor[i].Soltado) { // se ha quitado el dedo switch(i) { // apagamos el led que corresponda case 0: output_low(LED0); break; case 1: output_low(LED1); break; case 2: output_low(LED2); break; case 3: output_low(LED3); break; case 4: output_low(LED4); break; case 5: output_low(LED5); break; case 6: output_low(LED6); break; case 7: output_low(LED7); break; } Sensor[i].Soltado = 0; // trabajo realizado, borramos el indicador } } } }
pruebas mtouch.h
#FUSES INTRC_IO //Oscilador interno #FUSES VCAP_A0 //VCAP en pin A0 #FUSES NOWDT //No Watch Dog Timer #FUSES NOPROTECT //Código accesible #FUSES PLLEN //PLL activado #FUSES MCLR //Master Clear activado #FUSES NOBROWNOUT //No brownout reset #FUSES NOPUT //No Power Up Timer
#use delay (clock=8000000)
// No dejamos que el compilador establezca los TRIS #use fast_io(A) #use fast_io(B) #use fast_io(C) #use fast_io(D) #use fast_io(E)