Módulos

Multiplexores y visualizadores de siete segmentos

Figura 2: Diagrama electrónico de los visualizadores.

En siete segmentos y VHDL se desarrolló un componente para mostrar dígitos en un visualizador de siete segmentos, mismo que se mostraba en los cuatro visualizadores de la tarjeta Basys 2. En esta pequeña entrada se hace uso de un multiplexor para mostrar un dígito distinto en cada uno de los visualizadores.

[wpdm_file id=5] [wpdm_file id=6]

Multiplexor

Como se menciona en (Tocci, 1993), un multiplexor o selector de datos es un circuito lógico que acepta varias entradas y solamente permite a una de ellas alcanzar la salida. La figura 1 muestra el diagrama de un multiplexor, donde se observa que la salida Z puede tomar el valor de A o B, pero no de ambos a la vez, en base al valor del parámetro de selección S0. Un claro ejemplo de un multiplexor se encuentra en la televisión, donde solamente se muestra en pantalla el canal de deportes o el canal de música, pero no ambos a la vez (al menos hasta hace unos años, claro está).

Figura 1: Diagrama de multiplexor.

Figura 1: Diagrama de multiplexor.

Desde el punto de vista de programación, equivale a una simple estructura if - else, donde una variable puede tomar o uno u otro valor. Habiendo dicho esto, es claro que un multiplexor puede verse como una instrucción switch al incrementar la cantidad de valores posibles.

¿Qué tiene que ver un multiplexor con los visualizadores? Primeramente, observemos el diagrama electrónico de los visualizadores en la tarjeta Basys2 (figura 2). En base a la figura, podemos deducir que solamente existen 8 señales para mostrar los dígitos (no 32 como se esperaba) y las señales AN0 a AN3 son las encargadas de decidir cuales de los cuatro visualizadores están activo.

Figura 2: Diagrama electrónico de los visualizadores.

Figura 2: Diagrama electrónico de los visualizadores.

Ahora, ¿cómo mostrar un dígito diferente en los cuatro visualizadores a la vez? La verdad es que solamente se puede mostrar un dígito diferente a la vez, pero si utilizamos la frecuencia correcta, se llega a la ilusión de que hay cuatro dígitos distintos. Este efecto es similar a un video, el cual es compuesto de muchas imágenes sucesivas. Una frecuencia de 200Hz es más que suficiente para generar este efecto, por lo cual se utiliza el divisor creado en divisor de frecuencia con VHDL.

Descripción mediante VHDL

Dado que ya contamos con el divisor de frecuencia y nuestro componente para mostrar un dígito, solamente falta crear un componente para determinar cual de los cuatro dígitos deseamos mostrar, en otras palabras, crear un multiplexor.

----------------------------------------------------------------------------------
-- Compañía:            Estado Finito
-- Ingeniero:           Carlos Ramos
-- 
-- Fecha de creación:   2012/07/30 12:15:56
-- Nombre del módulo:   siete_segmentos_mux - Behavioral
-- Descripción: 
--   Multiplexor (de frecuencia) para mostrar un valor diferente en cada uno de
--   los visualizadores de siete segmentos. Esto se logra activando solamente un
--   visualizador a la vez y mandar el dato correspondiente. Si la frecuencia es
--   mayor a 16Hz por visualizador, no habrá parpadeo perceptible.
--   Diseñado para Basys2 de Digilent.
--
-- Revisión:
--   Revisión 0.01 - Archivo creado.
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity siete_segmentos_mux is
    PORT (
        clk   : IN  STD_LOGIC;
        reset : IN  STD_LOGIC;
        D0    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Primer dígito.
        D1    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Segundo dígito.
        D2    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Tercer dígito.
        D3    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Cuarto dígito.
        salida: OUT STD_LOGIC_VECTOR(5 downto 0);  --Salida del multiplexor (valor a desplegar).
        MUX   : OUT STD_LOGIC_VECTOR(3 downto 0)   --Valor que define cual dígito se va a mostrar.
    );
end siete_segmentos_mux;
 
