viernes, 10 de junio de 2016

Conversor binario BCD de 8 bits en VHDL

El objetivo es implementar en la FPGA disponible en la  tarjeta Basys 2, Digilent,  y utilizando el software Xilinx ISE, un conversor de Binario a BCD, que al introducir en binario un Byte, por medio de los 8 interruptores disponibles en la tarjeta de desarrollo, se pueda visualizar en tres displays de 7 segmentos de la tarjeta, el respectivo número decimal que corresponda al número binario introducido de 8 bits. Los decimales visualizados en los displays estan comprendidos desde el 000 hasta el 255. 

Se tiene en cuenta el siguiente diagrama esquematico:


Elaboramos el código en VHDL del conversor de Binario a BCD de acuerdo al algoritmo de sumar 3 y desplazar cada 4 bits, para lo cual hacemos uso de una VARIABLE de 20 bits, que llamamos la variable Z, y que debe contener los 8 bits del binario a convertir, y los 12 bits del BCD: 4 bits de las centenas, 4 bits de las decenas y los 4 bits de las unidades.  Cada vez que en BCD se detecte un número mayor de 4 se le suma 3 y se desplaza, lo cual equivale a sumar 6, lo cual es lo requerido para efectuar la conversión de binario a BCD para cada 4 bits.  Inicialmente la variable Z se pone en ceros, y luego desplaza los tres primeros bits, antes de averiguar si el número es mayor de 4, para sumarle tres y desplazarlo en caso que lo sea.

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


entity Conv_Bin_BCD is
    Port ( Bin : in   STD_LOGIC_VECTOR (7 downto 0);
           Cen : out  STD_LOGIC_VECTOR (3 downto 0);
           Dec : out  STD_LOGIC_VECTOR (3 downto 0);
           Uni : out  STD_LOGIC_VECTOR (3 downto 0));
end Conv_Bin_BCD;

architecture Behavioral of Conv_Bin_BCD is

begin

Process(Bin)
variable Z: STD_LOGIC_VECTOR (19 downto 0);
begin

 for i in 0 to 19 loop
 Z(i) := '0';
 end loop;

 Z(10 downto 3) := Bin;


 for i in 0 to 4 loop

    if Z(11 downto 8) > 4 then
Z(11 downto 8) := Z(11 downto 8) + 3;
end if;

if Z(15 downto 12) > 4 then
Z(15 downto 12) := Z(15 downto 12) + 3;
    end if;

Z(17 downto 1) := Z(16 downto 0);
  end  loop;
   

 
  Cen <= Z(19 downto 16);
  Dec <= Z(15 downto 12);
  Uni <= Z(11 downto 8);
end Process;
end Behavioral;

Luego seguimos con un Multiplexor de 3 entradas/ 1 salida , y como selector la salida de un contador ascendente binario del 0 al 2, cuyo reloj tiene una frecuencia de 1 khz, para poder lograr la visualización dinámica para el manejo de los displays de 7 segmentos:

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

entity Mux_31 is
    Port ( C : in  STD_LOGIC_VECTOR (3 downto 0);
           D : in  STD_LOGIC_VECTOR (3 downto 0);
           U : in  STD_LOGIC_VECTOR (3 downto 0);
           Selectores : in  STD_LOGIC_VECTOR (1 downto 0);
           Salidas : out  STD_LOGIC_VECTOR (3 downto 0));
end Mux_31;

architecture Behavioral of Mux_31 is

begin
process (Selectores,C,D,U)
begin
   case Selectores is
      when "00" => Salidas <= C;
      when "01" => Salidas <= D;
      when "10" => Salidas <= U;
      when others => Salidas <= "0000";
   end case;
end process;

end Behavioral;

De acuerdo al esquemático que nos sirve de guía seguimos con el decodificador de BCD a 7 segmentos:

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

entity Dec7seg is
port(  BCD: in  STD_LOGIC_VECTOR (3 downto 0);
       led: out STD_LOGIC_VECTOR(6 downto 0) ); 
 end Dec7seg;
 
architecture comportamiento of Dec7seg is
begin
 process (BCD)
begin
case BCD 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 others => LED <=  "0001100"; --9
end case;
end process ;
end comportamiento;

Continuamos ahora con el Divisor de frecuencia del clock de 50 Mhz a 1 Khz:

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;
 CLK1KHZ <=  pulso;

end Behavioral;


El esquemático nos muestra ahora que seguimos con el contador del 0 al 2:

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

entity Cont_0al2 is
    Port ( Clk : in   STD_LOGIC;
           Q : inout  STD_LOGIC_VECTOR (1 downto 0));
end Cont_0al2;

architecture Behavioral of Cont_0al2 is

begin
process (Clk) 
begin
   if Clk ='1' and Clk'event then
if Q = "11" then Q <= "00";
    else
Q <= Q + 1;
   end if;
  end if;
end process;

end Behavioral;

Finalmente requerimos manejar los ánodos de los displays de 7 segmentos, ánodo común, para lograr el efecto de persistencia de la imágen en la retina requerido para la visualización dinámica:

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_VECTOR(1 downto 0);
           Anodos : out  STD_LOGIC_VECTOR (3 downto 0));
end Anodos_displays;

architecture Behavioral of Anodos_displays is

