Assignment Chef icon Assignment Chef
All English tutorials

Programming lesson

Mastering Sequential Circuits in VHDL: Build a Stopwatch Like a Pro (2026 Edition)

Learn to design sequential circuits in VHDL by building a stopwatch with counters, clock dividers, and pushbutton control. Step-by-step guide with simulation tips for ECSE 222 Lab #2.

VHDL sequential circuits ECSE 222 lab stopwatch VHDL clock divider VHDL counter VHDL Altera DE1-SoC FPGA design digital logic simulation ModelSim testbench 7-segment display VHDL pushbutton debouncing state machine VHDL BCD counter 50 MHz clock divider hardware description language tutorial sequential logic VHDL

Introduction: Why Sequential Circuits Matter in 2026

In today's world of AI accelerators, smart wearables, and real-time IoT devices, sequential circuits are the backbone of digital systems that remember and react over time. From fitness trackers counting your steps to autonomous drones timing sensor readings, counters and state machines drive modern electronics. In this ECSE 222 lab tutorial, you'll learn how to describe sequential logic in VHDL by designing a stopwatch that measures time in 10-millisecond increments. By the end, you'll be able to simulate and test your design on the Altera DE1-SoC board—a skill that translates directly to industry FPGA development.

Learning Objectives: What You'll Master

  • Design an up-counter and a down-counter in VHDL
  • Create a clock divider to generate enable signals at precise intervals
  • Build a multi-digit stopwatch with start, pause, and reset controls
  • Write testbenches for functional simulation using ModelSim
  • Map your design to the DE1-SoC board using pushbuttons and 7-segment displays

Part 1: The Up-Counter – Your First Sequential Circuit

A counter is the simplest sequential circuit: it remembers a value and increments (or decrements) on each clock edge. For your stopwatch, you'll need counters that count from 0 to 9 (for centiseconds and seconds) and from 0 to 5 (for tens of seconds and minutes). Let's start with an 4-bit up-counter with an asynchronous active-low reset and an enable signal.

VHDL Code for the Up-Counter

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity gNN_counter is
    Port ( enable : in  std_logic;
           reset  : in  std_logic;
           clk    : in  std_logic;
           count  : out std_logic_vector(3 downto 0));
end gNN_counter;

architecture Behavioral of gNN_counter is
    signal cnt : unsigned(3 downto 0) := (others => '0');
begin
    process(clk, reset)
    begin
        if reset = '0' then
            cnt <= (others => '0');
        elsif rising_edge(clk) then
            if enable = '1' then
                cnt <= cnt + 1;
            end if;
        end if;
    end process;
    count <= std_logic_vector(cnt);
end Behavioral;

Explanation: The counter uses an internal unsigned signal cnt. On reset (active low), it clears to 0. On each rising clock edge, if enable is high, cnt increments. The output is converted to std_logic_vector.

Simulation with Testbench

To verify your counter, write a testbench that applies a clock, toggles enable, and asserts reset. In ModelSim, you'll see the count increment only when enable is high. This is the same principle used in gaming consoles to keep score—except here we're counting clock cycles instead of points.

Part 2: Clock Divider – Generating the 10ms Enable Signal

The DE1-SoC board provides a 50 MHz clock. To measure 10 ms, you need an enable signal that pulses once every 500,000 clock cycles (since 50 MHz / 100 = 500,000). A clock divider counts down from T-1 to 0 and asserts en_out when the count reaches 0.

Calculating T

Desired period = 10 ms = 0.01 s. Clock period = 1/50 MHz = 20 ns. Number of cycles = 0.01 s / 20 ns = 500,000. So T = 500,000. Your down-counter will count from 499,999 down to 0.

VHDL Code for Clock Divider

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity gNN_clock_divider is
    Port ( enable : in  std_logic;
           reset  : in  std_logic;
           clk    : in  std_logic;
           en_out : out std_logic);
end gNN_clock_divider;

architecture Behavioral of gNN_clock_divider is
    constant T : integer := 500000;
    signal cnt : integer range 0 to T-1 := 0;
