news 2026/4/22 11:06:11

用Verilog手把手教你实现一个带紧急通行功能的十字路口交通灯(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Verilog手把手教你实现一个带紧急通行功能的十字路口交通灯(附完整代码)

从零实现FPGA交通灯控制系统:状态机设计与紧急通行模块实战

1. 项目背景与核心需求

十字路口交通灯控制是FPGA初学者绝佳的练手项目。这个看似简单的系统,实际上融合了状态机设计、时序控制、外设驱动等多个数字电路核心概念。对于刚接触Verilog的同学来说,通过实现一个支持紧急通行功能的交通灯控制器,可以快速掌握FPGA开发的完整流程。

典型的交通灯系统需要满足以下核心需求:

  • 多状态循环:主干道与支路的红绿灯按预设时间自动切换
  • 倒计时显示:通过数码管实时显示当前状态剩余时间
  • 紧急中断:特殊车辆通过时可强制切换为全红灯状态
  • 黄灯过渡:任何绿灯到红灯的转换都需要3秒黄灯缓冲
// 状态定义示例 parameter MAIN_GREEN = 3'b001; // 主干道绿灯 parameter MAIN_YELLOW = 3'b010; // 主干道黄灯 parameter SIDE_GREEN = 3'b100; // 支路绿灯

2. 系统架构设计

2.1 整体模块划分

我们的交通灯控制系统采用模块化设计,主要包含以下功能单元:

模块名称功能描述关键信号
时钟分频模块将系统时钟分频为1Hz计时脉冲clk_1Hz
状态控制模块实现交通灯状态机及紧急通行逻辑current_state, next_state
倒计时模块生成各状态的倒计时数值count_val[7:0]
数码管驱动模块将倒计时数值转换为7段数码管信号seg_data[6:0]
LED驱动模块控制实际红绿灯LED的亮灭red, yellow, green

2.2 状态机设计

交通灯控制的核心是一个有限状态机(FSM),我们定义7个主要状态:

  1. S0:主干道绿灯(29秒),支路红灯
  2. S1:主干道黄灯(3秒),支路红灯
  3. S2:主干道左转绿灯(14秒),支路红灯
  4. S3:主干道黄灯(3秒),支路红灯
  5. S4:支路绿灯(20秒),主干道红灯
  6. S5:支路黄灯(3秒),主干道红灯
  7. S6:紧急通行模式(全红灯10秒)
// 状态转移逻辑片段 always @(posedge clk_1Hz or negedge reset_n) begin if (!reset_n) begin current_state <= S0; end else begin case(current_state) S0: if (timer_expired) current_state <= S1; S1: if (timer_expired) current_state <= S2; // ...其他状态转移 S6: if (timer_expired) current_state <= S0; endcase end end

3. 关键模块实现细节

3.1 时钟分频模块

FPGA开发板通常提供50MHz系统时钟,我们需要将其分频为1Hz信号用于计时:

module clock_divider ( input clk_50MHz, input reset_n, output reg clk_1Hz ); reg [25:0] counter; always @(posedge clk_50MHz or negedge reset_n) begin if (!reset_n) begin counter <= 0; clk_1Hz <= 0; end else if (counter == 26'd24_999_999) begin counter <= 0; clk_1Hz <= ~clk_1Hz; end else begin counter <= counter + 1; end end endmodule

3.2 倒计时与显示模块

每个状态都有特定的持续时间,倒计时模块需要根据当前状态加载不同的初始值:

状态初始值数码管显示
S02929→00
S1303→00
S21414→00
S3303→00
S42020→00
S5303→00
S61010→00
// 倒计时模块核心逻辑 always @(posedge clk_1Hz or negedge reset_n) begin if (!reset_n) begin count_val <= STATE_DURATION[current_state]; end else if (emergency) begin count_val <= 10; // 紧急模式固定10秒 end else if (count_val > 0) begin count_val <= count_val - 1; end else begin count_val <= STATE_DURATION[next_state]; end end

3.3 紧急通行模块实现

紧急通行功能通过外部按钮触发,当检测到按钮按下时:

  1. 立即中断当前状态
  2. 强制切换到全红灯状态(S6)
  3. 保持10秒后恢复原状态循环
// 紧急模式处理逻辑 always @(posedge emergency_btn or posedge clk_1Hz) begin if (emergency_btn) begin saved_state <= current_state; current_state <= S6; end else if (current_state == S6 && timer_expired) begin current_state <= saved_state; end end

4. 调试与优化技巧

4.1 Modelsim仿真要点

编写测试平台时,需要重点验证以下场景:

  1. 正常状态循环是否按时序切换
  2. 紧急按钮能否正确中断当前状态
  3. 倒计时显示是否准确
  4. 状态恢复后时序是否正确
// 测试平台示例片段 initial begin // 初始化信号 reset_n = 0; emergency_btn = 0; #100 reset_n = 1; // 正常运行观察 #2900000000; // 观察S0状态 // 触发紧急模式 emergency_btn = 1; #100 emergency_btn = 0; #10000000000; // 观察紧急模式 $finish; end

4.2 常见问题与解决

  1. 状态机跑飞:确保所有状态转移条件完备,添加default分支
  2. 倒计时不同步:检查时钟分频是否准确,1Hz信号是否稳定
  3. 按钮抖动:添加防抖逻辑,通常20ms延时足够
  4. 显示异常:验证数码管译码表是否正确

调试提示:可先单独测试每个模块的功能,再逐步集成。使用SignalTap等工具实时观察FPGA内部信号。

5. 完整系统集成

将各模块例化连接后,顶层模块主要完成:

  1. 时钟分配与全局复位
  2. 按钮信号去抖处理
  3. 状态机与各功能模块互联
  4. 输出信号分配到实际IO引脚
module traffic_light_top ( input clk_50MHz, input reset_n, input emergency_btn, output [2:0] main_light, // [red, yellow, green] output [2:0] side_light, output [6:0] seg_main, output [6:0] seg_side ); wire clk_1Hz; wire debounced_btn; clock_divider u_clk_div( .clk_50MHz(clk_50MHz), .reset_n(reset_n), .clk_1Hz(clk_1Hz) ); debounce u_debounce( .clk(clk_50MHz), .btn_in(emergency_btn), .btn_out(debounced_btn) ); traffic_fsm u_fsm( .clk_1Hz(clk_1Hz), .reset_n(reset_n), .emergency(debounced_btn), .main_light(main_light), .side_light(side_light), .count_val(count_val) ); seg_driver u_seg( .value(count_val), .seg_out({seg_main, seg_side}) ); endmodule

6. 功能扩展思路

基础功能实现后,可以考虑以下增强功能:

  1. 夜间模式:通过光敏传感器或定时器切换为黄灯闪烁
  2. 车流量检测:使用传感器动态调整绿灯时长
  3. 行人按钮:添加行人过街请求功能
  4. 无线遥控:通过蓝牙/WiFi实现远程控制
// 夜间模式实现示例 always @(posedge clk_1Hz) begin if (night_mode) begin main_light <= {1'b0, ~main_light[1], 1'b0}; side_light <= {1'b0, ~side_light[1], 1'b0}; end end

在实现基础版本后,我建议先进行充分仿真验证,再下载到开发板测试。实际调试时,可以先用较短的定时值(如29秒改为2.9秒)来加速测试循环。遇到问题时,采用"分而治之"的策略,逐步隔离定位问题源。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 11:04:36

FFmpeg在直播带货中的实战:如何用一条命令实现多平台推流与画质优化

FFmpeg在直播带货中的实战&#xff1a;如何用一条命令实现多平台推流与画质优化 直播带货的火爆让实时视频处理技术成为电商运营的刚需。想象一下&#xff0c;当你需要同时向抖音、B站、视频号三个平台推送高清直播流时&#xff0c;传统方案可能需要三台编码设备或复杂的推流软…

作者头像 李华
网站建设 2026/4/22 10:57:46

**时序数据库实战:用Go语言构建高性能时间序列数据存储系统**在现代物联网、监控告警和金融交易等场景中,**时序数据**

时序数据库实战&#xff1a;用Go语言构建高性能时间序列数据存储系统 在现代物联网、监控告警和金融交易等场景中&#xff0c;时序数据&#xff08;Time Series Data&#xff09;的处理能力直接决定了系统的实时性和稳定性。传统的通用关系型数据库在面对高频写入、高并发查询和…

作者头像 李华