eda课程设计交通灯

99ANYc3cd6 课程介绍 1

EDA课程设计:基于FPGA的交通灯控制系统

设计目标

本课程设计旨在利用EDA技术和FPGA(现场可编程门阵列)芯片,设计并实现一个功能完备、结构清晰、易于扩展的十字路口交通灯控制系统,具体目标如下:

  1. 基本功能实现:

    • 实现一个十字路口(主干道A与次干道B)的交通灯控制。
    • 主干道A:绿灯 -> 黄灯 -> 红灯。
    • 次干道B:红灯 -> 绿灯 -> 黄灯。
    • A、B两方向灯色变化必须互锁,确保不会出现冲突。
    • 各灯色持续时间可预置并显示。
  2. 核心能力培养:

    • 掌握使用Verilog HDL进行数字逻辑电路的设计方法。
    • 熟悉FPGA开发流程(设计输入、功能仿真、综合实现、硬件测试)。
    • 理解并应用状态机(Finite State Machine, FSM)来设计时序逻辑控制电路。
    • 掌握分频器、计数器等基本数字逻辑模块的设计与应用。
  3. 扩展功能(可选,用于提高设计难度和创新性):

    • 紧急车辆优先通行: 当有紧急车辆(如救护车、消防车)信号时,两个方向的交通灯全部变为红灯,以便紧急车辆快速通过。
    • 倒计时显示: 在数码管上显示当前灯色的剩余时间。
    • 车流量检测与动态调整: 模拟通过传感器检测车辆排队情况,动态调整绿灯持续时间。

设计方案论证

1 核心控制器选择:状态机

交通灯的控制是一个典型的时序逻辑问题,其输出(灯的状态)不仅取决于当前的输入,还取决于之前的历史状态,采用有限状态机作为核心控制器是最合适、最清晰的设计方案。

  • 为什么是状态机?
    • 结构清晰: 可以将交通灯的每一个工作阶段(如A绿灯、A黄灯、B绿灯等)定义为一个独立的状态,状态之间的转换关系一目了然。
    • 易于实现: Verilog HDL对状态机的描述非常方便,可以使用case语句来实现状态转移和输出。
    • 可靠性强: 状态机的设计能确保系统在任意状态下都能正确地进入下一个状态,避免逻辑混乱。

2 状态定义

根据基本功能需求,我们可以定义4个核心状态:

  • S_A_GREEN (状态0): 主干道A绿灯亮,次干道B红灯亮。
  • S_A_YELLOW (状态1): 主干道A黄灯亮,次干道B红灯亮。
  • S_B_GREEN (状态2): 主干道A红灯亮,次干道B绿灯亮。
  • S_B_YELLOW (状态3): 主干道A红灯亮,次干道B黄灯亮。

状态转移流程为:S_A_GREEN -> S_A_YELLOW -> S_B_GREEN -> S_B_YELLOW -> S_A_GREEN ... 循环往复。

3 模块划分

为了设计的模块化和可复用性,将整个系统划分为以下几个子模块:

  1. 顶层模块 (traffic_light_top):

    • 功能: 连接所有子模块,作为系统的总入口。
    • 端口: 系统时钟、复位信号、紧急信号、LED灯输出、数码管输出(如果有时)。
  2. 分频器模块 (clk_divider):

    • 功能: 将FPGA开发板提供的较高频率时钟(如50MHz)分频为适合系统计时的较低频率时钟(如1Hz)。
    • 理由: 交通灯的秒级计时不需要高频时钟,分频可以降低计数器的位数和功耗。
  3. 状态控制器模块 (state_controller):

    • 功能: 系统的核心,根据当前状态和计时器的值,在满足时间条件时进行状态转移。
    • 内部逻辑: 使用always块实现状态寄存器和状态转移逻辑。case语句根据当前状态决定下一状态和输出。
  4. 计时器模块 (timer):

    • 功能: 在每个状态下进行倒计时。
    • 逻辑: 这是一个简单的计数器,当状态控制器进入一个新状态时,计时器加载该状态的预设时间,并开始递减,当计时器减到0时,向状态控制器发送一个时间到信号。
  5. LED驱动模块 (led_driver):

    • 功能: 根据当前状态,控制6个LED灯(A红、A黄、A绿、B红、B黄、B绿)的亮灭。
    • 逻辑: 这是一个组合逻辑电路,直接将状态编码转换为LED灯的控制信号。
  6. 紧急处理逻辑 (emergency_handler - 可选):

    • 功能: 当检测到紧急信号时,强制系统进入一个特殊状态(所有灯为红),并屏蔽正常的状态转移。
    • 逻辑: 可以在状态控制器中增加对紧急信号的判断,作为最高优先级的条件。
  7. 数码管显示模块 (seg_display - 可选):

    • 功能: 动态扫描显示当前状态的剩余时间。
    • 逻辑: 包含一个BCD码计数器和段选/位选信号生成逻辑。

详细Verilog代码实现

1 顶层模块 (traffic_light_top.v)