begin
    process(clk, reset)
    begin
        if reset = '0' then
            cnt <= 0;
            en_out <= '0';
        elsif rising_edge(clk) then
            if enable = '1' then
                if cnt = 0 then
                    cnt <= T-1;
                    en_out <= '1';
                else
                    cnt <= cnt - 1;
                    en_out <= '0';
                end if;
            else
                en_out <= '0';
            end if;
        end if;
    end process;
end Behavioral;

Tip: The en_out pulse lasts one clock cycle. This signal will drive the enable input of your centiseconds counter.

Part 3: Building the Stopwatch – Putting It All Together

Your stopwatch has six counters (two per digit pair) for centiseconds, seconds, and minutes. You also need a state machine to handle start (PB0), pause (PB1), and reset (PB2). Pushbuttons are active low (0 when pressed, 1 when released). The state machine must remember the current state even after the button is released.

State Machine VHDL Snippet

type state_type is (IDLE, RUNNING, PAUSED);
signal state : state_type := IDLE;

process(clk, reset)
begin
    if reset = '0' then
        state <= IDLE;
    elsif rising_edge(clk) then
        case state is
            when IDLE =>
                if start = '0' then state <= RUNNING; end if;
            when RUNNING =>
                if stop = '0' then state <= PAUSED; end if;
            when PAUSED =>
                if start = '0' then state <= RUNNING; end if;
        end case;
    end if;
end process;

The stopwatch enable signal is '1' only when state = RUNNING and the clock divider's en_out is '1'. Counters chain: when a counter reaches 9 (or 5 for tens), it rolls over and enables the next higher counter.

Top-Level Entity

entity gNN_stopwatch is
    Port ( start : in  std_logic;
           stop  : in  std_logic;
           reset : in  std_logic;
           clk   : in  std_logic;
           HEX0  : out std_logic_vector(6 downto 0);
           HEX1  : out std_logic_vector(6 downto 0);
           HEX2  : out std_logic_vector(6 downto 0);
           HEX3  : out std_logic_vector(6 downto 0);
           HEX4  : out std_logic_vector(6 downto 0);
           HEX5  : out std_logic_vector(6 downto 0));
end gNN_stopwatch;

You'll instantiate the clock divider, six counters (with different rollover values), and six 7-segment decoders (from Lab #1). The decoders convert each 4-bit BCD value to the 7-segment pattern.

Simulation and Testing

Write a comprehensive testbench that simulates pressing buttons and verifies the count sequence. In ModelSim, you can run for several seconds of simulated time (e.g., 100 ms) to see the centiseconds increment. This is similar to debugging a smartwatch firmware—you simulate edge cases like rapid button presses or reset during counting.

Mapping to the DE1-SoC Board

After compiling in Quartus, assign pins: pushbuttons to KEY0-2, 7-segment displays to HEX0-5, and the 50 MHz clock to PIN_Y2. Download the bitstream and test: press PB0 to start, PB1 to pause, PB2 to reset. The display shows time in MM:SS:CS format (e.g., 01:23:45 for 1 minute, 23 seconds, 45 centiseconds).

Troubleshooting Common Issues

  • Counter not incrementing: Check enable signal and clock divider output. Use simulation to verify en_out pulses.
  • State machine stuck: Ensure reset is active low and buttons are debounced (though for this lab, simple edge detection suffices).
  • 7-segment display shows wrong digits: Verify decoder mapping and that counters are BCD (0-9 or 0-5).

Conclusion: From Lab to Real-World Applications

You've just built a stopwatch that could be the core of a sports timer, a kitchen timer, or a data acquisition logger. The same principles apply to designing state machines for AI inference controllers or clock dividers for sensor sampling rates. As FPGA technology evolves for edge AI and 5G, mastering sequential VHDL remains a critical skill. Practice by adding features like lap timing or a countdown mode—your imagination is the limit.

Keywords: VHDL sequential circuits, ECSE 222 lab, stopwatch VHDL, clock divider VHDL, counter VHDL, Altera DE1-SoC, FPGA design, digital logic simulation, ModelSim testbench, 7-segment display, pushbutton debouncing, state machine VHDL, BCD counter, 50 MHz clock divider, hardware description language tutorial.