Experimentando con mTouch: lectura de sensores capacitivos
User Rating: / 20
PoorBest 
Monday, 14 December 2009 11:49

 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:

Prototipo mtouch


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:

Esquema mTouch 


Aquí puedes ver un vídeo de su funcionamiento:

Dim lights Embed Embed this video on your site


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 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)
// 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.

Last Updated on Monday, 08 February 2010 10:38