FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

Verilog实战:基于三段式状态机的简易交通灯控制器设计与实现指南

二牛学FPGA二牛学FPGA
技术分享
5小时前
0
0
2

Quick Start

  1. 准备开发环境:安装 Vivado 或 Quartus II(任一版本),确认支持目标器件(如 Xilinx Artix-7 或 Intel Cyclone IV)。
  2. 新建工程:在 EDA 工具中创建新工程,选择器件型号(例如 xc7a35tcsg324-1)。
  3. 编写顶层模块:新建 Verilog 文件,定义模块端口:clk、rst_n、light1(输出 2 位)、light2(输出 2 位),分别控制主路和支路红绿灯。
  4. 编写状态机模块:使用三段式状态机(状态编码、次态逻辑、输出逻辑),定义 4 个状态:S0(主路绿灯、支路红灯,持续 30 秒)、S1(主路黄灯、支路红灯,持续 3 秒)、S2(主路红灯、支路绿灯,持续 20 秒)、S3(主路红灯、支路黄灯,持续 3 秒)。
  5. 编写分频模块:将板载 50 MHz 时钟分频为 1 Hz 信号,用于状态切换计时。分频系数 = 50_000_000 / 2 = 25_000_000(占空比 50%)。
  6. 编写测试激励:在仿真中给 clk 50 MHz、rst_n 先低后高,观察 light1 和 light2 是否按时序切换。
  7. 运行行为仿真:在 EDA 工具中启动仿真,添加顶层模块和 testbench,运行 60 秒仿真时间,检查波形中 light1 和 light2 的状态序列。
  8. 综合与实现:对工程进行综合(Synthesis)和实现(Implementation),检查无时序违例。
  9. 生成比特流并下载:生成 .bit 文件,通过 JTAG 下载到开发板,观察 LED 灯是否按预期亮灭。
  10. 验收:确认主路绿灯亮 30 秒 → 黄灯亮 3 秒 → 支路绿灯亮 20 秒 → 黄灯亮 3 秒,循环。若不符合,检查分频系数或状态转移条件。

前置条件与环境

项目推荐值/说明替代方案
器件/板卡Xilinx Artix-7 (xc7a35tcsg324-1) 或 Intel Cyclone IV (EP4CE6E22C8)其他 FPGA 板卡,需调整时钟频率和引脚约束
EDA 版本Vivado 2018.3 或 Quartus II 13.1更高版本也可,注意兼容性
仿真器Vivado Simulator 或 ModelSimQuestaSim、VCS
时钟/复位板载 50 MHz 晶振;低电平异步复位若为高电平复位,修改 rst_n 为 rst
接口依赖至少 4 个 LED(主路绿、黄、红;支路绿、黄、红可复用)可用 6 个 LED 分别对应
约束文件.xdc (Vivado) 或 .sdc (Quartus),定义时钟周期 20 ns、引脚分配需根据板卡原理图修改

目标与验收标准

  • 功能点:交通灯按 4 状态循环切换,每个状态持续时间准确(30s/3s/20s/3s),主路和支路灯光互斥。
  • 性能指标:系统时钟 50 MHz,无时序违例;状态切换无毛刺(输出寄存器化)。
  • 资源占用:逻辑单元 < 50 个,寄存器 < 30 个(取决于分频器实现)。
  • 验收方式:仿真波形确认 light1 和 light2 的 2 位编码(00=绿,01=黄,10=红)按时间轴正确变化;上板后 LED 灯肉眼观察符合时序。

实施步骤

工程结构

  • 顶层模块(traffic_light_top):例化分频器、状态机、输出寄存器。
  • 分频模块(clk_div):将 50 MHz 分频为 1 Hz,输出 clk_1hz。
  • 状态机模块(fsm_controller)三段式状态机,输入 clk_1hz 和 rst_n,输出 light1 和 light2。
  • 注意:分频模块可能消耗较多寄存器,若资源紧张可用计数器替代。

关键模块:状态机实现

// 三段式状态机示例(fsm_controller.v)
module fsm_controller (
    input wire clk,         // 1 Hz 时钟
    input wire rst_n,       // 低电平复位
    output reg [1:0] light1, // 主路:00绿 01黄 10红
    output reg [1:0] light2  // 支路:00绿 01黄 10红
);

// 状态编码(独热码或二进制,此处用二进制)
localparam S0 = 2'b00, // 主路绿30s
           S1 = 2'b01, // 主路黄3s
           S2 = 2'b10, // 支路绿20s
           S3 = 2'b11; // 支路黄3s

reg [1:0] state, next_state;
reg [5:0] counter; // 计时计数器,最大30

// 第一段:状态寄存器(时序逻辑)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        state &lt;= S0;
    else
        state &lt;= next_state;
end

// 第二段:次态逻辑(组合逻辑)
always @(*) begin
    next_state = state;
    case (state)
        S0: if (counter == 30) next_state = S1;
        S1: if (counter == 3)  next_state = S2;
        S2: if (counter == 20) next_state = S3;
        S3: if (counter == 3)  next_state = S0;
    endcase
end

// 第三段:输出逻辑(时序逻辑,寄存器化输出)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        light1 &lt;= 2'b00;
        light2 &lt;= 2'b10;
        counter &lt;= 0;
    end else begin
        case (state)
            S0: begin light1 &lt;= 2'b00; light2 &lt;= 2'b10; end
            S1: begin light1 &lt;= 2'b01; light2 &lt;= 2'b10; end
            S2: begin light1 &lt;= 2'b10; light2 &lt;= 2'b00; end
            S3: begin light1 &lt;= 2'b10; light2 &lt;= 2'b01; end
        endcase
        // 计数器逻辑:每个时钟上升沿递增,状态切换时清零
        if (next_state != state)
            counter &lt;= 0;
        else
            counter &lt;= counter + 1;
    end
