首先,需要定义输入和输出端口,包括四个方向的红、黄、绿灯和数码管的显示。

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
Verilog 交通灯控制器设计:十字路口红绿灯信号控制

原文地址: https://www.cveoy.top/t/topic/lxz1 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录