Verilog 交通灯控制器设计:十字路口红绿灯信号控制
首先,需要定义输入和输出端口,包括四个方向的红、黄、绿灯和数码管的显示。
module traffic_light_controller(
input clk,
input rst,
input east_west_go,
input north_south_go,
output reg east_west_red,
output reg east_west_yellow,
output reg east_west_green,
output reg north_south_red,
output reg north_south_yellow,
output reg north_south_green,
output reg [3:0] digit_display
);
接下来,需要定义状态机的各个状态,包括东西方向绿灯、黄灯、红灯,南北方向绿灯、黄灯、红灯,以及显示倒计时的状态。
enum {EW_GREEN, EW_YELLOW, EW_RED, NS_GREEN, NS_YELLOW, NS_RED, COUNT_DOWN} state;
然后,需要定义每个状态下的输出信号和计数器值。在此需要注意,绿灯、黄灯、红灯的持续时间分别为 5s、3s 和 8s,需要根据时钟频率计算出对应的计数器值。
reg [3:0] count_down;
reg [3:0] ew_green_counter;
reg [3:0] ew_yellow_counter;
reg [3:0] ew_red_counter;
reg [3:0] ns_green_counter;
reg [3:0] ns_yellow_counter;
reg [3:0] ns_red_counter;
always @(posedge clk or posedge rst) begin
if (rst) begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= 4'b1111;
state <= EW_GREEN;
count_down <= 4'b0000;
ew_green_counter <= 4'b0000;
ew_yellow_counter <= 4'b0000;
ew_red_counter <= 4'b0000;
ns_green_counter <= 4'b0000;
ns_yellow_counter <= 4'b0000;
ns_red_counter <= 4'b0000;
end
else begin
case (state)
EW_GREEN: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b1;
north_south_red <= 1'b1;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= ew_green_counter;
if (ew_green_counter == 5'b11111) begin
state <= EW_YELLOW;
ew_green_counter <= 5'b00000;
end
else begin
ew_green_counter <= ew_green_counter + 5'b00001;
end
end
EW_YELLOW: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b1;
east_west_green <= 1'b0;
north_south_red <= 1'b1;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= ew_yellow_counter;
if (ew_yellow_counter == 5'b01111) begin
state <= EW_RED;
ew_yellow_counter <= 5'b00000;
end
else begin
ew_yellow_counter <= ew_yellow_counter + 5'b00001;
end
end
EW_RED: begin
east_west_red <= 1'b1;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b1;
digit_display <= ew_red_counter;
if (ew_red_counter == 5'b11111) begin
state <= NS_GREEN;
ew_red_counter <= 5'b00000;
end
else begin
ew_red_counter <= ew_red_counter + 5'b00001;
end
end
NS_GREEN: begin
east_west_red <= 1'b1;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b1;
digit_display <= ns_green_counter;
if (ns_green_counter == 5'b11111) begin
state <= NS_YELLOW;
ns_green_counter <= 5'b00000;
end
else begin
ns_green_counter <= ns_green_counter + 5'b00001;
end
end
NS_YELLOW: begin
east_west_red <= 1'b1;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b1;
north_south_green <= 1'b0;
digit_display <= ns_yellow_counter;
if (ns_yellow_counter == 5'b01111) begin
state <= NS_RED;
ns_yellow_counter <= 5'b00000;
end
else begin
ns_yellow_counter <= ns_yellow_counter + 5'b00001;
end
end
NS_RED: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b1;
north_south_red <= 1'b1;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= ns_red_counter;
if (ns_red_counter == 5'b11111) begin
state <= EW_GREEN;
ns_red_counter <= 5'b00000;
end
else begin
ns_red_counter <= ns_red_counter + 5'b00001;
end
end
COUNT_DOWN: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= count_down;
if (count_down == 5'b00000) begin
if (east_west_go) begin
state <= EW_GREEN;
end
else if (north_south_go) begin
state <= NS_GREEN;
end
end
else begin
count_down <= count_down - 5'b00001;
end
end
endcase
end
end
最后,需要在模块中添加一个计时器,用于在 COUNT_DOWN 状态下进行倒计时。
reg [23:0] timer;
always @(posedge clk or posedge rst) begin
if (rst) begin
timer <= 24'b000000000000000000000000;
end
else begin
if (state == COUNT_DOWN) begin
if (timer == 24'b111111111111111111111111) begin
count_down <= count_down - 5'b00001;
timer <= 24'b000000000000000000000000;
end
else begin
timer <= timer + 24'b000000000000000000000001;
end
end
else begin
timer <= 24'b000000000000000000000000;
end
end
end
always @(posedge clk or posedge rst) begin
if (rst) begin
count_down <= 4'b0000;
end
else begin
if (east_west_go) begin
case (state)
EW_GREEN: begin
count_down <= 5'd25;
end
EW_YELLOW: begin
count_down <= 5'd15;
end
EW_RED: begin
count_down <= 5'd40;
end
default: begin
count_down <= 4'b0000;
end
endcase
end
else if (north_south_go) begin
case (state)
NS_GREEN: begin
count_down <= 5'd25;
end
NS_YELLOW: begin
count_down <= 5'd15;
end
NS_RED: begin
count_down <= 5'd40;
end
default: begin
count_down <= 4'b0000;
end
endcase
end
else begin
count_down <= 4'b0000;
end
end
end
完整的代码如下所示。其中,模块的输入输出端口和状态机的各个状态和计数器值可以根据需求进行修改。
module traffic_light_controller(
input clk,
input rst,
input east_west_go,
input north_south_go,
output reg east_west_red,
output reg east_west_yellow,
output reg east_west_green,
output reg north_south_red,
output reg north_south_yellow,
output reg north_south_green,
output reg [3:0] digit_display
);
enum {EW_GREEN, EW_YELLOW, EW_RED, NS_GREEN, NS_YELLOW, NS_RED, COUNT_DOWN} state;
reg [3:0] count_down;
reg [3:0] ew_green_counter;
reg [3:0] ew_yellow_counter;
reg [3:0] ew_red_counter;
reg [3:0] ns_green_counter;
reg [3:0] ns_yellow_counter;
reg [3:0] ns_red_counter;
reg [23:0] timer;
always @(posedge clk or posedge rst) begin
if (rst) begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= 4'b1111;
state <= EW_GREEN;
count_down <= 4'b0000;
ew_green_counter <= 4'b0000;
ew_yellow_counter <= 4'b0000;
ew_red_counter <= 4'b0000;
ns_green_counter <= 4'b0000;
ns_yellow_counter <= 4'b0000;
ns_red_counter <= 4'b0000;
timer <= 24'b000000000000000000000000;
end
else begin
case (state)
EW_GREEN: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b1;
north_south_red <= 1'b1;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= ew_green_counter;
if (ew_green_counter == 5'b11111) begin
state <= EW_YELLOW;
ew_green_counter <= 5'b00000;
end
else begin
ew_green_counter <= ew_green_counter + 5'b00001;
end
end
EW_YELLOW: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b1;
east_west_green <= 1'b0;
north_south_red <= 1'b1;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= ew_yellow_counter;
if (ew_yellow_counter == 5'b01111) begin
state <= EW_RED;
ew_yellow_counter <= 5'b00000;
end
else begin
ew_yellow_counter <= ew_yellow_counter + 5'b00001;
end
end
EW_RED: begin
east_west_red <= 1'b1;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b1;
digit_display <= ew_red_counter;
if (ew_red_counter == 5'b11111) begin
state <= NS_GREEN;
ew_red_counter <= 5'b00000;
end
else begin
ew_red_counter <= ew_red_counter + 5'b00001;
end
end
NS_GREEN: begin
east_west_red <= 1'b1;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b1;
digit_display <= ns_green_counter;
if (ns_green_counter == 5'b11111) begin
state <= NS_YELLOW;
ns_green_counter <= 5'b00000;
end
else begin
ns_green_counter <= ns_green_counter + 5'b00001;
end
end
NS_YELLOW: begin
east_west_red <= 1'b1;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b1;
north_south_green <= 1'b0;
digit_display <= ns_yellow_counter;
if (ns_yellow_counter == 5'b01111) begin
state <= NS_RED;
ns_yellow_counter <= 5'b00000;
end
else begin
ns_yellow_counter <= ns_yellow_counter + 5'b00001;
end
end
NS_RED: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b1;
north_south_red <= 1'b1;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= ns_red_counter;
if (ns_red_counter == 5'b11111) begin
state <= EW_GREEN;
ns_red_counter <= 5'b00000;
end
else begin
ns_red_counter <= ns_red_counter + 5'b00001;
end
end
COUNT_DOWN: begin
east_west_red <= 1'b0;
east_west_yellow <= 1'b0;
east_west_green <= 1'b0;
north_south_red <= 1'b0;
north_south_yellow <= 1'b0;
north_south_green <= 1'b0;
digit_display <= count_down;
if (count_down == 5'b00000) begin
if (east_west_go) begin
state <= EW_GREEN;
end
else if (north_south_go) begin
state <= NS_GREEN;
end
end
else begin
count_down <= count_down - 5'b00001;
if (timer == 24'b111111111111111111111111) begin
count_down <= count_down - 5'b00001;
timer <= 24'b000000000000000000000000;
end
else begin
timer <= timer + 24'b000000000000000000000001;
end
end
end
endcase
end
end
always @(posedge clk or posedge rst) begin
if (rst) begin
count_down <= 4'b0000;
end
else begin
if (east_west_go) begin
case (state)
EW_GREEN: begin
count_down <= 5'd25;
end
EW_YELLOW: begin
count_down <= 5'd15;
end
EW_RED: begin
count_down <= 5'd40;
end
default: begin
count_down <= 4'b0000;
end
endcase
end
else if (north_south_go) begin
case (state)
NS_GREEN: begin
count_down <= 5'd25;
end
NS_YELLOW: begin
count_down <= 5'd15;
end
NS_RED: begin
count_down <= 5'd40;
end
default: begin
count_down <= 4'b0000;
end
endcase
end
else begin
count_down <= 4'b0000;
end
end
end
endmodule
原文地址: https://www.cveoy.top/t/topic/lxz1 著作权归作者所有。请勿转载和采集!