组合逻辑与时序逻辑:4 位计数器 + 七段显示

知识库
知识库文档
/tech-stacks/verilog-systemverilog/examples/组合逻辑与时序逻辑:4 位计数器 + 七段显示.md

文档

Verilog 组合逻辑与时序逻辑:4 位计数器 + 七段显示

目标

用 Verilog 编写一个带使能和复位的 4 位计数器,配合七段数码管译码器,在 FPGA 上显示 0-F。

工具

  • Icarus Verilog (仿真) + GTKWave (波形)
  • 或任意 FPGA 开发板(本代码可直接综合)

一、七段显示译码器(组合逻辑)

// seven_seg_decoder.v — 4 位 BCD → 七段显示(共阳极,低电平点亮)
module seven_seg_decoder (
    input  wire [3:0] bcd,       // 4-bit BCD (0-15)
    output reg  [6:0] seg         // 七段 {a,b,c,d,e,f,g} — 共阳:0=亮
);

    always @(*) begin
        case (bcd)
            4'h0:    seg = 7'b1000000;  // "0"
            4'h1:    seg = 7'b1111001;  // "1"
            4'h2:    seg = 7'b0100100;  // "2"
            4'h3:    seg = 7'b0110000;  // "3"
            4'h4:    seg = 7'b0011001;  // "4"
            4'h5:    seg = 7'b0010010;  // "5"
            4'h6:    seg = 7'b0000010;  // "6"
            4'h7:    seg = 7'b1111000;  // "7"
            4'h8:    seg = 7'b0000000;  // "8"
            4'h9:    seg = 7'b0010000;  // "9"
            4'hA:    seg = 7'b0001000;  // "A"
            4'hB:    seg = 7'b0000011;  // "b"
            4'hC:    seg = 7'b1000110;  // "C"
            4'hD:    seg = 7'b0100001;  // "d"
            4'hE:    seg = 7'b0000110;  // "E"
            4'hF:    seg = 7'b0001110;  // "F"
            default: seg = 7'b1111111;  // 全灭
        endcase
    end

endmodule

二、带使能的 4 位计数器(时序逻辑)

// counter_4bit.v — 同步复位 + 使能的 4 位计数器
module counter_4bit (
    input  wire       clk,          // 时钟
    input  wire       rst_n,        // 异步复位(低有效)
    input  wire       enable,       // 计数使能
    output reg  [3:0] count,        // 计数值
    output wire       overflow      // 溢出标志(15→0)
);

    assign overflow = (count == 4'hF) && enable;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            count <= 4'h0;
        end else if (enable) begin
            count <= count + 4'h1;
        end
        // enable 为低时保持
    end

endmodule

三、顶层模块(Top-Level)

// top_counter.v — 顶层:计数器 + 分频 + 七段显示
module top_counter (
    input  wire       clk_50mhz,    // 50MHz 板载时钟
    input  wire       rst_n,        // 按键复位(低有效)
    output wire [6:0] seg,          // 七段管
    output wire [3:0] an            // 位选(单管共阳直接用 1 位)
);

    wire [31:0] clk_div;
    wire       clk_slow;
    wire [3:0] bcd_count;

    // ── 时钟分频(50MHz → ~2Hz)──
    // 50,000,000 / 2 = 25,000,000 cycles → 分频系数
    parameter DIV = 25_000_000;

    reg [24:0] div_counter = 0;
    reg        clk_slow_reg = 0;

    always @(posedge clk_50mhz or negedge rst_n) begin
        if (!rst_n) begin
            div_counter <= 0;
            clk_slow_reg <= 0;
        end else if (div_counter >= DIV - 1) begin
            div_counter <= 0;
            clk_slow_reg <= ~clk_slow_reg;
        end else begin
            div_counter <= div_counter + 1;
        end
    end

    assign clk_slow = clk_slow_reg;

    // ── 计数器例化 ──
    counter_4bit u_counter (
        .clk     (clk_slow),
        .rst_n   (rst_n),
        .enable  (1'b1),        // 始终计数
        .count   (bcd_count),
        .overflow()
    );

    // ── 七段译码例化 ──
    seven_seg_decoder u_decoder (
        .bcd (bcd_count),
        .seg (seg)
    );

    // 单管显示:位选常有效(共阳极时拉低)
    assign an = 4'b0000;

endmodule

四、仿真 Testbench

// tb_counter.v — 4 位计数器仿真
`timescale 1ns / 1ps

module tb_counter;

    reg        clk;
    reg        rst_n;
    reg        enable;
    wire [3:0] count;
    wire       overflow;

    counter_4bit uut (
        .clk    (clk),
        .rst_n  (rst_n),
        .enable (enable),
        .count  (count),
        .overflow(overflow)
    );

    // 100MHz 时钟生成
    always #5 clk = ~clk;   // 10ns 周期

    initial begin
        $dumpfile("counter.vcd");
        $dumpvars(0, tb_counter);

        clk    = 0;
        rst_n  = 0;
        enable = 1;
        #20 rst_n = 1;       // 释放复位

        // 观察 20 个计数周期
        #200;

        // 测试使能关闭
        enable = 0;
        #40;
        $display("使能关闭:count = %d(应保持)", count);

        enable = 1;
        #200;

        // 测试复位
        rst_n = 0;
        #10 rst_n = 1;
        $display("复位后:count = %d(应为 0)", count);

        #100 $finish;
    end

    always @(posedge clk) begin
        $display("t=%0tns | count=%d | overflow=%b", $time, count, overflow);
    end

endmodule

五、运行步骤

# 编译仿真
iverilog -o counter_tb counter_4bit.v tb_counter.v
vvp counter_tb

# 查看波形
gtkwave counter.vcd

六、关键点

概念 说明
组合逻辑 always @(*) / assign,输出仅取决于当前输入(七段译码器)
时序逻辑 always @(posedge clk),输出取决于时钟沿(计数器)
阻塞赋值 = 用于组合逻辑,立即生效
非阻塞赋值 <= 用于时序逻辑,同时更新,避免竞争
复位 negedge rst_n 实现异步复位
参数化 parameter 使模块可复用(如分频系数)

⚠️ Verilog 的可综合子集有限:for 循环只在 generate 块中可综合,#delay 仅用于仿真。

信息

路径
/tech-stacks/verilog-systemverilog/examples/组合逻辑与时序逻辑:4 位计数器 + 七段显示.md
更新时间
2026/5/31