sábado, 21 de mayo de 2016

Visualización de Fecha en displays de 7 segmentos: año,mes,dia.

Ejercicio para subir nota, para presentar en clase el miercoles 25 de mayo:

 Elaborar un programa en VHDL  que permita visualizar en los 4 displays de 7 segmentos, disponibles en la tarjeta Basys 2 Digilent,  el año, el mes y el dia. Si un boton pulsador no se acciona debe aparecer el año: 2016, y se acciona el pulsador debe visualizarse  en los dos primeros displays  el mes: 05, y en los dos ultimos displays el dia:25.


Ayudas:

1. Se sugiere analizar el siguiente esquemático:


2. Sintetizar el código para cada uno de los seis componentes.
3. Elaborar el programa final utilizando los componentes y señales indicados.

martes, 17 de mayo de 2016

Contador del 0 al 99 con VHDL en FPGA de la tarjeta Basys 2

Comenzamos el diseño en nuestro proyecto que hemos llamado contador_BCD, creando una nueva fuente  Contador  con el codigo en VHDL de un contador BCD de 2 dígitos: decenas y unidades, el cual dispone de una entrada de reloj de 1 Hz, y de entradas adicionales sincrónicas  de Clear y Enable, para poderlo reiniciar e inhabilitar cuando se requiera.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Contador is
    Port ( clock : in  STD_LOGIC;
           Clear, Enable : in  STD_LOGIC;
           Dec,Uni : inout  STD_LOGIC_VECTOR (3 DOWNTO 0));
end Contador;

architecture Behavioral of Contador is
begin
  PROCESS(clock)
  begin
   if clock'event and clock = '1' then
  if Clear = '1' then
   Dec <= "0000"; Uni <= "0000";
elsif Enable = '1' then
   if Uni = "1001" then 
      Uni <= "0000";
if Dec = "1001" then
   Dec <= "0000";
else
                Dec <= Dec + '1';
             end if;
else
          Uni <= Uni + '1';
end if;  
end if;
     end if;
  end PROCESS;  
 end  Behavioral;

Las decenas y unidades en BCD del contador  se declaran en la entidad como inout (entrada/salida) y son vectores de 4 bits.

En el proceso se considera que en el flanco de subida del reloj, si la entrada Clear es de nivel alto, las decenas y unidades del contador se hacen igual a cero.  

Luego se observa en el código que para que el contador trabaje se requiere que la entrada de habilitación Enable esté en nivel alto, estando la entrada Clear en nivel bajo.

Para comprender la esencia del código es importante analizar el siguiente diagrama de flujo:

Al llegar el flanco de subida del reloj de 1 Hz, si el Clear = 0, y el Enable = 1,  las unidades del contador se incrementan cada segundo, y al llegar al 9, (1001) en binario, las unidades se resetean y las decenas se incrementan. Esta situación hace que el contador pase del 09 al 10, y así sucesivamente, luego pase del 19 al 20, etc. Al llegar al 99 pasará al 00. 

Este código debe salvarse y sintetizarse para ser utilizado luego como componente del programa final que busca visualizar en dos de los  displays de 7 segmentos disponibles en la tarjeta Basys 2 el conteo de decenas y unidades desde el 00 al 99.

Requerimos además adicionar una fuente con el código del divisor que convierte el reloj de cristal  de 50 Mhz disponible en la tarjeta Basys 2 a la frecuencia de 1 Hz requerido para que el conteo de las unidades se haga cada segundo:

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;
           CLK1hz   : out STD_LOGIC);
end Divisor;

architecture Behavioral of Divisor 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;
end Behavioral;

Este código deberá guardarse y sintetizarse, asignandole módulo de nivel superior Set as Top Module para poderlo hacer.

Como ya se ha estudiado anteriormente en este código se produce un pulso de 1 segundo de periodo de reloj,  por cada cincuenta millones de pulsos del cristal de 50 Mhz. 

Se requiere ahora como un tercer componente utilizar un multiplexor de 2 a 1, que permita seleccionar las decenas o las unidades para enviarlas a sus displays respectivos:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Mux21 is
    Port ( Decenas  : in  STD_LOGIC_VECTOR (3 downto 0);
           Unidades : in  STD_LOGIC_VECTOR (3 downto 0);
   Selector : in  STD_LOGIC;
           Salidas  : out  STD_LOGIC_VECTOR (3 downto 0));
