Está en la página 1de 5

Para explicar bien intentaré escribir como hablaría para dar lo que hace este código.

Iremos paso por paso para que no quede nada sin cubrir.

1. Las librerías necesarias


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.NUMERIC_STD.ALL;

2. La entidad. ¿Qué es esta sección? Donde se escriben los puertos de entrada y salida del “circuito”. En
este caso necesito como entradas el reloj (porque es un circuito secuencial), el reset, un botón que al
presionarlo va a aumentar el contador. Y como salidas están los displays (7 segmentos cada uno y el
punto) y sus habilitadores (si no comprenden bien qué son, no se hagan muchas bolas porque no lo
necesitan ahorita pero simplemente son la base de transistores que dicen si un display se enciende o
no).
entity TOP is
PORT(
clk, rst, btn : in std_logic; -- un bit cada uno
e : out std_logic_vector(2 downto 0); -- 3 bits porque hay tres habilitadores
seg : out std_logic_vector(7 downto 0) – 8 bits
);
end TOP;

3. Empieza la arquitectura
architecture Behavioral of TOP is

4. Cuando creamos las memorias donde guardan valores de las señales que están replicando dijimos que
una ventaja de vhdl es que podemos crear tipos de variables, como ya existen el entero (números +, - y
0), natural (+ y 0), stdl_logic (1, 0, h, l, u, x, z, w, -) y otros. En este caso entonces queremos crear un tipo
de máquina de estado y lo llamaremos FSM por finite state machine, que va a tener la característica de
ser ESPERA para cuando, valga la redundancia, estemos esperando a que el botón se presione, HOLD
para cuando el botón haya sido presionado y esperemos a que se suelte y DELAY para esperar una
fracción de tiempo antes de volver al inicio. Así, puedo tener una variable que se llame a, papa, taza,
actual, State (o como yo quiera) que será del tipo FSM.

type FSM is (ESPERA, HOLD, DELAY);


signal State : FSM;

5. Declaro contadores
signal cnt : natural range 0 to 9; -- contador para sacar en displays
signal cnt_del : natural range 0 to 1200000; -- contador para delay
begin

6. Hay que considerar ahora que el objetivo de una máquina de estados para evitar rebotes es que no se
den lecturas erróneas del valor de botón porque cualquier roce, falso contacto o fallo de hardware
puede hacer que se reciba un 1 cuando realmente no se presionó el botón o que se reciban veinte 1s
seguidos y entonces veríamos el contador ir a loco entre números porque cambia muy rápido cuando
sólo presionamos una vez.
Entonces la magia está en decir que sólo vamos a permitir al fpga recibir un 1 cuando hayamos
asegurado que ese es su estado y de igual forma el 0, en caso de estar usando lógica negada.
Así va lo siguiente:
Inicio un proceso porque es un circuito sincronizado y este va a depender en mi caso del reloj de la
tarjeta pero puede depender de la frecuencia que ustedes necesitan. También depende del reset
asíncrono y le especifico que cuando el botón rst se presione, reinicie el contador.

process(clk, rst)
begin
if(rst='0')then
cnt<=0;

7. Ahora, la máquina de estados depende de los flancos de subida del reloj que le puse.
elsif(rising_edge(clk))then
-- conteo sin rebote

8. Y la sintaxis de una FSM siempre va a estar dada por un case. Este case va a ser la lectura del valor que
tenga la señal que creé al inicio de la arquitectura y los valores que puede tomar son los estados que le
asigné a la máquina.
case State is

9. El primer estado lo que hace es mantener a la tarjeta como en modo de escucha con otro case que
depende del botón. Su comportamiento resulta ser que mientras el botón no se presione, vamos a
seguir esperando y cuando sí se haya presionado entonces hacemos algo.
when ESPERA =>

