Siebensegmentanzeigen eignen sich wunderbar als leicht umsetzbare Anzeige für z. B. Messwerte oder Statuswerte. Zum Ansteuern der kompletten Anzeige werden insgesamt sieben Datenleitungen und eine gemeinsame Leitung (je nach Anzeigentyp entweder die Masse als Kathode K oder die Betriebsspannung über Anode A) verwendet.
Durch die Verwendung von mehreren Anzeigen können mehrstellige Zahlen dargestellt werden. Da die Ansteuerung einer einzelnen Anzeige bis zu acht Leitungen am Steuerchip benötigt, werden die einzelnen Anzeigen durch einen Multiplexer nacheinander ein- und ausgeschaltet. Wird dieser Vorgang schnell genug wiederholt, ergibt sich für das menschliche Auge den Eindruck, als ob beide Anzeigen aktiv sind.
Wird durch den Multiplexer lediglich die gemeinsame Leitung eines Displays geschaltet, so verringert sich die Anzahl der benötigten Anschlussleitungen von auf
.
Schauen wir uns mal an, wie ein einfacher Multiplexer für zwei Siebensegmentanzeigen in VHDL entworfen werden kann. Die verwendete Siebensegmentanzeige verwendet für jedes Element eine gemeinsame Kathode, die über einen Schmitt-Trigger auf Masse geschaltet werden muss.
Über einen Puls an der CAT-Leitung wird die jeweils aktive Anzeige gewechselt. Für den Multiplexer wird also erst einmal ein Timer benötigt, der die CAT-Leitung in bestimmten Abständen ein- und ausschaltet. Dies soll über das Signal Strobe
geschehen.
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;
Abhängig von dem Zustand des Signals Strobe_Int
werden die jeweiligen vier Bit eines Datenbytes genutzt und als passendes Muster auf den sieben Datenleitungen ausgegeben:
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);
Die Beschreibung für den vollständige Multiplexer sieht damit folgendermaßen aus:
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;
Der fertige Multiplexer soll abschließend genutzt werden um einen Sekundenzähler zu realisieren. Dazu wird ein 125 MHz Takt für die Schaltung heruntergeteilt, ein Zähler inkrementiert und der Wert für die Zehner-, bzw. Einerstellen an den Multiplexer weiter gegeben.
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;
Das fertige Design kann anschließend auf das FPGA übertragen und ausprobiert werden.
Ihr findet das komplette Projekt GitHub-Repository.
Schreibe einen Kommentar