Las 7 filas de la matriz, se conectan a 7 salidas de la FPGA dispuesta en la tarjeta Digilent en sus puertos de expansión. Los cátodos de los leds, en las columnas se manejan a través de un contador de anillo de 5 bits, activo por nivel bajo. Sólo una columna se energiza cada vez, pero al hacer la secuencia del contador de anillo muy rápidamente cada 0,01 segundo, el ojo humano, por la persistencia de la imágen en la retina, ve todas las 5 columnas como si estuvieran todas energizadas, y pareciese que todos los Leds que generan el caracter estuvieran encendidos, pero en realidad sólo se estan encendiendo columnna por columna, de acuerdo al CERO que envía el Contador de Anillo a todos los 7 leds de cada columna y aterrizarlos. Por medio de la FPGA se envían los UNOS para que se enciendan los leds requeridos para que vaya formando el caracter. Por ejemplo, para formar la U, inicialmente la memoria debe enviarle a los leds de la primera columna 1111110, luego 0000001 a la segunda columna al tiempo que se energiza esa columna por el contador de anillo, después eso mismo a la tercera y cuarta columna a medida que el contador de anillo se desplaza, y al final a los 0,05 segundos, cuando se energiza la quinta columna, la más a la derecha, la memoria debe enviar nuevamente 1111110, y esto debe hacerlo repetitivamente unas 20 veces, para que el caracter, en este caso la U se observe durante 1 segundo ( 0,05 * 20 = 1). Luego se continúa en igual forma con los otros dos caracteres, la A y la N, dejando en blanco durante 1 segundo el display, y luego seguir la secuencia desplegando el mensaje UAN blanco, UAN blanco,.. indefinidamente.
Se utilizó una matriz miniatura
En la implementación se utlizan 3 puertos de expansión dispuestas en la tarjeta Digilent Basys 2:
Se pueden observar en el gráfico anterior las resistencias de protección contra corto circuitos a las salidas, lo mismo que Diodos de protección ESD a tierra contra descargas electrostáticas.
Veamos la conexión de pines:
Veamos ahora el programa final en VHDL:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Letrero_UAN is
Port ( CLOCK50MHZ : in STD_LOGIC;
COL : out STD_LOGIC_VECTOR (4 downto 0);
FIL : out STD_LOGIC_VECTOR (6 downto 0));
end Letrero_UAN;
architecture Behavioral of Letrero_UAN is
signal Xclk: STD_LOGIC;
signal Xclk_letras: STD_LOGIC;
signal Xq : STD_LOGIC_VECTOR (2 downto 0);
signal Xcol: STD_LOGIC_VECTOR (4 downto 0);
signal XSL : STD_LOGIC_VECTOR (1 downto 0);
component Divisor
Port ( CLK50Mhz : in STD_LOGIC;
CLK1khz : out STD_LOGIC);
end component;
component Cont
Port ( Clk : in STD_LOGIC;
Q : out STD_LOGIC_VECTOR (2 downto 0));
end component;
component anillo
Port ( Entrada : in STD_LOGIC_VECTOR (2 downto 0);
Salida : out STD_LOGIC_VECTOR (4 downto 0));
end component;
component Memoria
Port ( Selector_letra: in STD_LOGIC_VECTOR (1 downto 0);
Direccion : in STD_LOGIC_VECTOR (4 downto 0);
Datos : out STD_LOGIC_VECTOR (6 downto 0));
end component;
component Cont_letras
Port ( CLK_letras : in STD_LOGIC;
Q : out STD_LOGIC_VECTOR (1 downto 0));
end component;
component Reloj_letras
Port ( CLK50Mhz : in STD_LOGIC;
CLK1hz : out STD_LOGIC);
end component;
begin
paso1: Divisor port map (CLOCK50MHZ, Xclk);
paso2: Cont port map (Xclk, Xq);
paso3: anillo port map (Xq, Xcol);
paso4: Memoria port map (XSL,Xcol, FIL );
paso5: Reloj_letras port map (CLOCK50MHZ, Xclk_letras);
paso6: Cont_letras port map (Xclk_letras, XSL);
COL <= Xcol;
end Behavioral;
El esquemático RTL es el siguiente:
A continuación el código VHDL de cada componente:
-- DIVISOR 1 KHZ
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Divisor is
Port ( CLK50Mhz : in STD_LOGIC;
CLK1khz : out STD_LOGIC);
end Divisor;
architecture Behavioral of Divisor is
signal pulso: STD_LOGIC := '0';
signal contador: integer range 0 to 24999 := 0;
begin
process (CLK50Mhz)
begin
if (CLK50Mhz'event and CLK50Mhz = '1') then
if (contador = 24999) then
pulso <= NOT(pulso);
contador <= 0;
else
contador <= contador+1;
end if;
end if;
end process;
CLK1khz <= pulso;
end Behavioral;
................................................................................................................................................
-- CONTADOR DEL 0 AL 4
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Cont is
Port ( Clk : in STD_LOGIC;
Q : out STD_LOGIC_VECTOR (2 downto 0));
end Cont;
architecture Behavioral of Cont is
signal count: STD_LOGIC_VECTOR (2 downto 0);
begin
process (Clk)
begin
if count = "101" then
count <= "000";
elsif Clk ='1' and Clk'event then
count <= count + 1;
end if;
end process;
Q <= count;
end Behavioral;
................................................................................................................................................
-- CONTADOR DE ANILLO
-
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity anillo is
Port ( Entrada : in STD_LOGIC_VECTOR (2 downto 0);
Salida : out STD_LOGIC_VECTOR (4 downto 0));
end anillo;
architecture Behavioral of anillo is
begin
process(Entrada)
begin
case Entrada is
when "000" => Salida <= "01111";
when "001" => Salida <= "10111";
when "010" => Salida <= "11011";
when "011" => Salida <= "11101";
when "100" => Salida <= "11110";
when others => Salida <= "00000";
end case;
end process;
end Behavioral;
................................................................................................................................................
-- DIVISOR DE 1 HZ
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Reloj_letras is
Port ( CLK50Mhz : in STD_LOGIC;
CLK1hz : out STD_LOGIC);
end Reloj_letras;
architecture Behavioral of Reloj_letras is
signal pulso: STD_LOGIC := '0';
signal contador: integer range 0 to 24999999 := 0;
begin
process (CLK50Mhz)
begin
if (CLK50Mhz'event and CLK50Mhz = '1') then
if (contador = 24999999) then
pulso <= NOT(pulso);
contador <= 0;
else
contador <= contador+1;
end if;
end if;
end process;
CLK1hz <= pulso;
................................................................................................................................................
-- CONTADOR PARA DESPLEGAR LAS LETRAS UAN
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Cont_letras is
Port ( CLK_letras : in STD_LOGIC;
Q : out STD_LOGIC_VECTOR (1 downto 0));
end Cont_letras;
architecture Behavioral of Cont_letras is
signal count: STD_LOGIC_VECTOR (1 downto 0);
begin
process (CLK_letras)
begin
if (CLK_letras = '1' and CLK_letras'event) then
count <= count + 1;
end if;
end process;
Q <= count;
end Behavioral;
................................................................................................................................................
-- MEMORIA CON LAS LETRAS A DESPLEGAR
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Memoria is
Port ( Selector_letra: in STD_LOGIC_VECTOR (1 downto 0);
Direccion : in STD_LOGIC_VECTOR (4 downto 0);
Datos : out STD_LOGIC_VECTOR (6 downto 0));
end Memoria;
architecture Behavioral of Memoria is
begin
process (Selector_letra,Direccion)
begin
if Selector_letra = "00" then
case Direccion is -- Letra U
when "01111" => Datos <= "1111110";
when "10111" => Datos <= "0000001";
when "11011" => Datos <= "0000001";
when "11101" => Datos <= "0000001";
when "11110" => Datos <= "1111110";
when others => Datos <= "0000000";
end case;
elsif Selector_letra = "01" then
case Direccion is -- Letra A
when "01111" => Datos <= "0111111";
when "10111" => Datos <= "1001000";
when "11011" => Datos <= "1001000";
when "11101" => Datos <= "1001000";
when "11110" => Datos <= "0111111";
when others => Datos <= "0000000";
end case;
elsif Selector_letra = "10" then
case Direccion is -- Letra N
when "01111" => Datos <= "0111111";
when "10111" => Datos <= "1000000";
when "11011" => Datos <= "1000000";
when "11101" => Datos <= "1000000";
when "11110" => Datos <= "0111111";
when others => Datos <= "0000000";
end case;
-- end process ;
else
case Direccion is -- Espacio en Blanco
when "01111" => Datos <= "0000000";
when "10111" => Datos <= "0000000";
when "11011" => Datos <= "0000000";
when "11101" => Datos <= "0000000";
when "11110" => Datos <= "0000000";
when others => Datos <= "0000000";
end case;
End if;
end process ;
end Behavioral;
.....................................................................................................................................................
Fotografía: