Lesson 6

⏱️ 秒表

🏆 启动/暂停/复位功能
✅ Verilator仿真验证通过

📖 实验描述

实现精密秒表,支持启动、暂停、复位和百分秒显示。

秒表是计数器控制逻辑的典型应用。 与数字时钟不同,秒表需要:启动/暂停控制、复位归零、百分秒(1/100秒)精度。 核心:1/100秒计数器(10ms精度),配合启动/暂停使能信号控制计数。 状态:STOPPED → RUNNING → STOPPED(暂停)→ RUNNING(继续)→ RESET → STOPPED 秒表精度取决于时钟频率和分频精度。50MHz时钟分频到100Hz(10ms)可实现百分秒计时。

🧠 核心概念

📐 电路结构

电路与状态图
秒表结构:

  50MHz → 分频(100Hz) → 10ms脉冲
                          │
                    ┌─────▼─────┐  carry  ┌─────▼─────┐  carry  ┌─────▼────┐
  start/stop ──→   │百分秒计数 │───────→│  秒计数   │───────→│ 分计数   │
  reset ──────→    │  00-99   │        │  00-59   │        │ 00-59   │
                   └───────────┘        └───────────┘        └──────────┘

📝 设计步骤

  1. 1设计50MHz→100Hz分频器(10ms精度)
  2. 2实现百分秒计数器(0-99,99→0+carry)
  3. 3实现秒计数器(0-59)和分计数器(0-59)
  4. 4设计启动/暂停使能逻辑
  5. 5实现复位归零功能
  6. 6测试:启动→运行→暂停→继续→复位

💻 Verilog实现

stopwatch.svSystemVerilog · Verilator 5.020
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
// Stopwatch - 精密秒表
// 百分秒精度,启动/暂停/复位
module stopwatch(
    input  wire       clk,       // 50MHz
    input  wire       rst,
    input  wire       start,     // 启动/暂停切换
    input  wire       reset,     // 复位归零
    output reg  [6:0] cs,        // 百分秒 00-99
    output reg  [5:0] sec,       // 秒 00-59
    output reg  [5:0] min,       // 分 00-59
    output reg        running    // 运行中指示
);

localparam DIV_100HZ = 26'd500_000;  // 50MHz/100 = 500k

reg [25:0] clk_div;
reg tick_10ms;
wire cs_carry, sec_carry;

// Clock divider: 50MHz -> 100Hz (10ms)
always @(posedge clk or posedge rst) begin
    if (rst) begin
        clk_div  <= 26'd0;
        tick_10ms <= 1'b0;
    end else begin
        tick_10ms <= 1'b0;
        if (clk_div >= DIV_100HZ - 26'd1) begin
            clk_div   <= 26'd0;
            tick_10ms <= 1'b1;
        end else begin
            clk_div <= clk_div + 26'd1;
        end
    end
end

// Centisecond counter: 0-99
always @(posedge clk or posedge rst) begin
    if (rst) begin
        cs <= 7'd0;
    end else if (reset) begin
        cs <= 7'd0;
    end else if (running && tick_10ms) begin
        if (cs == 7'd99)
            cs <= 7'd0;
        else
            cs <= cs + 7'd1;
    end
end

assign cs_carry = running && tick_10ms && (cs == 7'd99);

// Second counter: 0-59
always @(posedge clk or posedge rst) begin
    if (rst) begin
        sec <= 6'd0;
    end else if (reset) begin
        sec <= 6'd0;
    end else if (cs_carry) begin
        if (sec == 6'd59)
            sec <= 6'd0;
        else
            sec <= sec + 6'd1;
    end
end

assign sec_carry = cs_carry && (sec == 6'd59);

// Minute counter: 0-59
always @(posedge clk or posedge rst) begin
    if (rst) begin
        min <= 6'd0;
    end else if (reset) begin
        min <= 6'd0;
    end else if (sec_carry) begin
        if (min == 6'd59)
            min <= 6'd0;
        else
            min <= min + 6'd1;
    end
end

// Start/stop toggle
always @(posedge clk or posedge rst) begin
    if (rst) begin
        running <= 1'b0;
    end else if (reset) begin
        running <= 1'b0;
    end else if (start) begin
        running <= ~running;
    end
end

endmodule

🔬 仿真说明

仿真环境与策略

测试:复位→00:00:00;启动→计数运行;暂停→计数保持;继续→从暂停值继续;复位→归零。验证百分秒进位和秒进位正确。

✅ 验证结果

Verilator 5.020 仿真通过

本实验所有Verilog代码已通过Verilator编译验证,功能行为正确。测试用例覆盖核心功能路径,确保设计满足规格要求。

⚠️ 常见错误

🌍 真实世界

工业应用

专业秒表(如体育计时)精度可达1/1000秒甚至更高。奥运会使用电子计时系统,基于同样的计数器原理但频率更高。游泳触壁计时器精度达0.001秒。

💡 扩展挑战

🚀 自己动手

# 编译并运行
verilator --cc stopwatch.sv --exe stopwatch_tb.cpp --build -j 0
./obj_dir/Vstopwatch

🎯 试一试

修改参数

尝试修改代码中的关键参数,观察仿真结果变化:

  • 调整位宽,观察不同数据范围
  • 修改初始值/种子,观察不同起始条件
  • 改变时钟分频,测试不同速度

💡 Verilator会在位宽不匹配时给出Warning,这是学习的好机会

添加功能

在现有基础上增加新功能:

  • 添加新的输入信号和控制逻辑
  • 增加状态或修改状态转移条件
  • 扩展输出,增加更多显示信息

🔧 增量开发:每次只改一个地方,验证通过后再改下一个

📋 Verilog速查

语法说明示例
reg [7:0]8位寄存器reg [7:0] data;
wire组合逻辑连线wire valid = cnt > 5;
always @(posedge clk)时序逻辑上升沿触发
always @(*)组合逻辑敏感列表自动推导
localparam局部常量localparam DIV = 50000000;
case多分支选择注意default分支
$display仿真打印不可综合,仅仿真用

📊 性能指标

资源估算(FPGA参考)

本设计在典型FPGA上的资源占用估算:LUT约20-120个,FF约30-100个,无BRAM/DSP依赖(特殊模块除外)。时钟频率可达50-100MHz+。Verilator仿真速度约5-10M周期/秒。

← 上一课 📚 目录 下一课 →