Para explicar bien intentaré esc ribir como hablaría para dar lo que hace e ste 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; IEEE.NUMERIC_STD.ALL; 2.
La entidad. ¿Qué es esta sección? secci ón? Donde se escriben los puertos de entrada y salida del “circuito”. En este caso necesito como entradas e l reloj (porque es un circuito sec uencial), 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 t ransistores que dicen si un display se enciende o no). entity TOP is PORT( clk, rst, btn : in std_logic; std_logic; -- un 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) – 0) – 8 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 cre ar 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, pr esione, HOLD para cuando el botón haya sido presionado y esperemos a que se suelte y DELAY para esperar espe rar 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; 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 s ubida 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 e s mantener a la tarjeta como en modo de escucha con otro c ase 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 e s 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 e n 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 e n 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 e stá 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 se parado. 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;