2008-09-30 22 views
6

¿Tiene a mano una rutina de eliminación del rebote para tratar con una sola entrada de interruptor?Rutina de rebote simple

Este es un sistema simple de metal desnudo sin ningún sistema operativo.

Me gustaría evitar una construcción de bucle con un conteo específico, ya que la velocidad del procesador puede fluctuar.

Respuesta

10

Creo que se podría aprender mucho sobre esto aquí: http://www.ganssle.com/debouncing.pdf

Su mejor apuesta es siempre la de hacer esto en el hardware, si es posible, pero hay algunas ideas sobre el software en allí también.

simple código de ejemplo de TFA:

#define CHECK_MSEC 5 // Read hardware every 5 msec 
#define PRESS_MSEC 10 // Stable time before registering pressed 
#define RELEASE_MSEC 100 // Stable time before registering released 
// This function reads the key state from the hardware. 
extern bool_t RawKeyPressed(); 
// This holds the debounced state of the key. 
bool_t DebouncedKeyPress = false; 
// Service routine called every CHECK_MSEC to 
// debounce both edges 
void DebounceSwitch1(bool_t *Key_changed, bool_t *Key_pressed) 
{ 
    static uint8_t Count = RELEASE_MSEC/CHECK_MSEC; 
    bool_t RawState; 
    *Key_changed = false; 
    *Key_pressed = DebouncedKeyPress; 
    RawState = RawKeyPressed(); 
    if (RawState == DebouncedKeyPress) { 
     // Set the timer which allows a change from current state. 
     if (DebouncedKeyPress) Count = RELEASE_MSEC/CHECK_MSEC; 
     else Count = PRESS_MSEC/CHECK_MSEC; 
    } else { 
     // Key has changed - wait for new state to become stable. 
     if (--Count == 0) { 
      // Timer expired - accept the change. 
      DebouncedKeyPress = RawState; 
      *Key_changed=true; 
      *Key_pressed=DebouncedKeyPress; 
      // And reset the timer. 
      if (DebouncedKeyPress) Count = RELEASE_MSEC/CHECK_MSEC; 
      else Count = PRESS_MSEC/CHECK_MSEC; 
     } 
    } 

}

+0

encontraron realidad, unos 10 minutos después de hacer la pregunta. Muy útil. Estoy de acuerdo con la solución de HW ... si solo ... – Benoit

+0

@Benoit: ¡Bien, marqueme la respuesta! ;) – GEOCHET

1

Para rebotar, desea ignorar cualquier cambio que dure menos de un cierto umbral. Puede configurar un temporizador de hardware en el cambio, o usar un indicador establecido mediante interrupción periódica.

1

Si puede salirse con la suya, la mejor solución en hardware es tener el interruptor tiene dos estados distintos con ningún estado intermedio. Es decir, use un interruptor SPDT, con cada polo alimentando las líneas R o S de un flip/flop. Con cableado de esa manera, la salida del flip/flop debe ser eliminada.

+0

Estoy de acuerdo en que HW sería mejor, pero eso no está en los dados. – Benoit

+0

Si se trata de algo que una persona está cambiando, casi siempre es necesario reblandecerlo, incluso si hay rebote de hardware. Las manos de las personas tiemblan, no usan demasiada o demasiada fuerza en el botón, o la mierda ha llegado al botón; pueden * mecánicamente * crear rebote de esa manera, lo que su SPDT informará fielmente. El antirrebote de hardware es excelente, sin embargo, y si nada más, le permite mantener su tiempo de rebote mucho más pequeño y obtener un teclado más receptivo. –

2

No existe una única solución simple que funcione para todo tipo de botones. No importa lo que alguien aquí te diga que uses, tendrás que probarlo con tu hardware y ver qué tan bien funciona. Y mira las señales en un alcance, para asegurarte de que realmente sabes lo que está pasando. El enlace de Rich B con el pdf parece un buen lugar para comenzar.

9

