题解主体
首先设置一个倒计时的计数器,每个时钟计数器输出减一,当计数器计数到0时,切换切换显示灯颜色,同时重置计数器为相应颜色的持续时间。每个颜色的指示灯都会持续一段时间,可以取指示灯信号变化的上升沿作为状态转移的触发条件。上升沿的获取可以通过缓存一个时刻的数值,当当前时刻为1,前一时刻为0时,表示上升沿出现。
reg p_red,p_yellow,p_green; //用于缓存信号灯的前一时刻的数值,判断上升沿按照上文提到的倒计时的取值逻辑,首先判断当前是否是绿灯,绿灯倒计时是否大于10,行人按钮是否被按下,如果这三个条件同时满足,则把倒计时置为10。
always @(posedge clk, negedge rst_n)
begin
if(!rst_n)
begin
p_yellow <= 1'd0;
p_red <= 1'd0;
p_green <= 1'd0;
end
else
begin
p_yellow <= yellow;
p_red <= red;
p_green <= green;
end
然后根据指示灯的颜色确定倒计时的数值:当红灯上升沿到达时,说明切换到红灯状态,倒计时置为10,当绿灯上升沿到达时,倒计时置为60,当黄灯上升沿到达时,倒计时置为3。
其余情况下,倒计时每个时钟减一。
always @(posedge clk, negedge rst_n)三个颜色的指示灯之间的转化可以使用一个简单的状态机实现。在红灯状态下,红灯亮,其余两个灯灭。而且当cnt==0,即倒计时结束时切换到黄灯,否则停留在红灯状态。在黄灯灯状态下,黄灯亮,其余两个灯灭。而且当cnt==0,即倒计时结束时切换到绿灯,否则停留在黄灯状态。在绿灯状态下,绿灯亮,其余两个灯灭。而且当cnt==0,即倒计时结束时切换到红灯,否则停留在绿灯状态。
begin
if(!rst_n)
begin
cnt <= 7'd0;
end
else if (pass_request&&green&&(cnt>10))
cnt <= 7'd10;
else if (!green&&p_red)
cnt <= 7'd60;
else if (!yellow&&p_yellow)
cnt <= 7'd3;
else if (!red&&p_red)
cnt <= 7'd10;
else cnt <= cnt -1;
assign clock = cnt;
有一点需要特别注意:考虑取信号上升沿和重置计数器数值所需要的时间,倒计时和信号灯颜色有3个时钟的错位。使用在cnt==3时,而不是cnt==0时,完成状态切换。同时将指示灯延迟一个时钟输出可以实现信号灯颜色和倒计时的对应。
parameter idle = 2'd0,
s1_red = 2'd1,
s2_yellow = 2'd2,
s3_green = 2'd3;
reg [7:0] cnt;
reg [1:0] state; reg p_red,p_yellow,p_green; //用于缓存信号灯的前一时刻的数值,判断上升沿always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= idle;
p_red <= 1'b0;
p_green <= 1'b0;
p_yellow <= 1'b0;
end
else case(state)
idle:
begin
p_red <= 1'b0;
p_green <= 1'b0;
p_yellow <= 1'b0;
state <= s1_red;
end
s1_red:
begin
p_red <= 1'b1;
p_green <= 1'b0;
p_yellow <= 1'b0;
if (cnt == 3)
state <= s2_yellow;
else
state <= s1_red;
end
s2_yellow:
begin
p_red <= 1'b0;
p_green <= 1'b0;
p_yellow <= 1'b1;
if (cnt == 3)
state <= s3_green;
else
state <= s2_yellow;
end
s3_green:
begin
p_red <= 1'b0;
p_green <= 1'b1;
p_yellow <= 1'b0;
if (cnt == 3)
state <= s1_red;
else
state <= s3_green;
end
endcaseend
参考答案
`timescale 1ns/1ns module triffic_light ( input rst_n, //异位复位信号,低电平有效 input clk, //时钟信号 input pass_request, output wire[7:0]clock, output reg red, output reg yellow, output reg green ); parameter idle = 2'd0, s1_red = 2'd1, s2_yellow = 2'd2, s3_green = 2'd3; reg [7:0] cnt; reg [1:0] state; reg p_red,p_yellow,p_green; //用于缓存信号灯的前一时刻的数值,判断上升沿 always @(posedge clk or negedge rst_n) begin if(!rst_n) begin state <= idle; p_red <= 1'b0; p_green <= 1'b0; p_yellow <= 1'b0; end else case(state) idle: begin p_red <= 1'b0; p_green <= 1'b0; p_yellow <= 1'b0; state <= s1_red; end s1_red: begin p_red <= 1'b1; p_green <= 1'b0; p_yellow <= 1'b0; if (cnt == 3) state <= s2_yellow; else state <= s1_red; end s2_yellow: begin p_red <= 1'b0; p_green <= 1'b0; p_yellow <= 1'b1; if (cnt == 3) state <= s3_green; else state <= s2_yellow; end s3_green: begin p_red <= 1'b0; p_green <= 1'b1; p_yellow <= 1'b0; if (cnt == 3) state <= s1_red; else state <= s3_green; end endcase end always @(posedge clk or negedge rst_n) if(!rst_n) cnt <= 7'd10; else if (pass_request&&green&&(cnt>10)) cnt <= 7'd10; else if (!green&&p_green) cnt <= 7'd60; else if (!yellow&&p_yellow) cnt <= 7'd5; else if (!red&&p_red) cnt <= 7'd10; else cnt <= cnt -1; assign clock = cnt; always @(posedge clk or negedge rst_n) if(!rst_n) begin yellow <= 1'd0; red <= 1'd0; green <= 1'd0; end else begin yellow <= p_yellow; red <= p_red; green <= p_green; end endmodule