Pulsador antirebote en VHDL (debouncing)

Antirrebote o debouncing de un pulsador

El uso de actuadores mecánicos como los pulsadores, tiene muchas ventajas, sobre todo económicas, ya que son muy baratos. Sin embargo, precisamente por su naturaleza mecánica, vienen acompañados de ciertos problemas que dependiendo del uso que hagamos de ellos, pueden llegar a ser un verdadero quebradero de cabeza. El mayor de estos inconvenientes es el rebote o bouncing.

Al ser accionados, los pulsadores tardan cierto tiempo en alcanzar un estado estable, es decir, que durante muy poco tiempo (del orden de los milisengundos) pueden cambiar entre el estado pulsado y no pulsado hasta que la señal se estabiliza. A pesar de ser muy poco tiempo, es el suficiente para que un sistema digital lo detecte como varias pulsaciones. La siguiente imagen muestra una señal de rebote típica.

Bounce o rebote

Hay varias aproximaciones para solucionar este problema, tanto hardware como software (si estamos trabajando con microcontroladores). En este artículo vamos a ver cómo atajar este problema desde el punto de vista hardware y más concretamente con VHDL.

Obviamente, hablamos de un circuito secuencial que debe recordar si el botón estaba pulsado en un momento anterior y compararlo con el estado actual, así que es necesario el uso de biestables o flip flops. La idea general es que si durante un periodo de tiempo lo suficientemente amplio (unos 10 u 11 milisegundos) el valor actual del pulsador y el valor del flip flop que almacena el estado anterior son iguales, podemos dar por sentado que el pulsador ha llegado a un estado de pulsación estable. El siguiente código VHDL implementa dicho circuito.

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity debouncer_top is
    port (
        clk	: in std_logic;
	btn_in	: in std_logic;
	btn_out	: out std_logic);
end debouncer_top;

architecture beh of debouncer_top is
    constant CNT_SIZE : integer := 19;
    signal btn_prev   : std_logic := '0';
    signal counter    : std_logic_vector(CNT_SIZE downto 0) := (others => '0');

begin
    process(clk)
    begin
	if (clk'event and clk='1') then
		if (btn_prev xor btn_in) = '1' then
			counter <= (others => '0');
			btn_prev <= btn_in;
		elsif (counter(CNT_SIZE) = '0') then
			counter <= counter + 1;
        	else
			btn_out <= btn_prev;
		end if;
	end if;
    end process;
end beh;

 

La señal btn_prev es el biestable encargado de almacenar el estado anterior (entiéndase, el estado en el pulso de reloj anterior). Para contar el tiempo se usa un contador de 20 bits (enseguida veremos por qué de 20 y no de otro tamaño). Dentro del proceso, en cada pulso de reloj se comprueba mediante una puerta xor si el valor del pulsador es diferente al del pulso de reloj previo. Si es así, el contador se pone a cero y vuelve a comenzar la cuenta de tiempo, si no, se incrementa el contador, salvo que su último bit sea 1, en cuyo caso, ha pasado el tiempo suficiente como para dar por hecho que la pulsación ya es estable. Si este es el caso, ponemos el valor del biestable btn_prev en btn_out (que es otro biestable que se conecta a la salida del circuito).

El tamaño del contador se ha ajustado para una frecuencia de reloj de 50 MHz. En general, el tiempo que se consigue según el tamaño del contador se puede aproximar con la siguiente fórmula.

Tamaño del contador

Siendo n el número de bits del contador. Así pues, en este caso tenemos un reloj de 50 MHz y un contador de 20 bits. Como en realidad el contador no va a contar hasta el final sino hasta que su bit más significativo sea 1, podemos usar un valor n=19 como una aproximación más que aceptable.

Tiempo contador

Por lo tanto, estamos dejando un margen de algo más de 10 milisegundos para que se estabilice el pulsador. Un valor muy razonable para un pulsador normal.

 

4 Comentarios en "Pulsador antirebote en VHDL (debouncing)"

  1. No me parece que 10 mS sea un tiempo considerable y suficiente para un pulsador en rebote.
    En mi experiencia, es necesario algo mas de 100mS.

    • Alberto García | en | Responder

      Buenos días Danilo,

      Gracias por tus comentarios. Pienso que, probablemente, 10 ms sea tiempo suficiente para estabilizar la entrada del pulsador (y eso dependerá también del tipo de pulsador, claro). En todo caso, he buscado valores redondos y fácilmente manejables para que se entienda bien, ya que lo que pretendo es que sean artículos didácticos para personas que están aprendiendo (me incluyo). En un producto final el enfoque sería obviamente algo diferente en cuanto a robustez del circuito. De todas formas, con 100ms te aseguras de que no vas a tener problemas 😉

      Muchas gracias y un saludo.

  2. Jhonatan Juño | en | Responder

    Gracias por el aporte, me sirvió perfeca en un cpdl con el cual trabajo, gracias.

  3. Marco Carnaghi | en | Responder

    Muy bueno el aporte. Y la explicación bien clara, lo cual agradezco ya que aoy bastante nuevo en el uso de VHDL

Deja un comentario.

Tu dirección de correo no será publicada.


*