Las soluciones más sencillas suelen ser las mejores, y he descubierto que simplemente leer el estado del interruptor cada milisegundos (entre 10 y 50, dependiendo de los interruptores) siempre me ha funcionado.

He eliminado las rutinas de rebote rotas y complejas y las reemplacé con una simple encuesta lenta, y los resultados siempre han sido lo suficientemente buenos de esa manera.

Para implementarlo, necesitará una interrupción de temporizador periódica simple en su sistema (suponiendo que no se admite RTOS), pero si está acostumbrado a programarlo en el metal desnudo, eso no debería ser difícil de organizar.

Tenga en cuenta que este enfoque simple agrega un retraso a la detección del cambio de estado. Si un interruptor toma T ms para alcanzar un nuevo estado estable, y es sondeado cada X ms, entonces el peor retraso de caso para detectar la prensa es T + X ms. Su intervalo de sondeo X debe ser ser más grande que el tiempo de rebote en el peor de los casos T.

+0

Estoy de acuerdo en que un período estable funciona perfectamente bien. A menudo utilizo mi ciclo de actualización de pantalla para eliminar el rebote "desde que estoy allí" y eso funciona bien. Aquí falta la "lógica antirrebotes", a menos que siempre active un cambio de estado, que simplemente no funcionará todo el tiempo. –

+3

@Tom, todo el punto está ahí * es * no hay lógica antirrebote: no lo necesita. El "rebote" del interruptor es realmente solo un artefacto causado al muestrear un clúster de contacto mecánico más rápido de lo que fue diseñado para operar. Al disminuir la frecuencia de muestreo, evitas el problema. (y sí, la frecuencia de actualización del video es perfecta para la mayoría de los buenos interruptores) – Roddy

+0

