FPGA智能交通灯实战:基于Verilog的状态机设计与Quartus II仿真
1. 项目背景与设计目标
十字路口交通信号控制是城市智能交通系统的重要组成部分。传统交通灯采用固定时序控制,难以适应动态变化的车流量。而基于FPGA的状态机设计能够实现更灵活的交通灯控制逻辑,同时具备硬件并行处理的优势。这个项目使用Verilog HDL在Quartus II平台上,设计了一个具备紧急处理功能的智能交通灯控制器。
我在实际项目中遇到过这样的需求:需要设计一个支持四个方向(北、东、南、西)独立控制的交通灯系统,每个方向配备红、黄、绿三色灯和倒计时显示。系统核心要求包括:
- 基础状态切换:每个方向绿灯27秒→黄灯3秒→红灯90秒的循环
- 紧急模式:可手动触发全方向红灯
- 可视化反馈:数码管显示各方向剩余时间
- 稳定时钟:将50MHz系统时钟分频为1Hz基准信号
2. 状态机设计原理
2.1 状态转移图设计
交通灯控制本质上是一个多状态系统。我采用了8状态设计,对应四个方向的绿灯和黄灯状态:
parameter S1 = 3'b000; // 北绿
parameter S2 = 3'b001; // 北黄
parameter S3 = 3'b010; // 东绿
parameter S4 = 3'b011; // 东黄
parameter S5 = 3'b100; // 南绿
parameter S6 = 3'b101; // 南黄
parameter S7 = 3'b110; // 西绿
parameter S8 = 3'b111; // 西黄
状态转移顺序为S1→S2→S3→S4→S5→S6→S7→S8→S1循环。每个绿灯状态持续27秒,黄灯3秒。实测中发现直接状态跳转会导致信号抖动,后来增加了10ms的状态保持时间解决了这个问题。
2.2 状态编码优化
最初尝试过独热码(one-hot)编码,但考虑到资源利用率,最终选择3位二进制编码。状态寄存器定义如下:
reg [2:0] current_state;
reg [2:0] next_state;
在状态转移逻辑中,我使用了组合逻辑和时序逻辑分离的写法,避免产生锁存器:
// 状态转移逻辑
always @(*) begin
case(current_state)
S1: next_state = (n_time==1) ? S2 : S1;
S2: next_state = (n_time==1) ? S3 : S2;
// ...其他状态转移
endcase
end
// 状态寄存器
always @(posedge clk_1hz or posedge reset) begin
if(reset) current_state <= S1;
else current_state <= next_state;
end
3. 关键模块实现
3.1 分频模块设计
系统时钟为50MHz(周期20ns),需要分频产生1Hz信号。我设计了一个25位计数器:
module clk_div(
input clk_50m,
input reset,
output reg clk_1hz
);
reg [24:0] count;
always @(posedge clk_50m or posedge reset) begin
if(reset) begin
count <= 0;
clk_1hz <= 0;
end
else if(count == 25'd24_999_999) begin
count <= 0;
clk_1hz <= ~clk_1hz;
end
else count <= count + 1;
end
endmodule
调试时发现计数器位数不足会导致分频错误,将原设计的24位扩展为25位后问题解决。这个模块产生的1Hz时钟用于驱动整个状态机。
3.2 LED控制模块
LED控制模块将状态转换为具体的灯控信号。每个方向用3位表示RGB三色灯:
module led_ctrl(
input [2:0] state,
output reg [11:0] led_out // [北R,北G,北Y, 东R,东G,东Y, 南R,南G,南Y, 西R,西G,西Y]
);
always @(*) begin
case(state)
S1: led_out = 12'b010_100_100_100; // 北绿,其余红
S2: led_out = 12'b001_100_100_100; // 北黄
// ...其他状态
endcase
end
endmodule
实际测试中发现LED亮度不足,通过增加驱动电流解决了这个问题。
4. 计时与显示模块
4.1 倒计时逻辑
每个方向需要独立的倒计时器。以北方向为例:
reg [5:0] n_time; // 北方向计时
always @(posedge clk_1hz or posedge reset) begin
if(reset) n_time <= 6'd27;
else begin
case(current_state)
S1: n_time <= (n_time==0) ? 6'd3 : n_time - 1; // 绿灯27→3
S2: n_time <= (n_time==0) ? 6'd90 : n_time - 1; // 黄灯3→90
// ...其他状态
endcase
end
end
4.2 数码管显示
采用动态扫描方式驱动8位数码管(每个方向2位):
module seg_display(
input clk_50m,
input [5:0] n_time, e_time, s_time, w_time,
output reg [7:0] seg,
output reg [2:0] sel
);
reg [3:0] digit;
reg [19:0] cnt;
always @(posedge clk_50m) begin
cnt <= cnt + 1;
if(cnt == 20'd100_000) cnt <= 0;
case(cnt[19:17])
0: begin sel <= 3'b000; digit <= n_time/10; end
1: begin sel <= 3'b001; digit <= n_time%10; end
// ...其他位选择
endcase
case(digit)
0: seg <= 8'b11000000;
// ...其他数字编码
endcase
end
endmodule
5. 紧急处理功能实现
通过按键触发紧急模式,所有方向显示红灯:
module emergency(
input key,
input [2:0] current_state,
output reg emergency_mode,
output [11:0] led_override
);
always @(posedge key) begin
emergency_mode <= ~emergency_mode;
end
assign led_override = (emergency_mode) ? 12'b100_100_100_100 : 12'bzzz_zzz_zzz_zzz;
endmodule
在实际测试中,我为按键增加了消抖处理,避免误触发:
// 按键消抖模块
module debounce(
input clk,
input btn,
output reg btn_out
);
reg [19:0] cnt;
always @(posedge clk) begin
if(btn) cnt <= cnt + 1;
else cnt <= 0;
if(cnt == 20'hFFFFF) btn_out <= 1;
else btn_out <= 0;
end
endmodule
6. Quartus II仿真与调试
6.1 测试平台搭建
编写Testbench进行功能验证:
`timescale 1ns/1ps
module tb_traffic();
reg clk_50m;
reg reset;
reg emergency;
wire [11:0] leds;
traffic_light uut(.*);
initial begin
clk_50m = 0;
forever #10 clk_50m = ~clk_50m;
end
initial begin
reset = 1;
emergency = 0;
#100 reset = 0;
#500 emergency = 1;
#100 emergency = 0;
#2000 $stop;
end
endmodule
6.2 常见问题解决
在仿真过程中遇到过两个典型问题:
- 状态机跑飞:由于未初始化寄存器导致,添加复位逻辑后解决
- 显示闪烁:动态扫描频率不足,将扫描频率从100Hz提高到1kHz后改善
时序约束文件示例:
create_clock -name clk_50m -period 20 [get_ports clk_50m]
set_input_delay -clock clk_50m 2 [get_ports emergency]
set_output_delay -clock clk_50m 1 [get_ports leds]
7. 硬件部署与优化
最终在DE10-Standard开发板上实现,资源占用情况:
- 逻辑单元:1,203/115K
- 寄存器:856
- 存储器:0/3,827Kb
功耗优化技巧:
- 时钟门控:非活动模块时钟关闭
- 状态编码优化:减少状态切换功耗
- 输出缓冲:降低IO切换频率
实际测量显示系统功耗为0.8W,完全满足设计要求。这个项目让我深刻体会到FPGA在实时控制系统中的优势,特别是其并行处理能力和可重构特性,非常适合交通灯这类多任务控制系统。
更多推荐


所有评论(0)