---
title: "BCD counter 0-9999 on seven segment VHDL"
subject: "Embedded System"
chapter: 9
key: "semester_6/embedded_system:vhdl-bcd-counter-seven-segment"
source: https://www.bctengineer.com/q/semester_6/embedded_system/vhdl-bcd-counter-seven-segment
site: BCT Engineering
---

# BCD counter 0-9999 on seven segment VHDL

Embedded System · Chapter 9: Microcontrollers in Embedded Systems

- Asked in: 2070 Bhadra, 8 marks
- Answer checked by Claude Opus 5.5 (high effort) on 2026-10-14
- Page: https://www.bctengineer.com/q/semester_6/embedded_system/vhdl-bcd-counter-seven-segment
- Whole chapter: https://www.bctengineer.com/md/semester_6/embedded_system/chapter-9

## Question

Write the code for BCD counter to display 0 to 9999 in seven segment using VHDL.

## Short answer

A 4-digit BCD counter increments on a slow tick (e.g. one second). Digits are multiplexed on a 7-segment display by scanning with a fast clock. The design uses tick and scan dividers, BCD to seven-segment decoding, and active-low segment and digit enables.

## Answer

#### Design

- A 4-digit BCD counter (0000 to 9999) is stored as four 4-bit digits. A slow tick (one per second) increments the units digit; each digit rolls from 9 to 0 and carries into the next; 9999 wraps to 0000.
- A seven-segment display (assumed common anode, so segments and digit enables are active low, as on common FPGA boards) shows the four digits. The digits share the segment lines and are scanned (multiplexed) one at a time at about 1 kHz, so all appear lit.
- Generics `TICK_DIV` and `SCAN_DIV` give the number of clock cycles per count and per digit (default for a 50 MHz clock), and can be made small for simulation.

```text
 clk -> [tick divider] -> [4-digit BCD counter]
                                 | digit(0..3)
                                 v
 clk -> [scan div] -> [sel] -> [4:1 mux] -> [7-seg] -> seg
                          +--> [2-to-4 decoder] ---------> an
```

#### VHDL code

```vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bcd_counter_7seg is
  generic (
    TICK_DIV : positive := 50_000_000;   -- clocks per count step (1 s at 50 MHz)
    SCAN_DIV : positive := 50_000        -- clocks per digit (1 ms at 50 MHz)
  );
  port (
    clk : in  std_logic;
    rst : in  std_logic;                          -- active high
    seg : out std_logic_vector(6 downto 0);       -- g f e d c b a, active low
    an  : out std_logic_vector(3 downto 0)        -- digit enable, active low
  );
end entity bcd_counter_7seg;

architecture rtl of bcd_counter_7seg is
  type bcd_array is array (0 to 3) of unsigned(3 downto 0);
  signal digit    : bcd_array := (others => (others => '0'));   -- 0=units ... 3=thousands
  signal tick_cnt : integer range 0 to TICK_DIV - 1 := 0;
  signal scan_cnt : integer range 0 to SCAN_DIV - 1 := 0;
  signal sel      : unsigned(1 downto 0) := (others => '0');    -- digit being displayed
  signal value    : unsigned(3 downto 0);

  -- BCD to seven segment (active low, bit order g f e d c b a)
  function to_seg(d : unsigned(3 downto 0)) return std_logic_vector is
  begin
    case to_integer(d) is
      when 0 => return "1000000";
      when 1 => return "1111001";
      when 2 => return "0100100";
      when 3 => return "0110000";
      when 4 => return "0011001";
      when 5 => return "0010010";
      when 6 => return "0000010";
      when 7 => return "1111000";
      when 8 => return "0000000";
      when 9 => return "0010000";
      when others => return "1111111";             -- blank
    end case;
  end function;
begin
  -- 1) BCD counter 0000 .. 9999
  count_proc : process (clk, rst)
  begin
    if rst = '1' then
      digit    <= (others => (others => '0'));
      tick_cnt <= 0;
    elsif rising_edge(clk) then
      if tick_cnt = TICK_DIV - 1 then
        tick_cnt <= 0;
        if digit(0) /= 9 then
          digit(0) <= digit(0) + 1;
        else
          digit(0) <= (others => '0');
          if digit(1) /= 9 then
            digit(1) <= digit(1) + 1;
          else
            digit(1) <= (others => '0');
            if digit(2) /= 9 then
              digit(2) <= digit(2) + 1;
            else
              digit(2) <= (others => '0');
              if digit(3) /= 9 then
                digit(3) <= digit(3) + 1;
              else
                digit(3) <= (others => '0');       -- 9999 -> 0000
              end if;
            end if;
          end if;
        end if;
      else
        tick_cnt <= tick_cnt + 1;
      end if;
    end if;
  end process;

  -- 2) refresh: show one digit at a time
  scan_proc : process (clk, rst)
  begin
    if rst = '1' then
      scan_cnt <= 0;
      sel      <= (others => '0');
    elsif rising_edge(clk) then
      if scan_cnt = SCAN_DIV - 1 then
        scan_cnt <= 0;
        sel      <= sel + 1;
      else
        scan_cnt <= scan_cnt + 1;
      end if;
    end if;
  end process;

  value <= digit(to_integer(sel));
  seg   <= to_seg(value);
  an    <= "1110" when sel = "00" else
           "1101" when sel = "01" else
           "1011" when sel = "10" else
           "0111";
end architecture rtl;
```