Muy interesante, no lo había pensado así. Después de algunos garabatos, creo que es probablemente correcto SI el período de votación es entre dos veces el ciclo de antirrebote más largo de su hardware y la mitad de la duración del botón más corto que aceptará, siempre y cuando esté dispuesto a aceptar un retraso de (ocasionalmente) hasta dos ciclos completos de votación. (Para una frecuencia de actualización de la pantalla de 60 Hz, eso implica un ciclo de rebote de <9 ms, por ejemplo).) Debo haber sido gruñón, te marqué, y aparentemente no puedo cambiar esto. :-(Si cambia ligeramente su respuesta, puedo volver a marcarla –

2

He utilizado un método de voto mayoritario para evitar una entrada. Configuré un tipo simple de estructura de datos de registro de desplazamiento de tres estados, y cambié cada muestra y tomé los mejores dos de tres como el valor "correcto". Obviamente, esto es una función del controlador de interrupciones o de un sondeo, según el método utilizado para leer el hardware.

Pero, el mejor consejo es pedirle a su amigable diseñador de hardware que "bloquee" el valor y le permita borrar este valor cuando lo encuentre.

+0

Eso no me parece correcto. Sin duda, el orden en que ingresan es importante? Por ejemplo, si su registro de turno dice Up Down Up, seguramente estás "en medio de un rebote" y necesitas esperar un período más? –

0

Lo que suelo hacer es tener tres o más variables del ancho del registro de entrada. Cada encuesta, generalmente a partir de una interrupción, cambia los valores hacia arriba para dar paso a la nueva muestra.Luego tengo una variable antirrebote formada al establecer la lógica -y de las muestras, y borrar la inversa lógica- o. es decir, (no probado, de memoria)

input3 = input2; 
input2 = input1; 
input1 = (*PORTA); 

debounced |= input1 & input2 & input3; 
debounced &= (input1 | input2 | input3); 

Aquí está un ejemplo:

protección antirrebote tiene xxxx (donde 'x' es "lo que")

input1 = 0110, 
input2 = 1100, 
input3 = 0100 

Con la información anterior,

Necesitamos cambiar solo el bit 2 a 1, y el bit 0 a 0. El resto todavía están "rebotando".

debounced |= (0100); //set only bit 2 
debounced &= (1110); //clear only bit 0 

El resultado es que ahora antirrebote = x1x0

+0

Encontré tu algoritmo interesante (cerca de lo que estoy buscando). Lo edité para eliminar la negación '~ ', que creo que fue incorrecto – JACH

0

gurú Embedded Jack Ganssle ha dado a esto una gran cantidad de pensamiento. Su PDF de 26 páginas sobre el tema (A Guide to Debouncing) es lo mejor que he leído sobre este tema.

0

El algoritmo de ganssle.com podría tener un error en él. Tengo la impresión de la siguiente línea

static uint8_t Count = RELEASE_MSEC/CHECK_MSEC; 

debe leer

static uint8_t Count = PRESS_MSEC/CHECK_MSEC; 

con el fin de eliminar el rebote correctamente la prensa inicial.

0

a nivel de hardware de la rutina básica de eliminación de rebotes ha de tener en cuenta los siguientes segmentos del (o de interruptor) el comportamiento de una llave física:

clave sentados quietly-> dedo toca la tecla y comienza a empujar Down-> alcances clave la parte inferior del recorrido y el dedo lo sostiene allí-> el dedo comienza a soltar la tecla y el resorte empuja la tecla hacia atrás-> el dedo suelta la tecla y la tecla vibra un poco hasta que se detiene

Todas estas etapas involucran 2 piezas de metal raspado y frotado chocando entre sí, moviendo la tensión hacia arriba y hacia abajo de 0 a máximo durante períodos de milisegundos, por lo que hay ruido eléctrico en cada paso del camino:

(1) Ruido cuando no se toca la tecla, causada por problemas ambientales como humedad, vibración, cambios de temperatura, etc.causando cambios de voltaje en los contactos clave

(2) el ruido causado que la tecla está siendo presionada hacia abajo

(3) de ruido como la tecla está siendo presionada

(4) de ruido como la clave es de ser liberado

(5) el ruido como las claves vibra después de ser liberado

Aquí está el algoritmo por el cual, básicamente, suponemos que la clave está siendo presionado por una persona:

lee el estado de la tecla, que puede ser "presionada", "definitivamente está presionada", "definitivamente no está presionada", "podría no presionarse" (nunca estamos seguros)

loop mientras que la tecla "podría ser" presionada (si se trata de hardware, esta es una muestra de voltaje mayor que algún valor de umbral), hasta que "definitivamente no" esté presionada (menor que el voltaje de umbral) (esto es inicialización, esperando ruido a inmovilización, la definición de "podría ser" y "definitivamente no" depende de la aplicación específica)

bucle while clave es "definitivamente no" presionado, hasta que la tecla "podría ser" presionado

cuando se presiona la tecla "might", comience a repetir y muestrear el estado de la tecla, y lleve un registro de cuánto tiempo se "presionó" la tecla - si la tecla vuelve a "might not be" o "definitely is not" "estado comprimido antes de una cierta cantidad de tiempo, reinicie el procedimiento - en un momento determinado (en número de milisegundos) que haya elegido (generalmente mediante la experimentación con diferentes valores) usted decide que el valor de la muestra ya no es causado por el ruido, sino es muy probable que sea causado por la clave realmente está sujetado por un dedo humano y que devuelva el valor "presionado"


while(keyvalue = maybepressed){ 
//loop - wait for transition to notpressed 
sample keyvalue here; 
maybe require it to be "notpressed" a number of times before you assume 
it's really notpressed; 
} 
while(keyvalue = notpressed){ 
//loop - wait for transition to maybepressed 
sample keyvalue 
again, maybe require a "maybepressed" value a number of times before you 
transition 
} 
while(keyvalue=maybepressed){ 
    presstime+=1; 
    if presstime>required_presstime return pressed_affirmative 
    } 
} 
return pressed_negative 
Cuestiones relacionadas