end Mux21;

architecture Behavioral of Mux21 is

begin

 Salidas <= Decenas WHEN Selector = '0' ELSE 
           Unidades ; 

end Behavioral;

Este código que debe haberse guardado y sintetizado, permite con el Selector = 0,  que las Decenas del contador pasen a las Salidas, y con Selector = 1 lo hagan las unidades.

Se requiere ahora como cuarto componente sintetizar el decodificador que convierta el binario disponible en las decenas y unidades a lo exigido en los leds del display de 7 segmentos, ánodo común, para visualizar los dígitos desde el 0 hasta el 9.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Dec7segm_hex is
port(  BINARIO: in  STD_LOGIC_VECTOR (3 downto 0);
       led: out STD_LOGIC_VECTOR(6 downto 0) ); 
 end Dec7segm_hex;

architecture comportamiento of Dec7segm_hex is
begin
 process (BINARIO)
begin
case BINARIO is
  when "0000" => LED <=  "0000001"; --0
  when "0001" => LED <=  "1001111"; --1
  when "0010" => LED <=  "0010010"; --2
  when "0011" => LED <=  "0000110"; --3
  when "0100" => LED <=  "1001100"; --4 
  when "0101" => LED <=  "0100100"; --5
  when "0110" => LED <=  "0100000"; --6
  when "0111" => LED <=  "0001111"; --7
  when "1000" => LED <=  "0000000"; --8
  when "1001" => LED <=  "0001100"; --9
  when "1010" => LED <=  "0001000"; --A
  when "1011" => LED <=  "1100000"; --b  
  when "1100" => LED <=  "0110001"; --C   
  when "1101" => LED <=  "1000010"; --d    
  when "1110" => LED <=  "0110000"; --E 
  when others => LED <=  "0111000"; --F
end case;
end process ;
end comportamiento;

Aunque sólo se requiere visualizar los números del 0 al 9, adicionamos una fuente que ya se tenía, con el código dea un decodificador de 7 segmentos para el hexadecimal.

Un quinto componente indispensable para lograr la visualización dinámica que permita ver encendido los dos displays mostrando las decenas y unidades del contador es un RELOJ de 1 KHZ, que produce un periodo de 1 milisegundo. Como la persistencia de la imágen en la retina del ojo humano es de una décima de segundo, este tiempo que es cien veces mas pequeño, nos hará ver encendido el display que en la realidad está apagado.

Este periodo de 1 ms será entonces el Selector del Multiplexor de 2 a 1. 

Se utiliza como reloj de 1 Khz  un código análogo al del Divisor, sólo que en lugar de dividir por 50 millones, lo hace ahora por 50 mil.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity RELOJ1KHZ is
    Port ( CLK50MHZ : in  STD_LOGIC;
           CLK1KHZ : out  STD_LOGIC);
end RELOJ1KHZ;

architecture Behavioral of RELOJ1KHZ 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;

Al igual que el Multiplexor 2 a 1 debe trabajar a una frecuencia de 1 KHZ, así mismo lo deben  hacer los ánodos que son los que habilitan a traves de transistores PNP a los displays de 7 segmentos.

Esto hace que se requiera un sexto componente,  los Anodos de los displays, para que sincronizadamente con el multiplexor tambien esten cambiando cada milésima de segundo.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity Anodos_displays is
port( input: in std_logic;
      anodo: out std_logic_vector(3 downto 0));
end Anodos_displays;

architecture Behavioral of Anodos_displays is

begin
process(input)
begin
          case input is
            when '0' => anodo <= "0111";
            when others => anodo <= "1011";
           
         end case;
   
end process;

end Behavioral;

Recuerde que para que el transistor PNP se sature y por consiguiente permita que le llegue la alimentación de 3.3 voltios al ánodo de led del display debe existir un cero lógico entre base y colector del transistor. Con el 1 lógico, el display está desactivado, al estar desconectado el ánodo del display al voltaje de alimentación.

Procedemos despues de haber sintetizado los seis componentes a elaborar el código del circuito Final que obedezca el siguiente esquemático:


En este circuito final en la entidad se deben declarar como entradas el Reloj de 50 Mhz, el Clear y el Enable, y como salidas los cátodos de los displays de 7 segmentos, y los Änodos de los mismos.

