Es perfectamente legítimo utilizar todos los estados clave presentes en una serie de registros de turnos y llevar esos estados al ámbito del software. Todo lo que necesita hacer es muestrear los estados clave de forma periódica y en cada muestra realizar algunas "matemáticas de bits verticales" en el flujo de bits actual en comparación con la copia anterior del flujo de bits.
¡Lo bueno de este enfoque es que puede operar en los vectores de todos los datos de flujo de entrada, un byte a la vez y procesar efectivamente la lógica de rebote y estado actual en ocho teclas a la vez!
He usado este enfoque en varios productos comerciales a lo largo de los años y he podido admitir grandes cantidades de entradas clave sin consumir un alto porcentaje del ancho de banda de procesamiento si la MCU.
Para dar una idea de cómo funciona la matemática binaria vertical, compartiré aquí un código que procesa un vector de señales de entrada. En el ejemplo, las entradas se recopilaron de seis pines procedentes de un puerto. Sin embargo, se puede extender a un vector tan amplio como sea necesario con bytes sucesivos de datos provenientes de sus registros de turnos.
Primero algunas definiciones de un archivo de encabezado. Tenga en cuenta que este esquema de filtro de entrada se diseñó para ser llamado una vez cada 10 ms con cuatro periodos de muestra para proporcionar el debouncing del conmutador en un periodo de 40 ms.
#ifndef _INPUTS_H
#define _INPUTS_H
/* setup the number of input poll samples to filter for stable state */
#define INPUT_POLL_COUNT 4
/* define the states of the INPUT bits in the input status byte */
/* the inputs from port 4 are gathered and shifted right two bits */
#define INP_1 0x01 /* P4.2 - input 1 */
#define INP_2 0x02 /* P4.3 - input 2 */
#define INP_3 0x04 /* P4.4 - input 3 */
#define INP_4 0x08 /* P4.5 - input 4 */
#define INP_5 0x10 /* P4.6 - input 5 */
#define INP_6 0x20 /* P4.7 - input 6 */
#define INP_CNT 6 /* number of logical inputs */
/* global data declarations */
extern unsigned char code inp_table[INP_CNT];
extern unsigned char xdata inp_filter[INPUT_POLL_COUNT];
extern unsigned char xdata inp_status;
extern unsigned char xdata inp_previous;
extern unsigned char xdata inp_true;
extern unsigned char xdata inp_false;
/* input function prototypes */
extern void inp_init(void);
extern void inp_scan(void);
extern unsigned char inp_state(unsigned char inp_bit);
extern void inp_clear(unsigned char inp_bit);
extern unsigned char inp_true_test(unsigned char inp_bit);
extern unsigned char inp_true_get(unsigned char inp_bit);
extern unsigned char inp_false_test(unsigned char inp_bit);
extern unsigned char inp_false_get(unsigned char inp_bit);
#endif /* _INPUTS_H */
Aquí está la definición de datos globales para el escáner de rebote de entrada.
/* array of defined INP acess masks ordered by index number */
unsigned char code inp_table[INP_CNT] = {
INP_1, /* P4.2 - input 1 / power LED */
INP_2, /* P4.3 - input 2 / green stat LED */
INP_3, /* P4.4 - input 3 / amber stat LED */
INP_4, /* P4.5 - input 4 / blue ID LED */
INP_5, /* P4.6 - input 5 / aux in A */
INP_6 /* P4.7 - input 6 / aux in B */
};
/* array of bit flags for inputs filter */
unsigned char xdata inp_filter[INPUT_POLL_COUNT];
unsigned char xdata inp_status; /* current filtered input state */
unsigned char xdata inp_previous; /* previous filtered input state */
unsigned char xdata inp_true; /* saved input true transition */
unsigned char xdata inp_false; /* saved input false transition */
La siguiente es la rutina llamada al inicio para inicializar las matrices de filtros de rebote y los vectores de estado actuales.
/*
**
** routine to initialize the inp scan port logic to the inactive
** state.
**
*/
void inp_init(void)
{
unsigned char i;
for(i=0; i<INPUT_POLL_COUNT; i++)
{
inp_filter[i] = 0;
}
inp_status = 0;
inp_previous = 0;
inp_true = 0;
inp_false = 0;
}
Esta es la rutina a la que se llama una vez cada 10 ms desde una interrupción del temporizador para obtener los datos de entrada actuales y procesarlos a través de los vectores de bits utilizando matemática de bits vertical.
/*
**
** routine to poll the inp lines and filter the current state of inputs
** (note that this is called from the timer interrupt function)
**
*/
void inp_scan(void) using 1
{
unsigned char inp_tmp;
unsigned char inp_or;
unsigned char inp_cur;
unsigned char i;
inp_cur = P4 >> 2; /* read inputs from P4.2 -> P4.7 */
/* loop to shift filter up by one position and perform */
/* bit wise equal comparison */
inp_or = 0; /* this holds 1 for bits that are */
for(i=0; i<INPUT_POLL_COUNT; i++) /* changing in span of filter table */
{
inp_or |= inp_cur ^ inp_filter[i]; /* adjacent pair != so set or */
inp_tmp = inp_filter[i]; /* swap so to slide table up */
inp_filter[i] = inp_cur;
inp_cur = inp_tmp;
}
/* produce bit pattern for current stable input data */
/* if a input goes true its previous false state data is */
/* automatically cleared and as well if a input goes false */
/* its previous true going status is cleared */
/* no chg where toggles */ /* mask present status where stable */
inp_status = (inp_status & inp_or) | (inp_filter[0] & ~inp_or);
inp_tmp = inp_status & (inp_status ^ inp_previous);
inp_true |= inp_tmp;
inp_false &= ~inp_tmp;
inp_tmp = inp_previous & (inp_status ^ inp_previous);
inp_false |= inp_tmp;
inp_true &= ~inp_tmp;
inp_previous = inp_status;
}
Finalmente, aquí hay una colección de subrutinas a las que puede llamar el código de la línea principal para ver cuál es el estado actual de cualquier clave dada.
/*
**
** function to return the current filtered and stable state
** of a specific inp input. returns 0 if the inp is
** inactive and 1 if the input is active. the input argument
** is the bitmask for the requested inp.
**
*/
unsigned char inp_state(unsigned char inp_bit)
{
if(inp_status & inp_bit)
{
return(1);
}
return(0);
}
/*
**
** function to flush the inp input
** true/false status for a bit and make that inp
** look inactive. the input argument
** is the bitmask for the requested inp.
**
*/
void inp_clear(unsigned char inp_bit)
{
inp_true &= ~inp_bit;
inp_false &= ~inp_bit;
}
/*
**
** function to check for specific inp status
** indicating a queued TRUE transition of a inp.
** if so then to return a 1 value, else
** return a 0 value. the input argument
** is the bitmask for the requested inp.
**
*/
unsigned char inp_true_test(unsigned char inp_bit)
{
if(inp_true & inp_bit)
{
return(1);
}
return(0);
}
/*
**
** function to get input status for a inp bit
** indicating a queued TRUE transition of a inp
** and then clear the queued true status. if the inp
** is queued true then return a 1 value, else return
** a 0 value. the input argument is the bitmask
** for the requested inp.
**
*/
unsigned char inp_true_get(unsigned char inp_bit)
{
if(inp_true & inp_bit)
{
inp_true &= ~inp_bit; /* clear the status */
return(1);
}
return(0);
}
/*
**
** function to check for specific input status
** indicating a queued FALSE transition of a
** inp. if so then to return a 1 value, else
** return a 0 value. the input argument is the
** bitmask for the requested inp.
**
*/
unsigned char inp_false_test(unsigned char inp_bit)
{
if(inp_false & inp_bit)
{
return(1);
}
return(0);
}
/*
**
** function to get inp status for a specified bit
** indicating a queued FALSE transition of a inp
** and then clear the queued false status. if the input
** is queued false then this so then to return a 1 value,
** else to return a 0 value. the entry argument is a bit
** number 0-7 to look at.
**
*/
unsigned char inp_false_get(unsigned char inp_bit)
{
if(inp_false & inp_bit)
{
inp_false &= ~inp_bit; /* clear the status */
return(1);
}
return(0);
}