// 顶层模块:连接所有子模块
module traffic_light_top(
    input               clk,            // 系统时钟 (e.g., 50MHz)
    input               rst_n,          // 异步复位,低电平有效
    input               emergency,      // 紧急信号,高电平有效
    output reg [5:0]    led             // 6个LED灯 [A_red, A_yellow, A_green, B_red, B_yellow, B_green]
);
    // 内部信号
    wire        clk_1hz;              // 1Hz时钟,用于计时
    wire [3:0]  current_state;        // 当前状态编码
    wire        time_up;              // 计时器时间到信号
    // 实例化分频器模块
    clk_divider u_clk_divider(
        .clk_in     (clk),
        .rst_n      (rst_n),
        .clk_out    (clk_1hz)
    );
    // 实例化状态控制器模块
    state_controller u_state_controller(
        .clk        (clk_1hz),
        .rst_n      (rst_n),
        .emergency  (emergency),
        .current_state(current_state),
        .time_up    (time_up),
        .led        (led)
    );
    // 实例化计时器模块
    timer u_timer(
        .clk        (clk_1hz),
        .rst_n      (rst_n),
        .current_state(current_state),
        .time_up    (time_up)
    );
endmodule

2 状态控制器模块 (state_controller.v)

// 状态控制器:核心逻辑
module state_controller(
    input               clk,
    input               rst_n,
    input               emergency,
    input      [3:0]    current_state, // 从计时器或其他模块反馈回来的当前状态
    input               time_up,       // 计时器时间到信号
    output reg [5:0]    led            // LED控制信号
);
    // 定义状态编码 (使用独热码 One-Hot 更安全,但这里用4位二进制码节省资源)
    parameter S_A_GREEN  = 4'b0001;
    parameter S_A_YELLOW = 4'b0010;
    parameter S_B_GREEN  = 4'b0100;
    parameter S_B_YELLOW = 4'b1000;
    // 内部状态寄存器
    reg [3:0] state_reg;
    // 状态转移和输出逻辑 (同步时序逻辑)
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state_reg <= S_A_GREEN; // 复位后进入A绿灯状态
        end else if (emergency) begin
            // 紧急模式:所有灯为红
            state_reg <= 4'b0000;
            led <= 6'b100001; // A红, B红
        end else begin
            case (state_reg)
                S_A_GREEN: begin
                    if (time_up) begin
                        state_reg <= S_A_YELLOW;
                        led <= 6'b010001; // A黄, B红
                    end else begin
                        led <= 6'b001001; // A绿, B红
                    end
                end
                S_A_YELLOW: begin
                    if (time_up) begin
                        state_reg <= S_B_GREEN;
                        led <= 6'b100100; // A红, B绿
                    end else begin
                        led <= 6'b010001; // A黄, B红
                    end
                end
                S_B_GREEN: begin
                    if (time_up) begin
                        state_reg <= S_B_YELLOW;
                        led <= 6'b100010; // A红, B黄
                    end else begin
                        led <= 6'b100100; // A红, B绿
                    end
                end
                S_B_YELLOW: begin
                    if (time_up) begin
                        state_reg <= S_A_GREEN;
                        led <= 6'b001001; // A绿, B红
                    end else begin
                        led <= 6'b100010; // A红, B黄
                    end
                end
                default: begin // 包含紧急状态(4'b0000)和其他未知状态
                    state_reg <= S_A_GREEN;
                    led <= 6'b001001; // 默认回到A绿灯
                end
            endcase
        end
    end
endmodule

注意:上面的state_controller将状态寄存器和输出逻辑放在一个always块中,更紧凑,也可以将输出逻辑分离出来,形成摩尔型或米里型状态机。

3 计时器模块 (timer.v)