architecture Behavioral of siete_segmentos_mux is
    type estados is (rst, v0, v1, v2, v3);
    signal estado : estados;
begin
    visualizadores: process (reset, clk) begin
        if (reset = '1') then
            estado <= rst;
            MUX <= x"F";
            salida <= "111111";
        elsif rising_edge(clk) then
            case estado is
                when v0 =>
                    salida <= D3;
                    MUX <= "1110";
                    estado <= v1;
                when v1 =>
                    salida <= D2;
                    MUX <= "1101";
                    estado <= v2;
                when v2 =>
                    salida <= D1;
                    MUX <= "1011";
                    estado <= v3;
                when others =>
                    salida <= D0;
                    MUX <= "0111";
                    estado <= v0;
            end case;
        end if;
    end process;
end Behavioral;

A grandes rasgos, este componente acepta como entrada cuatro dígitos, D0 a D3, y solamente entrega uno como salida, el cual se mostrará en el visualizador indicado por el valor de MUX. Para este componente existen 5 estados, definidos en la línea 35 y cada señal de reloj recibida marcará el cambio de visualizador.

[wpdm_file id=5]

Integración con el divisor y el visualizador

Finalmente se crea un archivo con los PORT MAP correspondientes para la unión de las señales de un componente a otro, como se mestra en el listado 2.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity siete_segmentos_completo is
    PORT (
        clk   : IN  STD_LOGIC;
        reset : IN  STD_LOGIC;
        D0    : IN  STD_LOGIC_VECTOR(5 downto 0);
        D1    : IN  STD_LOGIC_VECTOR(5 downto 0);
        D2    : IN  STD_LOGIC_VECTOR(5 downto 0);
        D3    : IN  STD_LOGIC_VECTOR(5 downto 0);
        salida: OUT STD_LOGIC_VECTOR(7 downto 0);
        MUX   : OUT STD_LOGIC_VECTOR(3 downto 0)
    );
end siete_segmentos_completo;

architecture Behavioral of siete_segmentos_completo is
    COMPONENT clk200Hz IS
        PORT (
            entrada: IN  STD_LOGIC;
            reset  : IN  STD_LOGIC;
            salida : OUT STD_LOGIC
        );
    END COMPONENT;
    
    COMPONENT siete_segmentos IS
        PORT (
            entrada: IN  STD_LOGIC_VECTOR(5 downto 0);
            salida : OUT STD_LOGIC_VECTOR(7 downto 0)
        );
    END COMPONENT;
    
    COMPONENT siete_segmentos_mux IS
        PORT (
            clk   : IN  STD_LOGIC;
            reset : IN  STD_LOGIC;
            D0    : IN  STD_LOGIC_VECTOR(5 downto 0);
            D1    : IN  STD_LOGIC_VECTOR(5 downto 0);
            D2    : IN  STD_LOGIC_VECTOR(5 downto 0);
            D3    : IN  STD_LOGIC_VECTOR(5 downto 0);
            salida: OUT STD_LOGIC_VECTOR(5 downto 0);
            MUX   : OUT STD_LOGIC_VECTOR(3 downto 0)
        );
    END COMPONENT;
    
    signal clk_out : STD_LOGIC := '0';
    signal digito  : STD_LOGIC_VECTOR(5 downto 0);
begin
    clk_i: clk200Hz PORT MAP(
        clk, reset, clk_out
    );
    
    mux_i: siete_segmentos_mux PORT MAP(
        clk_out, reset, "000000", "000001", "000010", "000011", digito, MUX
    );
    
    seg_i: siete_segmentos PORT MAP(
        digito, salida
    );
end Behavioral;

Para este ejemplo se precargan los valores 0, 1, 2, y 3 en cada uno de los segmentos del visualizador (línea 54), como se muestra en la figura 3.

Figura 3: Multiplexor para 7 segmentos en Basys2.

Figura 3: Multiplexor para 7 segmentos en Basys2.

