Seven segment multiplexer

Seven segment displays are wonderful as an easily implementable display for e.g. measured values ​​or status values.

A total of seven data lines and a common line (depending on the type of display either the mass as cathode K or the operating voltage via anode A) are used to control the complete display.

By using multiple displays, multi-digit numbers can be displayed. Since the control of a single display requires up to eight lines on the control chip, the individual displays are switched on and off in succession by a multiplexer. If this process is repeated quickly enough, the human eye has the impression that both displays are active.

If only the common line of a display is switched by the multiplexer, the number of connection lines required is reduced from Displays x 8 to Displays + 7.

Let's take a look at how a simple multiplexer can be designed for two seven-segment displays in VHDL. This seven-segment display uses a common cathode for each element, which must be switched to ground via a Schmitt trigger.

The currently active display is changed via a pulse on the CAT line. A timer is therefore required for the multiplexer, which switches the CAT line on and off at certain intervals. This should be done using the Strobe signal.

process(Clock, nReset)
    variable RefreshCounter : INTEGER := 0;
begin
    if(nReset = '0') then
        RefreshCounter := 0;
        Strobe_Int <= '0';
    else
        if(rising_edge(Clock)) then
            if(RefreshCounter < REFRESH) then
                RefreshCounter := RefreshCounter + 1;
            else
                RefreshCounter := 0;
                Strobe_Int <= not Strobe_Int;
            end if;
        end if;
    end if;        
end process;

Strobe <= Strobe_Int;

Depending on the state of the Strobe_Int signal, the respective four bits of a data byte are used and output as a suitable pattern on the seven data lines:

process(Clock, nReset)
begin
    if(nReset = '0') then
        Anode <= (others => '0');
    elsif(rising_edge(Clock)) then
        case DisplayData is
            when "0000" => Anode <= "0111111";   
            when "0001" => Anode <= "0000110";
            when "0010" => Anode <= "1011011"; 
            when "0011" => Anode <= "1001111";
            when "0100" => Anode <= "1100110"; 
            when "0101" => Anode <= "1101101"; 
            when "0110" => Anode <= "1111101"; 
            when "0111" => Anode <= "0000111";
            when "1000" => Anode <= "1111111";
            when "1001" => Anode <= "1101111";
            when others => Anode <= (others => '0');
        end case;
    end if;
end process;

DisplayData <= Data(7 downto 4) when Strobe_Int = '1' else Data(3 downto 0);

So the complete description for the multiplexer looks like this:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Multiplexer is
    Generic (   REFRESH : INTEGER := 10000
                );
    Port ( Clock    : in STD_LOGIC;
           nReset   : in STD_LOGIC;
           Data     : in STD_LOGIC_VECTOR(7 downto 0);
           Anode    : out STD_LOGIC_VECTOR(6 downto 0);
           Strobe   : out STD_LOGIC
           );
end Multiplexer;

architecture Multiplexer_Arch of Multiplexer is

    signal DisplayData      : STD_LOGIC_VECTOR(3 downto 0)  := (others => '0');

    signal Strobe_Int       : STD_LOGIC := '0';

begin

    process(Clock, nReset)
        variable RefreshCounter : INTEGER := 0;
    begin
        if(nReset = '0') then
            RefreshCounter := 0;
        else
            if(rising_edge(Clock)) then
                if(RefreshCounter < REFRESH) then
                    RefreshCounter := RefreshCounter + 1;
                else
                    RefreshCounter := 0;
                    Strobe_Int <= not Strobe_Int;
                end if;
            end if;
        end if;        
    end process;

    process(Clock, nReset)
    begin
        if(nReset = '0') then
            Anode <= (others => '0');
        elsif(rising_edge(Clock)) then
            case DisplayData is
                when "0000" => Anode <= "0111111";   
                when "0001" => Anode <= "0000110";
                when "0010" => Anode <= "1011011"; 
                when "0011" => Anode <= "1001111";
                when "0100" => Anode <= "1100110"; 
                when "0101" => Anode <= "1101101"; 
                when "0110" => Anode <= "1111101"; 
                when "0111" => Anode <= "0000111";
                when "1000" => Anode <= "1111111";
                when "1001" => Anode <= "1101111";
                when others => Anode <= (others => '0');
            end case;
        end if;
    end process;

    Strobe <= Strobe_Int;
    DisplayData <= Data(7 downto 4) when Strobe_Int = '1' else Data(3 downto 0);

end Multiplexer_Arch;

The final multiplexer should be used to implement a simple second counter. For this purpose, a 125 MHz clock for the circuit is divided and a counter is incremented. Then the value is splitted into two single decimal numbers and passed into the multiplexer.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity Top is
    Generic (   REFRESH : INTEGER := 1000
                );
    Port (  Clock    : in STD_LOGIC;
            nReset   : in STD_LOGIC;
            Kathode  : out STD_LOGIC;
            Anode    : out STD_LOGIC_VECTOR (6 downto 0)
            );
end Top;

architecture Top_Arch of Top is

    signal First        : STD_LOGIC_VECTOR(3 downto 0) := (others => '0');
    signal Second       : STD_LOGIC_VECTOR(3 downto 0) := (others => '0');

    component Multiplexer is
        Generic (   REFRESH : INTEGER := 10000
                    );
        Port ( Clock    : in STD_LOGIC;
               nReset   : in STD_LOGIC;
               Data     : in STD_LOGIC_VECTOR(7 downto 0);
               Anode    : out STD_LOGIC_VECTOR(6 downto 0);
               Strobe   : out STD_LOGIC
               );
    end component Multiplexer;

begin

    Segment : component Multiplexer generic map (   REFRESH => REFRESH
                                                    )
                                    port map ( Clock => Clock,
                                               Data => Second & First,
                                               nReset => nReset,
                                               Anode => Anode,
                                               Strobe => Kathode
                                               );

    process(Clock, nReset)
        variable Counter    : INTEGER := 0;
        variable Seconds_E  : INTEGER := 0;
        variable Seconds_Z  : INTEGER := 0;
    begin
        if(nReset = '0') then
            Counter := 0;
            Seconds_E := 0;
            Seconds_Z := 0;
        elsif(rising_edge(Clock)) then
            if(Counter < 125000000) then
                Counter := Counter + 1;
            else
                Counter := 0;
                
                if(Seconds_E < 9) then
                    Seconds_E := Seconds_E + 1;
                else
                    Seconds_E := 0;
                    
                    if(Seconds_Z < 9) then
                        Seconds_Z := Seconds_Z + 1;
                    else
                        Seconds_Z := 0;
                    end if;
                end if;
            end if;
            
            First <= STD_LOGIC_VECTOR(to_unsigned(Seconds_E, First'length));
            Second <= STD_LOGIC_VECTOR(to_unsigned(Seconds_Z, First'length));
            
        end if;
    end process;
end Top_Arch;

Now it´s time for testing. Implement the final design and transfer it into your FPGA.

Last updated