// 计时器模块:为每个状态倒计时
module timer(
    input               clk,
    input               rst_n,
    input      [3:0]    current_state,
    output reg          time_up
);
    // 定义各状态的持续时间 (单位:秒)
    parameter T_A_GREEN  = 30; // 主干道绿灯30秒
    parameter T_A_YELLOW = 5;  // 主干道黄灯5秒
    parameter T_B_GREEN  = 20; // 次干道绿灯20秒
    parameter T_B_YELLOW = 5;  // 次干道黄灯5秒
    reg [7:0] counter; // 8位计数器,最大可计255秒,足够用
    // 计数器逻辑
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            counter <= 8'd0;
            time_up <= 1'b0;
        end else begin
            time_up <= 1'b0; // 默认不产生时间到信号
            if (counter == 8'd1) begin // 当减到1时,下一个时钟周期就会到0
                counter <= 8'd0;
                time_up <= 1'b1; // 产生时间到脉冲
            end else begin
                counter <= counter - 1'b1;
            end
        end
    end
    // 根据当前状态加载计数值
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            counter <= 8'd0;
        end else if (time_up) begin // 当时间到信号有效时,在下一个时钟周期重新加载
            case (current_state)
                4'b0001: counter <= T_A_GREEN;  // S_A_GREEN
                4'b0010: counter <= T_A_YELLOW; // S_A_YELLOW
                4'b0100: counter <= T_B_GREEN;  // S_B_GREEN
                4'b1000: counter <= T_B_YELLOW; // S_B_YELLOW
                default: counter <= 8'd0;
            endcase
        end
    end
endmodule

4 分频器模块 (clk_divider.v)

假设系统时钟为50MHz,我们需要分频到1Hz。

  • 分频系数 N = 50,000,000
  • 计数器位数为 log2(50,000,000) ≈ 25.57,所以需要26位计数器。
  • 计数器从0数到 N/2 - 1 (24,999,999) 产生一个周期的翻转。
// 分频器模块:将50MHz分频为1Hz
module clk_divider(
    input      clk_in,
    input      rst_n,
    output reg clk_out
);
    reg [25:0] counter; // 26位计数器
    always @(posedge clk_in or negedge rst_n) begin
        if (!rst_n) begin
            counter <= 26'd0;
            clk_out <= 1'b0;
        end else if (counter == 26'd24_999_999) begin // 50MHz / 2 - 1
            counter <= 26'd0;
            clk_out <= ~clk_out; // 翻转输出
        end else begin
            counter <= counter + 1'b1;
        end
    end
endmodule

仿真与测试

  1. 仿真工具: 使用ModelSim, Vivado Simulator, Quartus Prime Simulator等。
  2. 测试平台 (tb_traffic_light.v)
    • 生成时钟信号(如50MHz)。
    • 生成复位信号,初始化系统。
    • 模拟时间的流逝(对于秒级仿真,可以加快仿真速度或将分频器模块替换成一个更快的虚拟计时器)。
    • 在不同时间点,观察led信号的输出是否符合预期。
    • 模拟emergency信号,观察系统是否立即响应。

仿真波形分析要点:

  • 复位阶段: rst_n为低时,led是否初始化为A绿, B红的状态?
  • 状态转移: 在每个状态持续设定的时间后,led是否正确转移到下一个状态?(A绿灯 -> A黄灯 -> B绿灯...)
  • 紧急模式: 在任意状态下拉高emergency,所有led是否立即变为红灯?当emergency取消后,系统是否从上一个状态继续运行(或回到初始状态,取决于设计)?

硬件实现与验证

  1. 开发环境: Vivado (Xilinx) 或 Quartus Prime (Intel/Altera)。
  2. 流程:
    • 创建工程: 新建工程,选择目标FPGA芯片型号(如Basys3开发板的XC7A35T)。
    • 代码输入: 将上述.v文件添加到工程中。
    • 综合与实现: 运行综合工具,将Verilog代码转换为网表,然后进行布局布线。
    • 生成比特流: 生成最终可下载到FPGA的.bit文件。
    • 硬件连接:
      • 将6个LED灯连接到FPGA的相应GPIO引脚(在约束文件.xdc中定义)。
      • 将一个拨码开关或按键连接到emergency信号。
      • 连接时钟和复位按键。
    • 下载与测试: 使用JTAG下载器将比特流烧录到FPGA中,观察实际硬件上的交通灯运行情况,并与仿真结果对比。

扩展功能实现思路

1 紧急车辆优先通行

已在state_controller.v中实现,只需将emergency信号作为最高优先级判断条件,当其为高时,强制state_reg进入一个特殊状态(如4'b0000),并输出A红, B红的信号。

2 倒计时显示

  1. 修改计时器模块: 计时器不再减到0就清零,而是继续减,直到0,并将计数值counter输出。
  2. 创建BCD转换模块: 将8位二进制计数器的值转换为两个4位的BCD码(十位和个位)。
  3. 创建数码管显示模块:
    • 使用动态扫描技术,快速轮流点亮4位或8位数码管,利用人眼视觉暂留效应,看起来所有数码管是同时点亮的。
    • 该模块需要接收BCD码,并生成对应的段选信号(a-g, dp)和位选信号。
  4. 顶层模块连接: 将计时器的counter值送入BCD转换模块,再将BCD码送入数码管显示模块。

3 车流量检测与动态调整

  1. 输入信号: 增加2个输入信号,模拟A、B方向的车流量传感器(sensor_A, sensor_B),高电平表示有车排队。
  2. 修改状态机逻辑:
    • S_A_GREEN状态,除了检测time_up,还检测sensor_A是否为低电平(即A方向车流已空),如果为空,则提前进入S_A_YELLOW状态。
    • S_B_GREEN状态同理。
    • 可以设置一个“最小绿灯时间”,防止绿灯时间过短。

设计总结

本设计成功利用Verilog HDL和FPGA技术,实现了一个模块化、可扩展的交通灯控制系统,通过状态机的设计,清晰地表达了交通灯的控制逻辑,整个设计流程覆盖了从方案论证、代码编写、功能仿真到硬件实现的全过程,充分体现了EDA技术在现代数字系统设计中的强大优势,通过增加扩展功能,可以进一步深化对FPGA编程和复杂系统设计的理解。

标签: 仿真建模 状态机 控制逻辑

上一篇课程与教学论是否分方向?

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!