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.