VHDL新手求助:BASYS-3开发板0000-0099七段显示开关控制实现
Hey there! Let's walk through building this 00-99 switch-controlled counter for your Basys 3 board—you’ve already nailed the core seven-segment decoder, so we’re halfway there!
First, a quick note: you don’t need to manually pick individual logic gates (AND/OR/etc.) for this. VHDL is a behavioral description language—you describe what the circuit does, and tools like Vivado will automatically translate your code into the right logic gates and flip-flops. That takes a lot of the guesswork out!
Here's a step-by-step breakdown of the full system:
Your design needs 4 core components:
- A clock divider to turn the Basys 3’s 100MHz system clock into a slow 1Hz signal (for counting once per second)
- A dual BCD counter (tens + units) controlled by your switches and start/stop signal
- A 1kHz clock divider for seven-segment display multiplexing (so the two digits don’t flicker)
- A multiplexer to toggle between displaying the tens and units digits on the seven-segment displays
First, we need to create slower clocks for counting and display scanning:
1Hz Clock Divider (for counting)
This takes the 100MHz clock and outputs a 1Hz signal to drive the counter:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity clk_divider_1hz is Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; clk_1hz : out STD_LOGIC); end clk_divider_1hz; architecture Behavioral of clk_divider_1hz is signal count : unsigned(25 downto 0) := (others => '0'); signal temp_clk : STD_LOGIC := '0'; begin process(clk, reset) begin if reset = '1' then count <= (others => '0'); temp_clk <= '0'; elsif rising_edge(clk) then -- Count to 50 million (half of 100MHz) to get a 1Hz square wave if count = to_unsigned(49999999, 26) then count <= (others => '0'); temp_clk <= not temp_clk; else count <= count + 1; end if; end if; end process; clk_1hz <= temp_clk; end Behavioral;
1kHz Clock Divider (for display multiplexing)
This creates a fast enough clock to switch between digits without visible flicker:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity clk_divider_1khz is Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; clk_1khz : out STD_LOGIC); end clk_divider_1khz; architecture Behavioral of clk_divider_1khz is signal count : unsigned(16 downto 0) := (others => '0'); signal temp_clk : STD_LOGIC := '0'; begin process(clk, reset) begin if reset = '1' then count <= (others => '0'); temp_clk <= '0'; elsif rising_edge(clk) then if count = to_unsigned(49999, 17) then count <= (others => '0'); temp_clk <= not temp_clk; else count <= count + 1; end if; end if; end process; clk_1khz <= temp_clk; end Behavioral;
This counter handles both manual switch input and automatic counting:
- When the start/stop switch is off: the tens and units digits directly match your switch inputs
- When the start/stop switch is on: the counter increments once per second, rolling over from 99 back to 00
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity bcd_dual_counter is Port ( clk_1hz : in STD_LOGIC; reset : in STD_LOGIC; start_stop : in STD_LOGIC; sw_tens : in STD_LOGIC_VECTOR(3 downto 0); sw_units : in STD_LOGIC_VECTOR(3 downto 0); bcd_tens : out STD_LOGIC_VECTOR(3 downto 0); bcd_units : out STD_LOGIC_VECTOR(3 downto 0)); end bcd_dual_counter; architecture Behavioral of bcd_dual_counter is signal count_tens : unsigned(3 downto 0) := (others => '0'); signal count_units : unsigned(3 downto 0) := (others => '0'); begin process(clk_1hz, reset, start_stop) begin if reset = '1' then count_tens <= (others => '0'); count_units <= (others => '0'); elsif start_stop = '0' then -- Manual mode: set digits directly from switches count_tens <= unsigned(sw_tens); count_units <= unsigned(sw_units); elsif rising_edge(clk_1hz) then -- Automatic counting mode if count_units = 9 then count_units <= (others => '0'); if count_tens = 9 then count_tens <= (others => '0'); else count_tens <= count_tens + 1; end if; else count_units <= count_units + 1; end if; end if; end process; bcd_tens <= std_logic_vector(count_tens); bcd_units <= std_logic_vector(count_units); end Behavioral;
This uses your existing BCD decoder and toggles between tens/units digits to display both at once:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity seven_seg_mux is Port ( clk_1khz : in STD_LOGIC; bcd_tens : in STD_LOGIC_VECTOR(3 downto 0); bcd_units : in STD_LOGIC_VECTOR(3 downto 0); seg : out STD_LOGIC_VECTOR(6 downto 0); an : out STD_LOGIC_VECTOR(3 downto 0)); end seven_seg_mux; architecture Behavioral of seven_seg_mux is signal bcd_display : STD_LOGIC_VECTOR(3 downto 0); begin -- Your existing BCD-to-seven-segment decoder (works for Basys3's common anode displays) process(bcd_display) begin case bcd_display is when "0000" => seg <= "0000001"; -- 0 when "0001" => seg <= "1001111"; -- 1 when "0010" => seg <= "0010010"; -- 2 when "0011" => seg <= "0000110"; -- 3 when "0100" => seg <= "1001100"; -- 4 when "0101" => seg <= "0100100"; -- 5 when "0110" => seg <= "0100000"; -- 6 when "0111" => seg <= "0001111"; -- 7 when "1000" => seg <= "0000000"; -- 8 when "1001" => seg <= "0000100"; -- 9 when others => seg <= "1111111"; -- Turn off invalid digits end case; end process; -- Toggle between tens and units digits process(clk_1khz) begin if rising_edge(clk_1khz) then if clk_1khz = '0' then -- Display units digit (rightmost display, AN0) bcd_display <= bcd_units; an <= "1110"; -- Common anode: low = on else -- Display tens digit (second from right, AN1) bcd_display <= bcd_tens; an <= "1101"; end if; end if; end process; end Behavioral;
This ties all components together and maps to the Basys3's physical pins:
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity top_basys3_counter is Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; sw : in STD_LOGIC_VECTOR(15 downto 0); -- 16 Basys3 switches seg : out STD_LOGIC_VECTOR(6 downto 0); an : out STD_LOGIC_VECTOR(3 downto 0)); end top_basys3_counter; architecture Behavioral of top_basys3_counter is component clk_divider_1hz Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; clk_1hz : out STD_LOGIC); end component; component clk_divider_1khz Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; clk_1khz : out STD_LOGIC); end component; component bcd_dual_counter Port ( clk_1hz : in STD_LOGIC; reset : in STD_LOGIC; start_stop : in STD_LOGIC; sw_tens : in STD_LOGIC_VECTOR(3 downto 0); sw_units : in STD_LOGIC_VECTOR(3 downto 0); bcd_tens : out STD_LOGIC_VECTOR(3 downto 0); bcd_units : out STD_LOGIC_VECTOR(3 downto 0)); end component; component seven_seg_mux Port ( clk_1khz : in STD_LOGIC; bcd_tens : in STD_LOGIC_VECTOR(3 downto 0); bcd_units : in STD_LOGIC_VECTOR(3 downto 0); seg : out STD_LOGIC_VECTOR(6 downto 0); an : out STD_LOGIC_VECTOR(3 downto 0)); end component; signal clk_1hz : STD_LOGIC; signal clk_1khz : STD_LOGIC; signal bcd_tens : STD_LOGIC_VECTOR(3 downto 0); signal bcd_units : STD_LOGIC_VECTOR(3 downto 0); -- Switch mapping (adjust if you prefer different positions): -- SW15 = Start/Stop -- SW11-SW8 = Tens digit input -- SW3-SW0 = Units digit input begin u_clk_1hz : clk_divider_1hz port map(clk => clk, reset => reset, clk_1hz => clk_1hz); u_clk_1khz : clk_divider_1khz port map(clk => clk, reset => reset, clk_1khz => clk_1khz); u_counter : bcd_dual_counter port map(clk_1hz => clk_1hz, reset => reset, start_stop => sw(15), sw_tens => sw(11 downto 8), sw_units => sw(3 downto 0), bcd_tens => bcd_tens, bcd_units => bcd_units); u_seg_mux : seven_seg_mux port map(clk_1khz => clk_1khz, bcd_tens => bcd_tens, bcd_units => bcd_units, seg => seg, an => an); end Behavioral;
- Connect the Basys3's
BTNR(right button) to theresetpin to reset the counter to 00 - Double-check your switch assignments in the top module if you want to use different switches
- The seven-segment code assumes common anode displays (which the Basys3 uses), so your existing decoder is perfect as-is
内容的提问来源于stack exchange,提问作者selinoktay

