TODOPIC

Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: Nocturno en 16 de Mayo de 2014, 12:47:43

Título: Optimizando la lectura de un pulsador
Publicado por: Nocturno en 16 de Mayo de 2014, 12:47:43
La lectura de un pulsador es una de las tareas más sencillas y prácticas a la que todos nos hemos enfrentado en nuestros comienzos.
Y una vez que te enfrentas a ello, lo que en principio parece muy obvio, te encuentras con distintos problemas y oportunidades de mejora que van complicando la tarea.

Por ejemplo, ¿no habéis tenido que programar un delay antirrebotes?, ¿no tenéis pulsadores en lógica directa y otros en lógica inversa?, ¿no os gustaría en determinadas acciones que vuestro pulsador tuviera autorrepetición?

Intentando dar servicio a estos problemas de una forma estándar y abierta he preparado la función que veis a continuación, y que está comentada para que sea más fácil de digerir.

Esta función está pensada para ser metida en un bucle, ya sea en el main o en una interrupción del timer, y ofrece:

Seguro que se puede mejorar y optimizar, así que serán bienvenidas cuantas mejoras y ampliaciones que queráis hacerle.

Espero que os sea muy útil.

Código: [Seleccionar]
unsigned int1 Pulsacion(unsigned int8 Indice, unsigned int8 Pin, unsigned int1 TipoPin, unsigned int1 Logica) { 
   /*
      Esta función gestiona las entradas de pulsador, mediante el control de un retardo
      antirrebotes y con la opción de autorrepetición de hasta 3 velocidades
     
      Para que funcione, hay que dimensionar la variable Entradas con el nº de pulsadores
      que queramos controlar.
     
      ENTRADAS
         Indice: hace referencia al nº de pulsador a chequear
         Pin: indica el estado del pin del pulsador (lógica inversa)
         TipoPIN:
            TipoPin=0   -> No tiene autorrepetición
            TipoPin=1   -> Pin con autorrepetición   
         
      SALIDA
         La función devuelve un 1 si el pulsador está en condiciones de ser procesado
         y un 0 en caso contrario.
     
   */
   
   #define ANTIRREBOTES    20    // Nº de ciclos mínimo antes de detectar otra pulsación
   #define CAMBIO1         100   // Nº de ciclos para el primer intervalo
   #define CAMBIO2         500   // Nº de ciclos para el segundo intervalo
   #define CAMBIO3         2000  // Nº de ciclos para el tercer intervalo
   #define VELOCIDAD1      100   // Velocidad de autorrepetición más lenta
   #define VELOCIDAD2      50    // Velocidad de autorrepetición mediana
   #define VELOCIDAD3      10    // Velocidad de autorrepetición más rápida
   #define SIN_REPETICION  0     // La tecla no repite si se mantiene pulsada
   #define CON_REPETICION  1     // La tecla sí repite si se mantiene pulsada
   #define LOGICA_DIRECTA  0     // Al pulsar se recibe un 0
   #define LOGICA_INVERSA  1     // Al pulsar se recibe un 1
   
   static unsigned int16 Entradas[5]={0,0,0,0,0};  // Dimensionar en función del nº de pulsadores
   unsigned int16 j;
   unsigned int1 resultado=0;
   
   j=Entradas[Indice];  // Como leemos muchas veces el array, lo pasamos a variable local para
                        // incrementar la velocidad de ejecución
                       
   // Si se detecta pulsación y antes no había, devolvemos un 1 en resultado
   if ((((!Pin && Logica==LOGICA_INVERSA) || (Pin && Logica==LOGICA_DIRECTA)) && (j==0))) {
         resultado=1;
         j=1;
   };
   
   // Cada vez que se entra a la función se incrementa una unidad el array
   if (j>0)
         Entradas[Indice]++;
   
   // Si se detecta que ya no se está pulsando, inicializamos a 0 el array
   if (((Pin && Logica==LOGICA_INVERSA) || (!Pin && Logica==LOGICA_DIRECTA)) && j>ANTIRREBOTES)
      Entradas[Indice]=0;
     
   if (TipoPin) { // Si el pulsador tiene autorrepetición
      // Cuando se supera el nº de ciclos 3, devolveremos un 1 con la frecuencia VELOCIDAD3
      if ((j>=CAMBIO3) && !(j%VELOCIDAD3)){           
         resultado=1;
      } else
         // Cuando se supera el nº de ciclos 2, devolveremos un 1 con la frecuencia VELOCIDAD2
         if ((j>=CAMBIO2) && !(j%VELOCIDAD2)){
            resultado=1;
      } else
         // Cuando se supera el nº de ciclos 1, devolveremos un 1 con la frecuencia VELOCIDAD1
         if ((j>CAMBIO1) && !(j%VELOCIDAD1)){
            resultado=1;
      };
   }
   
   return (resultado);
}

Título: Re: Optimizando la lectura de un pulsador
Publicado por: ppyote en 16 de Mayo de 2014, 13:32:56
Hoy mismo la probaré
gracias por compartir Nocturno
Título: Re: Optimizando la lectura de un pulsador
Publicado por: PalitroqueZ en 16 de Mayo de 2014, 17:20:01
que bien!, incluye todas las opciones en una función. Gracias Manolo!!
Título: Re: Optimizando la lectura de un pulsador
Publicado por: BrunoF en 16 de Mayo de 2014, 18:43:38
Muy bien mano,

gracias por compartirlo. Hace algunos años compartí una subrutina mía, pero estaba orientada a dos pulsadores, y permitía registrar los eventos:

1) pulsación corta del pulsador A;
2) pulsación corta del pulsador B;
3) pulsación larga (c/ repetición) del pulsador A;
4) pulsación larga (c/ repetición) del pulsador A;
5) pulsador A mantenido y se presiona el B;
6) pulsador B mantenido y se presiona el A;
7) ambos A y B mantenidos;

Creo que esas eran todas.

Si sirve la vuelvo a colgar, aunque era más rebuscado el código que el tuyo.

Saludos!

Título: Re: Optimizando la lectura de un pulsador
Publicado por: Nocturno en 18 de Mayo de 2014, 07:39:37
He colgado un vídeo demostrando el funcionamiento de la función y el código fuente que he usado en el ejemplo.

Podéis verlo aquí:
http://www.micropic.es/mpblog/2014/05/gestion-de-pulsadores/