A esta integración del decodificador de seis bits a siete segmentos, con el divisor de frecuencia, y este multiplexor se le denominará simplemente como “siete segmentos completo”, y su código junto con archivo de implementación en la Basys2 se pueden descargar aquí:

[wpdm_file id=6]

Conclusión

En esta entrada vemos como poco a poco los sistemas digitales incrementan en complejidad, agregando un componente a la vez. Además, podemos apreciar como el diseño de componentes digitales individuales se asemeja al uso de funciones en los lenguajes de programación convencionales. En este caso ya tenemos un circuito digital capaz de mostrar cuatro digitos independientes en los visualizadores. El siguiente paso es hacer un pequeño contador :). Si alguna parte parece demasiado críptica en el código, no dudes en utilizar la sección de comentarios que está debajo :). Gracias por la lectura, y hasta la próxima.

Referencias

  • Haskell, Richard E. y Hanna, Darrin M. (2008). Learning by Example Using VHDL – Basic Digital Design with a Basys FPGA Board. Michigan: LBE Books.
  • Tocci, Ronald (1993). Sistemas Digitales – Principios y Aplicaciones (5ta Edición). México: Prentice Hall.

You Might Also Like

22 Comentarios

  • Responder
    Victor
    mayo 7, 2013 at 8:59 pm

    Hola de nuevo…una duda que tengo es de donde se obtienen o se jalan las entradas DO,D1,D2,D3 es que estoy realizando un contador pero las salidas las mando a los leds….y los quiero mandar tambien a los display pero no se bien como funciona el multiplexor ejemplificado anteriormente….
    este es mi codigo aver si me puedes hacer saber, donde necesito meter el multilplexor

    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;
    		RESET: in std_logic;
    		ANODES: out std_logic_vector(3 downto 0);
    		 
    		LED: out std_logic_vector(7 downto 0);
    		X:out std_logic_vector(6 downto 0));
    end cont;
    
    architecture Behavioral of cont is
    
    signal COUNTER: std_logic_vector(7 downto 0) := (others =&gt; '0');
    	signal PRESCALER: std_logic_vector(25 downto 0);
    begin
    
    	CounterProcess: process(RESET, CLK)
    	begin
    		if rising_edge(CLK) then
    			if RESET = '1' then
    				PRESCALER  '0');
    				COUNTER  '0');
    			else		
    				if PRESCALER &lt; &quot;10111110101111000010000000&quot; then
    					PRESCALER &lt;= PRESCALER + 1;
    				else
    					PRESCALER  '0');
    					COUNTER &lt;= COUNTER + 1;
    				end if;
    			end if;
    		end if;
    	end process CounterProcess;
    	
    	LED  X  X  X  X  X  X  X  X  X  X  X &lt;= &quot;1111111&quot;;
      end case;
     end process display;
    
    
     dis: process(COUNTER)
     begin
     if COUNTER &lt; &quot;00001000&quot; then
     ANODES &lt;= &quot;0111&quot;;
     else ANODES &lt;= &quot;1111&quot;;
     end if;
     end process dis;
     
     
    
    end Behavioral;
    

    si te das cuenta estoy nadamas apagando los segmentos a llegar al < que 8……espero tu respuesta y muchas gracias…..

    • Responder
      Carlos Ramos
      mayo 7, 2013 at 11:14 pm

      Hola, Víctor. Para este ejemplo, las entradas D0, D1, D2 y D3 poseen un valor constante, asignado en la línea 54 del listado 2.
      ¿Podrías indicarme con más detalle cuál es el propósito de tu componente? Concretamente, ¿cuáles son las entradas del sistema y qué se espera como salida? Por lo que deduzco, lo cual puede ser incorrecto, necesitas mostrar un contador en un visualizador. De ser así, ¿cuántos visualizadores debes ocupar para el diseño? Espero tu respuesta :).

      • Responder
        Victor
        mayo 8, 2013 at 12:01 pm

        El objetivo es realizar un contador del 0 al 99 y poder visualizar el conteo en 2 de los display y que al llegar 99 se regrese a 0 nuevamente….de entradas nadamas seria el clk y un reset ya que iniciaria de forma automatica a hacer el conteo…. y las salidas serian las del multiplexor para abilitar los segmentos y el decodificador…gracias nuevamente espero y me puedas ayudar

        • Responder
          Carlos Ramos
          mayo 9, 2013 at 9:34 am

          Víctor, en ese caso considero que el proyecto que puedes tomar como referencia es el del reloj digital, cuyo código fuente puedes descargar. Aunque para tu aplicación deberás hacer algunos cambios, la mayoría de los cuales residen en el archivo contador_reloj.vhd, el cual sería más o menos así:

          library IEEE;
          use IEEE.NUMERIC_STD.ALL;
          use IEEE.STD_LOGIC_1164.ALL;
          
          entity contador_reloj is
          	PORT (
          		clk  : IN  STD_LOGIC; --Reloj de 1Hz.
          		reset: IN  STD_LOGIC; --Señal de reset.
          		C1   : OUT STD_LOGIC_VECTOR(2 DOWNTO 0); --Segundo dígito del contador.
          		C0   : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); --Primer dígito del contador.
          	);
          end contador_reloj;
          
          architecture Behavioral of contador_reloj is
          	signal cc1: UNSIGNED(3 downto 0) := &quot;0000&quot;;
          	signal cc0: UNSIGNED(3 downto 0) := &quot;0000&quot;;
          begin
          	reloj: process (clk, reset) begin
          		if reset = '1' then
          			cc1 &lt;= &quot;0000&quot;;
          			cc0 &lt;= &quot;0000&quot;;
          		elsif rising_edge(clk) then
          			cc0 &lt;= cc0 + 1;
          			if cc0 = 9 then
          				cc1 &lt;= cc1 + 1;
          				cc0 &lt;= &quot;0000&quot;;
          			end if;
          			if cc1 = 9 then
          				cc1 &lt;= &quot;0000&quot;;
          			end if;
          		end if;
          	end process;
          	
          	--Asignación de señales.
          	C1 &lt;= STD_LOGIC_VECTOR(cc1);
          	C0 &lt;= STD_LOGIC_VECTOR(cc0);
          end Behavioral;
          

          Revisa el componente de reloj digital, ya que considero que es el más parecido a tu proyecto. Para ese reloj utilicé otros componentes, como se muestra en el diagrama a bloques. Por ejemplo, puedes probar el reloj digital y modificar el archivo siete_segmentos_mux.vhd para no mostrar dos de los cuatro visualizadores. Hazme sabe si el componente te sirve como base para lo que deseas hacer. Seguimos en contacto.

  • Responder
    pablo
    mayo 26, 2013 at 3:30 pm

    en el UCF ,como se asignan las salidas para que me lo muestre en los 7 segmentos , ya que quiero que cada 7 segmentos de la tarjeta me muestre un valor diferente ,pero como lo estoy haciendo no lo hace , espero su ayuda gracias.

    • Responder
      Carlos Ramos
      mayo 27, 2013 at 2:25 pm

      Hola, Pablo. En el listado 2 del la entrada Siete Segmentos y VHDL se encuentra el archivo *.ucf que utilicé para la implementación del proyecto en una tarjeta Basys 2. No sé si ese archivo puede ayudarte en tu problema o si se trata acerca de cómo incluir el archivo al proyecto. Gracias por tu comentario.

  • Responder
    esteban
    octubre 9, 2013 at 9:01 am

    Hola amigo, buen dia. Queria comentarte acerca de una inquietud
    cuando corro el programa como lo estableciste del listado 2, me aparece unas advertencias en sinthasys, mi pregunta es si tengo que agregar alguna fuente para la parte de component para estableces esas entradas o salidas. realmente soy nuevo manenjando este lenguaje y la tarjeta.

    Gracias por tu ayuda.

    • Responder
      Carlos Ramos
      octubre 15, 2013 at 12:15 pm

      Buenas tardes, Esteban, ¿podrías indicarme en qué parte del proceso te marca las advertencias y cuáles son?

  • Responder
    esteban
    octubre 9, 2013 at 9:10 am

    O si por favor podrias pasarme el archivo de implementacion como lo hiciste en el ejercicio de siete segmentos y VHDL

    • Responder
      Carlos Ramos
      octubre 17, 2013 at 9:52 pm

      Hola, Esteban. Claro que sí, aquí adjunto el archivo de implementación para la Basys2 que utilicé.

      NET  &quot;clk&quot;         LOC = &quot;B8&quot;;
      NET  &quot;reset&quot;       LOC = &quot;G12&quot;;
      # Entrada de datos. ###################
      NET  &quot;D0&lt;5&gt;&quot;       LOC = &quot;F3&quot;;
      NET  &quot;D0&lt;4&gt;&quot;       LOC = &quot;G3&quot;;
      NET  &quot;D0&lt;3&gt;&quot;       LOC = &quot;B4&quot;;
      NET  &quot;D0&lt;2&gt;&quot;       LOC = &quot;K3&quot;;
      NET  &quot;D0&lt;1&gt;&quot;       LOC = &quot;L3&quot;;
      NET  &quot;D0&lt;0&gt;&quot;       LOC = &quot;P11&quot;;
      # Segmentos del visualizador. #########
      NET  &quot;salida&lt;7&gt;&quot;   LOC = &quot;N13&quot;; # dp
      NET  &quot;salida&lt;6&gt;&quot;   LOC = &quot;M12&quot;; # g
      NET  &quot;salida&lt;5&gt;&quot;   LOC = &quot;L13&quot;; # f
      NET  &quot;salida&lt;4&gt;&quot;   LOC = &quot;P12&quot;; # e
      NET  &quot;salida&lt;3&gt;&quot;   LOC = &quot;N11&quot;; # d
      NET  &quot;salida&lt;2&gt;&quot;   LOC = &quot;N14&quot;; # c
      NET  &quot;salida&lt;1&gt;&quot;   LOC = &quot;H12&quot;; # b
      NET  &quot;salida&lt;0&gt;&quot;   LOC = &quot;L14&quot;; # a
      # Multiplexor #########################
      NET  &quot;MUX&lt;3&gt;&quot;      LOC = &quot;F12&quot;;
      NET  &quot;MUX&lt;2&gt;&quot;      LOC = &quot;J12&quot;;
      NET  &quot;MUX&lt;1&gt;&quot;      LOC = &quot;M13&quot;;
      NET  &quot;MUX&lt;0&gt;&quot;      LOC = &quot;K14&quot;;
      
  • Responder
    manuel
    febrero 13, 2014 at 6:38 am

    hola carlos disculpe la molestia. me podria apoyar con una duda que tengo para el multiplexor estoy haciendo un proyecto pero con una nexis 3 pero no se donde declarar los puertos D0, D1 ,D2 ,D3 EN LA TARJETA ya que tiene cada uno entradas del 0 al 5 y son muchas entradas de datos para los switch con los que cuenta la tarjeta, la duda es si puedo utilizar por ejemplo mismo switch para varias entradas o usted como lo declaro en su archivo UCF, porque lo he tratado de hacer de forma manual en mi archivo UCF y al momento de compilar no hacepta los datos ingrasados en los pines de entrada D0, D1 ,D2 ,D3; y si lo hago utilizando el PlanAhead no me me permite asignar un pin de entrada o salida para varias terminales, muchas gracias

    • Responder
      Carlos Ramos
      marzo 4, 2014 at 9:24 pm

      ¡Buenas tardes, Manuel! Una de las posibles soluciones es conectar más componentes en los puertos pMod. No es muy recomendable utilizar un mismo interruptor para varias entradas; en caso de que ambas entradas o salidas sean iguales, dicha asignación se puede, y es preferible, hacer desde software mediante señales auxiliares.

      • Responder
        Eduardo
        noviembre 12, 2019 at 11:23 am

        Se requiere generar un circuito en latarjeta BASYS2 que permita la visualización de 4 datos de dos bits en los cuatro displays incorporados. Los datos A,B,CyD a la entrada del multiplexor son datos de dos bits cada uno. En consecuencia,el DATO desalida de dicho multiplexor también es de dos bits(esto está limitado por las capacidades de la tarjeta BASYS2) Cada dato debe mostrarse solamente en un solo display ,de tal forma que en el display 1 se debe visualizar el datoA, en el display 2 se debe visualizar el dato B y a sí sucesivamente. Realice por escrito y de manera ordenada, independientemente del esquema mostrado a continuación,el planteamiento del problema y de cada uno de los módulos a programar en VHDL. Si es necesario, incluya tablas de verdad, ecuaciones booleanas, diagramas de flujo y todo lo necesario para justificar el funcionamiento del programa.Como tip, se sugiere utilizar un modelo de programación global tengo que haces este ejercicio me podrían ayudar.?

  • Responder
    Irving
    mayo 17, 2017 at 3:47 pm

    Que tal.
    He escrito el código y lo he cargado a una tarjeta Spartan-3, funciona perfectamente sin embrgo me sale la siguiente advertencia: “WARNING:Route:455 – CLK Net:clk_i/temporal may have excessive skew because “.
    No se bien a que se refiere y como podría solucionarlo, espero me puedas ayudar, saludos.

    • Responder
      Carlos Ramos
      junio 26, 2017 at 9:47 am

      Irving, esa es una advertencia que básicamente dice “hacer un reloj con un contador no va a ser muy exacto, y no recomendamos que lo hagas así porque puede tener algunos retrasos y generar algunos errores en tu sistema por ello”. Para nuestra aplicación, no obstante, no es un problema tan grande.

  • Responder
    HERMES ROBIEL LIPES VILLAMIZAR
    mayo 24, 2018 at 11:15 pm

    HOLA QUISIERA SABER A DETALLE PARA QUE SE UTILIZA UN CONTADOR A A LA ENTRADA DEL MULTIPLEXOR, Y ESTE CONTADOR QUE FRECUENCIA TIENE. GRACIAS.

    • Responder
      Carlos Ramos
      junio 7, 2018 at 1:30 pm

      Hola, Hermes. ¿A qué contador te refieres? ¿en cuál listado y qué líneas? Saludos.

  • Responder
    Akari
    mayo 29, 2018 at 11:19 pm

    Hola! Mi pregunta, si pudieses ayudarme es, en el listado 1 a partir de la línea 47:

    MUX <= "1110";
    estado
    salida <= D2;
    MUX <= "1101";
    quiénes son esos "1110" y "1101"? De dónde salen? Se refieren a cuál display estará activo? Lo que pasa es que estoy intentando hacer este proyecto pero con un display de cuatro dígitos externo al de la basys, que encima es de cátodo común. Por ende, tengo que modificar las últimas partes del programa, y no sé si esa es una de ellas. Me ayudaría mucho tu respuesta.

    • Responder
      Carlos Ramos
      junio 7, 2018 at 1:29 pm

      Hola, Akari. Así es, esos números indican cuál visualizador estará activo, siendo el cero el que determina cuál de los cuatro visualizadores está activo.
      Como nada más queremos un visualizador activo a la vez, únicamente hay un cero, siendo lo demás unos.
      Espero esta respuesta te sea de utilidad :D.

  • Responder
    miguel bello
    septiembre 28, 2018 at 12:15 pm

    hola como seria el diseño de este mismo codigo para la tarjeta nexys 4 digilent

    • Responder
      Carlos Ramos
      noviembre 7, 2018 at 9:37 pm

      Hola, Miguel. No tengo constraints para tal dispositivo. En teoría, el código debería ser similar, solamente los constraints cambiarían.

  • Responder
    juan
    diciembre 16, 2018 at 11:49 pm

    hola me gustaria saber si en la basys 2 se puede poner un sensor dht11 en una de sus entradas pmod ya que tiene una salida digital de 40 bits donde manda la informacion de la temperatura y humedad.

  • Deja tu comentario