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:
- la función devuelve un 1 tan pronto como recibe una pulsación
- pero no admite otra pulsación válida hasta que se supere el periodo marcado como ANTIRREBOTES
- si la tecla se mantiene pulsada, devolverá un 1 cuando toque hacer una autorrepetición, y un 0 durante las pausas. Estas pausas pueden ser configuradas en tres bloques en función del tiempo que el usuario mantenga la tecla apretada
- también admite un parámetro que definirá si la tecla está en lógica directa o inversa
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.
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);
}