文档
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仅用于仿真。