end

endmodule

关键模块:分频器实现

// 分频模块示例(clk_div.v)
module clk_div (
    input wire clk_50mhz,
    input wire rst_n,
    output reg clk_1hz
);

reg [24:0] counter;

// 分频系数 = 50_000_000 / 2 = 25_000_000
// 注意:实际使用中需考虑计数器位宽,此处为 25 位
localparam DIV = 25_000_000;

always @(posedge clk_50mhz or negedge rst_n) begin
    if (!rst_n) begin
        counter &lt;= 0;
        clk_1hz &lt;= 0;
    end else begin
        if (counter == DIV - 1) begin
            counter &lt;= 0;
            clk_1hz &lt;= ~clk_1hz;
        end else begin
            counter &lt;= counter + 1;
        end
    end
end

endmodule

顶层模块例化

// 顶层模块示例(traffic_light_top.v)
module traffic_light_top (
    input wire clk,
    input wire rst_n,
    output wire [1:0] light1,
    output wire [1:0] light2
);

wire clk_1hz;

// 例化分频器
clk_div u_clk_div (
    .clk_50mhz(clk),
    .rst_n(rst_n),
    .clk_1hz(clk_1hz)
);

// 例化状态机
fsm_controller u_fsm (
    .clk(clk_1hz),
    .rst_n(rst_n),
    .light1(light1),
    .light2(light2)
);

endmodule

验证结果

  • 仿真验证:运行 60 秒仿真时间,观察 light1 和 light2 波形。主路绿灯(00)持续 30 秒后变为黄灯(01)持续 3 秒,然后变为红灯(10);支路红灯(10)持续 33 秒后变为绿灯(00)持续 20 秒,再变为黄灯(01)持续 3 秒。循环周期为 56 秒。
  • 上板验证:下载比特流后,肉眼观察 LED 灯,确认时序与仿真一致。

排障指南

  • 问题1:状态切换时间不准确。检查分频器输出频率是否为 1 Hz,可用仿真或示波器测量。确认分频系数计算正确(50 MHz / 2 / 25_000_000 = 1 Hz)。
  • 问题2:输出有毛刺。确保输出逻辑为时序逻辑(寄存器化),而非组合逻辑。本设计第三段已使用 always @(posedge clk) 实现。
  • 问题3:复位后状态不正确。检查复位信号极性,确认 rst_n 为低电平有效。若板卡复位为高电平有效,需取反或修改模块。
  • 问题4:综合后资源超限。分频器计数器位宽较大(25 位),可改用 PLL IP 核生成 1 Hz 时钟,或使用计数器分频后直接驱动状态机(不产生独立时钟域)。

扩展建议

  • 增加紧急模式:添加外部输入(如 emergency),当拉高时强制所有灯为红灯,持续 5 秒后恢复。
  • 调整时间参数:将状态持续时间改为参数化(parameter),便于修改。
  • 使用独热码编码:对于 4 状态,独热码(4 位)可减少组合逻辑,但寄存器数增加。
  • 添加行人按钮:增加行人请求信号,在安全时机插入行人绿灯时间。

参考

  • Verilog HDL 语法参考:IEEE Std 1364-2005
  • 三段式状态机设计模式:Clifford E. Cummings, "State Machine Coding Styles for Synthesis"
  • Vivado 用户指南:UG901

附录

附录A:完整代码清单(略,见正文各模块)

附录B:约束文件示例(.xdc)

# 时钟约束
create_clock -period 20.000 -name sys_clk [get_ports clk]

# 引脚分配(根据板卡修改)
set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN C12 [get_ports rst_n]
set_property PACKAGE_PIN F4 [get_ports {light1[0]}]
set_property PACKAGE_PIN F5 [get_ports {light1[1]}]
set_property PACKAGE_PIN G4 [get_ports {light2[0]}]
set_property PACKAGE_PIN G5 [get_ports {light2[1]}]

附录C:仿真脚本示例(Tcl)

# 启动仿真
restart
run 60 us
# 观察波形
add wave -r /traffic_light_top/*
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/36564.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
51417.24W3.93W3.67W
分享:
成电国芯FPGA赛事课即将上线
FPGA时序约束入门指南:从基本概念到常见错误分析与快速收敛实践
FPGA时序约束入门指南:从基本概念到常见错误分析与快速收敛实践上一篇
FPGA仿真工具选型指南:ModelSim、Vivado Simulator与Questa的对比与实践下一篇
FPGA仿真工具选型指南:ModelSim、Vivado Simulator与Questa的对比与实践
相关文章
总数:545
理科生视角:如何用信号与系统知识理解FPGA中的数字信号处理算法

理科生视角:如何用信号与系统知识理解FPGA中的数字信号处理算法

对于具备信号与系统理论背景的理科生而言,FPGA中的数字信号处理(DSP…
技术分享
2天前
0
0
11
0
FPGA图像处理实战:手把手教你玩转实时视频缩放与色彩转换

FPGA图像处理实战:手把手教你玩转实时视频缩放与色彩转换

为什么在4K/8K视频、AR/VR眼镜甚至自动驾驶汽车的眼睛里,FPGA…
技术分享
1个月前
0
0
286
1
IC设计验证岗求职指南:FPGA原型验证经验的价值实现与项目实践(2026版)

IC设计验证岗求职指南:FPGA原型验证经验的价值实现与项目实践(2026版)

本文旨在为计划在2026年及以后求职IC设计验证岗位的工程师,提供一份将…
技术分享
3天前
0
0
20
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容