The code was analysed with GHDL and simulated with small generics: after 123 count steps the scanned digits were 3 (units), 2 (tens), 1 (hundreds), 0 (thousands), showing 0123.

## Check yourself

The answer's key points as multiple-choice questions, with the correct option and why.

1. How does the 4-digit BCD counter count from 0000 to 9999?
   A. One 14-bit binary counter is converted at the end
   B. Each digit counts 0 to 9, rolls to 0 and carries into the next digit; 9999 wraps to 0000
   C. Each digit counts 0 to 15 before carrying
   D. Each digit is reset by the scan counter
   Answer: B. The units digit increments on each tick; when a digit is 9 it returns to 0 and increments the next digit, and 9999 wraps to 0000. (Key point: BCD digit rollover)

2. Why are the four digits scanned one at a time at about 1 kHz?
   A. So the digits share the segment lines yet all appear lit continuously
   B. To slow the counter to one count per second
   C. To convert BCD to binary
   D. To reduce the clock to 50 MHz
   Answer: A. The digits share the segment lines, so only one can be driven at a moment. Fast scanning makes all look lit due to persistence of vision. (Key point: Display multiplexing)

3. With the assumed common anode display, how are segments and digit enables driven?
   A. Active high; '1' turns them on
   B. Active low; '0' turns them on
   C. Segments active high, enables active low
   D. Using tri-state '1' and 'Z'
   Answer: B. A common anode display lights a segment when driven low, so seg and an are active low (e.g. an = 1110 selects the units digit). (Key point: Active-low segments)

4. What are the generics TICK_DIV and SCAN_DIV for?
   A. They set the display brightness
   B. They set the number of clock cycles per count step and per digit, and can be made small for simulation
   C. They select common anode or common cathode
   D. They set the number of digits
   Answer: B. TICK_DIV divides the clock to one count per second and SCAN_DIV to about 1 ms per digit; small values make simulation fast. (Key point: Role of generics)

## Related in Embedded System

- [Seven segment display and clock counter](https://www.bctengineer.com/question.md?key=semester_6%2Fembedded_system%3Aseven-segment-clock-design) — Embedded System, chapter 9
- [Display 0 to 9 on seven segment](https://www.bctengineer.com/question.md?key=semester_6%2Fembedded_system%3A8051-seven-segment-0-9) — Embedded System, chapter 9, asked 2×
- [Display 99 to 00 on seven segment](https://www.bctengineer.com/question.md?key=semester_6%2Fembedded_system%3A8051-seven-segment-99-00) — Embedded System, chapter 9

## Related in other subjects

- [BCD-to-7-segment decoder; frequency counter](https://www.bctengineer.com/question.md?key=semester_3%2Fdigital_logic%3Abcd-7segment-frequency-counter) — Digital Logic, chapter 11
- [BCD-to-seven-segment decoder, segments a and e](https://www.bctengineer.com/question.md?key=semester_3%2Fdigital_logic%3Abcd-seven-segment-a-e) — Digital Logic, chapter 4
- [DEMUX vs decoder; seven-segment "b" segment](https://www.bctengineer.com/question.md?key=semester_3%2Fdigital_logic%3Ademux-decoder-b-segment) — Digital Logic, chapter 4
- [Seven-segment "a" segment using NOR gates](https://www.bctengineer.com/question.md?key=semester_3%2Fdigital_logic%3Aa-segment-nor-gates) — Digital Logic, chapter 4
