Lesson 1

🚦 交通灯控制器

🏆 红→绿→黄循环正确
✅ Verilator仿真验证通过

📖 实验描述

实现一个交通灯控制器,按照红→绿→黄的标准顺序循环,每个灯持续指定时间。

交通灯控制器是有限状态机(FSM)最经典的教学案例。 现实中十字路口的交通灯需要协调两个方向:主干道和支路。本实验先从单方向3色灯控制入手,理解状态机设计的基本方法。 核心状态:RED(30s) → GREEN(25s) → YELLOW(5s) → RED... 状态机类型为Moore机——输出仅由当前状态决定。每个状态有一个倒计时计数器,计数到0时状态转移。 交通灯控制器虽简单,但涵盖了FSM设计的核心要素:状态定义、状态转移、输出逻辑、定时控制。全球每天有超过3亿个交通灯在运行这种逻辑。

🧠 核心概念

📐 电路结构

电路与状态图
交通灯FSM结构:

  ┌─────┐  cnt=0  ┌───────┐  cnt=0  ┌───────┐
  │ RED │───────→│ GREEN │───────→│YELLOW │
  │ 30s │←───────│ 25s   │       │  5s   │
  └─────┘  cnt=0  └───────┘       └───┬───┘
                                     │cnt=0
                                     └──────┘

  每个状态:
  - 独立倒计时计数器
  - 输出对应灯色
  - 计数归零时转移至下一状态

📝 设计步骤

  1. 1定义3个状态:RED/GREEN/YELLOW
  2. 2设计倒计时计数器(参数化各状态持续时间)
  3. 3实现状态转移逻辑:计数归零时切换
  4. 4输出解码:状态→{red, green, yellow}灯
  5. 5添加异步复位,上电进入RED态
  6. 6仿真验证:观察完整红→绿→黄循环

💻 Verilog实现

traffic_light.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
// Traffic Light Controller - 交通灯控制器
// Moore FSM: RED(30) → GREEN(25) → YELLOW(5) → RED
module traffic_light(
    input  wire clk,
    input  wire rst,
    output reg  red,
    output reg  green,
    output reg  yellow,
    output reg  [4:0] countdown
);

localparam RED_TIME    = 5'd30;
localparam GREEN_TIME  = 5'd25;
localparam YELLOW_TIME = 5'd5;

typedef enum logic [1:0] {
    S_RED    = 2'd0,
    S_GREEN  = 2'd1,
    S_YELLOW = 2'd2
} state_t;

state_t state;
reg [4:0] timer;

always @(posedge clk or posedge rst) begin
    if (rst) begin
        state     <= S_RED;
        timer     <= RED_TIME;
        red       <= 1'b1;
        green     <= 1'b0;
        yellow    <= 1'b0;
        countdown <= RED_TIME;
    end else begin
        case (state)
            S_RED: begin
                red    <= 1'b1;
                green  <= 1'b0;
                yellow <= 1'b0;
                if (timer == 5'd1) begin
                    state <= S_GREEN;
                    timer <= GREEN_TIME;
                end else begin
                    timer <= timer - 5'd1;
                end
            end
            S_GREEN: begin
                red    <= 1'b0;
                green  <= 1'b1;
                yellow <= 1'b0;
                if (timer == 5'd1) begin
                    state <= S_YELLOW;
                    timer <= YELLOW_TIME;
                end else begin
                    timer <= timer - 5'd1;
                end
            end
            S_YELLOW: begin
                red    <= 1'b0;
                green  <= 1'b0;
                yellow <= 1'b1;
                if (timer == 5'd1) begin
                    state <= S_RED;
                    timer <= RED_TIME;
                end else begin
                    timer <= timer - 5'd1;
                end
            end
            default: begin
                state <= S_RED;
                timer <= RED_TIME;
                red   <= 1'b1;
                green <= 1'b0;
                yellow<= 1'b0;
            end
        endcase
        countdown <= timer;
    end
end

endmodule

🔬 仿真说明

仿真环境与策略

测试完整状态循环:复位后进入RED态,计时30→1后转入GREEN(25→1),再转入YELLOW(5→1),最后回到RED。验证灯色输出与倒计时完全正确。

✅ 验证结果

Verilator 5.020 仿真通过

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

⚠️ 常见错误

🌍 真实世界

工业应用

交通灯控制器是城市交通系统的基础。现代交通灯使用传感器和自适应算法优化通行效率,但核心FSM结构不变。上海、北京等超大城市每天处理超过2000个路口的信号协调,基于类似的FSM扩展设计。

💡 扩展挑战

🚀 自己动手

# 编译并运行
verilator --cc traffic_light.sv --exe traffic_light_tb.cpp --build -j 0
./obj_dir/Vtraffic_light

🎯 试一试

修改参数

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

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

💡 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周期/秒。

← 上一课 📚 目录 下一课 →