10. Entonces este case está dentro del estado ESPERA y dice “si estoy en espera y el botón es 0, significa que
se presionó y lo que interesa en este caso es sumar 1 al contador y pasar al siguiente estado (HOLD). Si,
por otro lado, estoy en espera y el botón es 1, significa que no ha sido presionado y lo que debo hacer es
seguir esperando” lo último está contemplado en el when others.
Realmente para su proyecto, aquí es donde les interesaría poner la acción de replicar la señal sólo que
de esta forma se evitan precisamente que por un mal contacto de las teclas, el valor vaya de 0 a 1
cuando no quieren. La diferencia está realmente en quizás no pondrían sólo un case para btn, sino para
sw.
case btn is
when '0' => State<=HOLD;
case cnt is
when 9 => cnt<=0;
when others => cnt<=cnt+1;
end case;
when others => State<=ESPERA;
end case;

11. Digamos que sí presioné el botón y la sección anterior hizo entonces que State<=HOLD, esto hace que
entremos a la siguiente opción del case principal.
when HOLD =>
12. Aquí también tengo entonces un case anidado que depende del botón porque presioné el botón pero
digamos que todo es tan rápido dentro del fpga que realmente no lo he soltado. La valuación dice “Si el
botón sigue presionado, estoy en HOLD. Si estoy en hold y el botón es 1, significa que lo soltaron…
entonces puedo hacer algo y pasar al siguiente estado que es DELAY. Si, por otro lado, estoy en hold y el
botón es 0 es que siguen presionándolo y como interesa sólo realizar una vez por cada vez que se
presiona, entonces debo seguir esperando a que lo suelten” igualmente la segunda opción la ven en el
when others.
case btn is
when '1' => State<=DELAY;
when others => State<=HOLD;
end case;

13. Y por ultimo tenemos el estado DELAY, que está contemplado también en un when others porque es la
única otra opción que puede darse como valor de la máquina de estados. Algunas veces sí se incluye
este entre los casos y se agrega un último estado que haga un reset de variables si es que se usan
“frescas” pero eso ya depende del diseño. Esta parte únicamente lo que hace es contar una fracción de
segundo y al terminar, vuelve al estado ESPERA.
when others =>
if(cnt_del=1200000)then
cnt_del<=0;
State<=ESPERA;
else
cnt_del<=cnt_del+1;
end if;
end case;

14. Este ultimo pedazo únicamente lo que hace es poner el número del contador en el display.
-- escritura en displays
case cnt is
when 0 => seg<=x"03";
when 1 => seg<=x"9F";
when 2 => seg<=x"25";
when 3 => seg<=x"0D";
when 4 => seg<=x"99";
when 5 => seg<=x"49";
when 6 => seg<=x"41";
when 7 => seg<=x"1F";
when 8 => seg<=x"01";
when 9 => seg<=x"09";
when others => seg<=x"FD";
end case;
end if;
end process;

e<=o"6";

end Behavioral;
Aquí está el código complete por si no se entiende bien por separado.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.NUMERIC_STD.ALL;

entity TOP is
PORT(
clk, rst, btn : in std_logic;
e : out std_logic_vector(2 downto 0);
seg : out std_logic_vector(7 downto 0)
);
end TOP;

architecture Behavioral of TOP is


type FSM is (ESPERA, HOLD, DELAY);
signal State : FSM;
signal cnt : natural range 0 to 9;
signal cnt_del : natural range 0 to 1200000;
begin

process(clk, rst)
begin
if(rst='0')then
cnt<=0;
elsif(rising_edge(clk))then
-- conteo sin rebote
case State is
when ESPERA =>
case btn is
when '0' => State<=HOLD;
case cnt is
when 9 => cnt<=0;
when others => cnt<=cnt+1;
end case;
when others => State<=ESPERA;
end case;
when HOLD =>
case btn is
when '1' => State<=DELAY;
when others => State<=HOLD;
end case;
when others =>
if(cnt_del=1200000)then
cnt_del<=0;
State<=ESPERA;
else
cnt_del<=cnt_del+1;
end if;
end case;

-- escritura en displays
case cnt is
when 0 => seg<=x"03";
when 1 => seg<=x"9F";
when 2 => seg<=x"25";
when 3 => seg<=x"0D";
when 4 => seg<=x"99";
when 5 => seg<=x"49";
when 6 => seg<=x"41";
when 7 => seg<=x"1F";
when 8 => seg<=x"01";
when 9 => seg<=x"09";
when others => seg<=x"FD";
end case;
end if;
end process;

e<=o"6";

end Behavioral;

También podría gustarte