Así mismo se utilizan como señales internas para interconectar los seis componentes:  X1hz, XDec, XUni, X1khz, y  XBin.

El código Final es el siguiente:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity final is
    Port ( Reloj50mhz, Clear,Enable : in  STD_LOGIC;
           Anodos : out  STD_LOGIC_VECTOR (3 downto 0);
           catodos : out  STD_LOGIC_VECTOR (6 downto 0));
end final;

architecture Behavioral of final is
signal X1hz,X1khz: std_logic;
signal XDec: STD_LOGIC_VECTOR (3 downto 0);
signal XUni: STD_LOGIC_VECTOR (3 downto 0);
signal XBin: STD_LOGIC_VECTOR (3 downto 0);

component Divisor 
    Port ( CLK50Mhz : in  STD_LOGIC;
           CLK1hz   : out STD_LOGIC);
end component;

component Contador 
    Port ( clock : in  STD_LOGIC;
           Clear, Enable : in  STD_LOGIC;
           Dec,Uni : inout  STD_LOGIC_VECTOR (3 DOWNTO 0));
end component;

component Mux21 
    Port ( Decenas  : in  STD_LOGIC_VECTOR (3 downto 0);
           Unidades : in  STD_LOGIC_VECTOR (3 downto 0);
 Selector : in  STD_LOGIC;
           Salidas  : out  STD_LOGIC_VECTOR (3 downto 0));
end component;

component Dec7segm_hex 
port(  BINARIO: in  STD_LOGIC_VECTOR (3 downto 0);
       led: out STD_LOGIC_VECTOR(6 downto 0) ); 
end component;

component RELOJ1KHZ 
    Port ( CLK50MHZ : in  STD_LOGIC;
           CLK1KHZ : out  STD_LOGIC);
end component;

component Anodos_displays 
port( input: in std_logic;
      anodo: out std_logic_vector(3 downto 0));
end component;

begin
paso1: Divisor         PORT MAP (Reloj50mhz, X1hz);
paso2: Contador        PORT MAP (X1hz,Clear,Enable,XDec,XUni);
paso3: Mux21           PORT MAP (XDec,XUni,X1khz,XBin);
paso4: Dec7segm_hex    PORT MAP (XBin,catodos);
paso5: RELOJ1KHZ       PORT MAP (Reloj50mhz, X1khz);
paso6: Anodos_displays PORT MAP (X1khz,Anodos);
end Behavioral;

Al salvar y sintetizar este código, se observa que este programa fin integra los seis componentes en seis pasos:


Para crear el archivo final.ucf hay que asignar pines como User Constrains (Restricciones de Usuario)

Al editar como texto este archivo de asignacion de pines se obtiene:


Lo que sigue es implementar el diseño, generar el archivo de programación, y una vez encendida la tarjeta Basys 2 configurarla debidamente:

Al efectuar la implementación del diseño aparece una advertencia respecto a lo demasiado angosto del pulso de 1 Hz, lo cual no es inconveniente para nuestro caso.

Luego se llama al ADEPT para la programación de la FPGA con el archivo final.bit.

Se debe verificar el excelente desempeño de la tarjeta al visualizarse en los displays el conteo desde el 00 al 99. 

martes, 10 de mayo de 2016

Contador binario ascendente síncrono con flip-flops T en esquemático

En el contador síncrono todas las entradas de reloj de los flip flops T se encuentran unidas entre sí. De esta forma se evita que  por retardos en cascada  de los flip-flops que el contador cuente en forma errada como lo hace el contador asíncrono.

Mediante tabla de estados y de excitación del flip flop T  se llega al siguiente esquemático utilizando el flip flop T con clear,  FTC, disponible en el Xilinx ISE:



Se sintetiza este archivo.sch  y se crea su símbolo esquemático.

Se crea nueva fuente en modulo VHD y se sintetiza el divisor que convierte los 50 Mhz a 1 Hz:

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;
           CLK1hz   : BUFFER STD_LOGIC);
end Divisor;

architecture Behavioral of Divisor 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;
end Behavioral;

Este archivo se sintetiza y luego se crea su símbolo esquemático.

Luego se crea un nuevo archivo esquemático, adicionando al contador el divisor:
Queda listo para implementarlo asignando pines y hacerlo trabajar con la FPGA en la Basys 2.