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: http://www.microchip.com/en_us/technology/mtouch/
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:
Aquí puedes ver un vídeo de su funcionamiento:
Y este es el código fuente, escrito en CCS:
pruebas mtouch.c
mTouch con 16LF727
http://www.micropic.es/ Nocturno 2009
*/
#include <16LF727.h>
#include <pruebas mtouch.h>
#define ANTIRREBOTES 1
#define SENSIBILIDAD 5
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;
TIPO_SENSOR Sensor[8];
/*************************************************************************************
INICIALIZACIÓN
*************************************************************************************/
void inicializacion() {
char i;
setup_oscillator(OSC_16MHZ);
for (indice=0; indice<8; indice++){ // Inicialización de variables
promedio[indice] = 0;
lectura[indice] = 0;
}
/* Utilizaremos estos 8 sensores:
CPS4: RB4
CPS5: RB5
CPS6: RA4
CPS7: RA5
CPS8: RD0
CPS9: RD1
CPS10: RD2
CPS11: RD3
*/
ANSELA = 0b00110000;
set_tris_a (0b11110111);
ANSELB = 0b00110000;
set_tris_b (0b01110001);
ANSELD = 0b00001111;
set_tris_d (0b11111111);
set_tris_c (0b11101001);
ANSELE = 0b00000000;
set_tris_e (0b00000000);
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
output_low(LED0); // Apagamos los leds
output_low(LED1);
output_low(LED2);
output_low(LED3);
output_low(LED4);
output_low(LED5);
output_low(LED6);
output_low(LED7);
}
/*************************************************************************************
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 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)
// Registros del micro
#byte ANSELA = 0x185
#byte ANSELB = 0x186
#byte ANSELD = 0x188
#byte ANSELE = 0x189
#byte PORTA = 0x5
#byte PORTB = 0x6
#byte PORTC = 0x7
#byte PORTD = 0x8
#byte PORTE = 0x9
#byte TRISA = 0x85
#byte TRISB = 0x86
#byte TRISC = 0x87
#byte TRISD = 0x88
#byte TRISE = 0x89
#byte T1CON = 0x010
#byte T1GCON = 0x08F
#byte CPSCON0 = 0x108
#byte CPSCON1 = 0x109
// Bits de configuración
#bit TMR1GIF = 0x0C.7 // clear gate intpt flag
#bit TMR1GIE = 0x8C.7 // enable gate intpt
#bit TMR1ON = 0x10.0
// Salidas de leds
#define LED0 PIN_B1
#define LED1 PIN_A3
#define LED2 PIN_B7
#define LED3 PIN_C1
#define LED4 PIN_C2
#define LED5 PIN_C4
#define LED6 PIN_B3
#define LED7 PIN_B2
El código fuente también está disponible para su descarga aquí: Código fuente mtouch en CCS
Espero que lo disfrutes.



