Verilog三段式FSM,实现十字路口红绿灯
运行环境:VCS + verdi
状态说明:
S0 : 初始状态
S1 : 东西方向绿灯亮,南北方向红灯亮;点亮30周期
S2 : 东西方向黄灯亮,南北方向红灯亮;点亮2 周期
S3 : 东西方向红灯亮,南北方向绿灯亮;点亮30周期
S4 : 东西方向红灯亮,南北方向黄灯亮;点亮2 周期
状态转换说明:
S0 → S1
S1:点亮30周期,进入S2,不足30周期维持S1
S2:点亮2周期,进入S3,不足2周期维持S2
S3:点亮30周期,进入S4,不足30周期维持S3
S4:点亮2周期,进入S1,不足2周期维持S4
代码如下:
如果需要控制时间,自行添加分频器,或者修改tb文件。
module traffic_light (input clk,input rst_n,output [2:0] light_east_west, light_south_north
);// 红路灯点亮的时间定义
localparam GREEN = 30;
localparam YELLOW = 2;// 亮灯的颜色定义
localparam dark = 2'b00;
localparam green = 2'b01;
localparam yello = 2'b10;
localparam red = 2'b11;// 状态定义
parameter S0 = 5'b0_0001; // 初始状态
parameter S1 = 5'b0_0010; // 东西方向绿灯亮,南北方向红灯亮;30周期
parameter S2 = 5'b0_0100; // 东西方向黄灯亮,南北方向红灯亮;2 周期
parameter S3 = 5'b0_1000; // 东西方向红灯亮,南北方向绿灯亮;30周期
parameter S4 = 5'b1_0000; // 东西方向红灯亮,南北方向黄灯亮;2 周期reg [4:0] status;
reg [4:0] next_status;
reg [7:0] cnt;// 计数器控制
always @(posedge clk or negedge rst_n) beginif(!rst_n) cnt <= 8'b0;else if ( (status == S1 && cnt == GREEN-1 ) ||(status == S2 && cnt == YELLOW-1) ||(status == S3 && cnt == GREEN-1 ) ||(status == S4 && cnt == YELLOW-1) )cnt <= 8'b0;elsecnt <= cnt + 1'b1;
end// 状态转换
always @(posedge clk or negedge rst_n) beginif(!rst_n)status <= S0;elsestatus <= next_status;
end// 状态判断
always @(*) beginif(!rst_n) beginnext_status = S0;endelse begincase(status)S0 : next_status = S1;S1 : next_status = (cnt == GREEN-1) ? S2 : S1;S2 : next_status = (cnt == YELLOW-1) ? S3 : S2;S3 : next_status = (cnt == GREEN-1) ? S4 : S3;S4 : next_status = (cnt == YELLOW-1) ? S1 : S4;default : next_status = S0;endcaseend
endreg [2:0] r_light_east_west, r_light_south_north;// 输出控制
always @(posedge clk or negedge rst_n) beginif(!rst_n) beginr_light_east_west <= dark;r_light_south_north <= dark;endelse begincase(status)S0 : beginr_light_east_west <= dark;r_light_south_north <= dark;endS1 : beginr_light_east_west <= green;r_light_south_north <= red;endS2 : beginr_light_east_west <= yello;r_light_south_north <= red;endS3 : beginr_light_east_west <= red;r_light_south_north <= green;endS4 : beginr_light_east_west <= red;r_light_south_north <= yello;enddefault: beginr_light_east_west <= dark;r_light_south_north <= dark;endendcaseend
endassign light_east_west = r_light_east_west;
assign light_south_north = r_light_south_north;endmodule
tb文件:
module tb_traffic_light ();
localparam CLK_PERIDO = 20;reg clk;
reg rst_n;
reg [2:0] light_east_west;
reg [2:0] light_south_north;traffic_light traffic_light_inst(.clk (clk),.rst_n (rst_n),.light_east_west (light_east_west), .light_south_north (light_south_north)
);initial beginclk = 0;forever #(CLK_PERIDO / 2) clk = ~clk;
endinitial beginrst_n = 0;repeat(4) @(posedge clk);#(CLK_PERIDO /5);rst_n = 1;repeat(500) @(posedge clk);$finish;
endinitial begin$dumpfile("traffic_light.fsdb");$dumpvars(0);
endendmodule