begin
process(Input)
begin
         case Input is
            when "00" => Anodos <= "0111";
            when "01" => Anodos <= "1011";
            when "10" => Anodos <= "1101";
            when others => Anodos <= "1111";
         end case;
Anodos(0) <= '1';
end process;
   
end Behavioral;

Luego procedemos a elaborar el código del circuito final que utilice los seis componentes descritos anteriormente y que cumpla con las conexiones, señales internas, entradas y salidas, descritas en el esquemático que nos ha servido de guía en el diseño:

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


entity Final is
    Port ( Binario : in  STD_LOGIC_VECTOR (7 downto 0);
           Reloj50mhz : in  STD_LOGIC;
           Catodos : out  STD_LOGIC_VECTOR (6 downto 0);
           Anodos : out  STD_LOGIC_VECTOR (3 downto 0));
end Final;

architecture Behavioral of Final is
Signal XCen, XDec, XUni, XBCD: STD_LOGIC_VECTOR (3 downto 0);
Signal X1khz : STD_LOGIC;
Signal XQ: STD_LOGIC_VECTOR (1 downto 0);

Component Conv_Bin_BCD 
    Port ( Bin : in  STD_LOGIC_VECTOR (7 downto 0);
           Cen : out  STD_LOGIC_VECTOR (3 downto 0);
           Dec : out  STD_LOGIC_VECTOR (3 downto 0);
           Uni : out  STD_LOGIC_VECTOR (3 downto 0));
end Component;

Component Mux_31 
    Port ( C : in  STD_LOGIC_VECTOR (3 downto 0);
           D : in  STD_LOGIC_VECTOR (3 downto 0);
           U : in  STD_LOGIC_VECTOR (3 downto 0);
           Selectores : in  STD_LOGIC_VECTOR (1 downto 0);
           Salidas : out  STD_LOGIC_VECTOR (3 downto 0));
end Component;

Component Dec7seg 
port(  BCD: 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 Cont_0al2 
    Port ( Clk : in   STD_LOGIC;
           Q : inout  STD_LOGIC_VECTOR (1 downto 0));
end Component;

Component Anodos_displays
    Port ( Input : in  STD_LOGIC_VECTOR(1 downto 0);
           Anodos : out  STD_LOGIC_VECTOR (3 downto 0));
end Component;

begin

paso1: Conv_Bin_BCD PORT MAP (Binario, XCen, XDec, XUni);
paso2: Mux_31       PORT MAP (XCen, XDec, XUni, XQ, XBCD );
paso3: Dec7seg      PORT MAP (XBCD, Catodos);
paso4: RELOJ1KHZ    PORT MAP (Reloj50mhz, X1khz);
paso5: Cont_0al2    PORT MAP (X1khz,XQ);
paso6: Anodos_displays PORT MAP (XQ, Anodos);

end Behavioral;


Tenemos que tener el archivo UCF que describa los pines de la FPGA que voy a utilizar como entradas  y salidas:

#PACE: Start of Constraints generated by PACE

#PACE: Start of PACE I/O Pin Assignments
NET "Anodos<0>"   LOC = "F12"  ;
NET "Anodos<1>"   LOC = "J12"  ;
NET "Anodos<2>"   LOC = "M13"  ;
NET "Anodos<3>"   LOC = "K14"  ;
NET "catodos<0>"  LOC = "M12"  ;
NET "catodos<1>"  LOC = "L13"  ;
NET "catodos<2>"  LOC = "P12"  ;
NET "catodos<3>"  LOC = "N11"  ;
NET "catodos<4>"  LOC = "N14"  ;
NET "catodos<5>"  LOC = "H12"  ;
NET "catodos<6>"  LOC = "L14"  ;
NET "Reloj50mhz"  LOC = "B8"   ;
NET "Binario<7>"  LOC = "N3"   ;
NET "Binario<6>"  LOC = "E2"   ;
NET "Binario<5>"  LOC = "F3"   ;
NET "Binario<4>"  LOC = "G3"   ;
NET "Binario<3>"  LOC = "B4"   ;
NET "Binario<2>"  LOC = "K3"   ;
NET "Binario<1>"  LOC = "L3"   ;
NET "Binario<0>"  LOC = "P11"  ;

#PACE: Start of PACE Area Constraints

#PACE: Start of PACE Prohibit Constraints

#PACE: End of Constraints generated by PAC

5 comentarios:

  1. MUY INTERESANTE, YA LO IMPLEMENTE FUE MUY BUENA SU DESCRIPCIÓN APRENDÍ MUCHO DE SU LÓGICA: ¡¡GRACIAS!!!

    ResponderEliminar
  2. Ingeniero le agradezco el apoyo me ah salvado !

    ResponderEliminar
  3. Muchas gracias, fue muy útil su blog. Saludos desde México.

    ResponderEliminar
  4. GRACIAS PROFE CHUCHO, COMO LO AMO AHORA SÍ MI PROFE HILARIO NO ME VOLVERA A HUMILLAR FRENTE A TODOS MIS COMPAÑEROS LA VERDAD DEJA MUCHA TAREA DEBERIAN SACARLO DE MI ESCUELA. SALUDOS DESDE AREQUIPA - PERÚ

    ResponderEliminar