东北大学《逻辑与数字系统设计》 交通信号灯控制系统设计与Verilog实现

本文介绍了东北大学《逻辑与数字系统设计》实验中的交通信号灯控制系统设计,使用Verilog实现,并在FPGA上进行验证。实验详细描述了系统设计、计时器、状态机、输出逻辑等内容,并提供了扩展任务,增加了左转信号灯的控制逻辑。设计考虑了主道和支道的交通状况,确保了交通灯的合理切换。
摘要由CSDN通过智能技术生成

实验4  交通信号灯控制系统设计与Verilog实现

一、实验目的

  1. 掌握多位计数器的设计方法;
  2. 掌握分频电路的设计方法;
  3. 掌握控制器的设计方法;
  4. 掌握8位数码管的动态扫描显示的设计方法;
  5. 掌握FPGA的层次化设计方法。

二、实验主要仪器设备

  1. FPGA实验板。
  2. 软件为Vivado2018.3,ModelSim 10.6c

三、设计任务与要求

1. 基本任务及要求

十字路口由一条主道和支道构成。主道和支道均有红、绿、黄3种信号灯。

通常保持主道绿灯、支道红灯。只有当支道有车时,且主道计时的时间到,才转为主道红灯,支道绿灯。

绿灯转红灯过程中,先由绿灯转为黄灯,3秒钟后再由黄灯转为红灯;同时对方红灯转绿灯。

当两个方向同时有车时,红、绿灯应每隔30秒变换一次,应扣除绿灯转红灯过程中有3秒黄灯过渡,绿灯实际只亮27秒;如图1所示。

若仅一个方向有车时,处理方法是:该方向原来为红灯时,另一个方向立即由绿灯变为黄灯,3秒钟后再由黄灯变为红灯,同时本方向由红灯变为绿灯。该方向原为绿灯时,继续保持绿灯。当另一方向有车来时,作两个方向均有车处理。

图1 主道与支道信号灯与时间关系

2. 扩展任务及要求

  1. 当两个方向同时有车时,主道红、绿灯每隔30秒变换一次,支道每隔20秒变换一次。

图2主道与支道信号灯时间不相等状态图

  1. 2采用置最大时间、减计时;例如置27后每隔1秒减1
  2. 当两个方向增加左转信号灯。
  1. 主道是直行绿灯为27秒,转为黄灯3秒,再转为左转绿灯12秒,再转为黄灯3秒,所消耗的时间一共为45秒。
  2. 支道是直行绿灯为17秒,转为黄灯3秒,再转为左转绿灯7秒,再转为黄灯3秒,所消耗的时间一共为30秒。

图3 增加左转信号灯状态图

  1. 四、实验内容与步骤

1. 基本任务

(1) 系统设计

根据交通信号灯控制系统的功能,车辆传感器及交通信号灯如图1所示,具体方案如下:

  1. 在4个方向各装1个车辆传感器,有车用1表示,无车用0表示。主道(A道)分别为AS1和AS2,只要AS1或AS2中有一个为1,就说明A道有车,令AS=AS1+AS2。支道(B道)分别为BS1和BS2,只要BS1或BS2中有一个为1,就说明B道有车,令BS=BS1+BS2。
  2. 设黄灯3秒时间到时T3=1,时间未到时T3=0;设绿灯27秒时间到时,T27=1,时间未到时T27=0。
  3. 设主道由绿灯转为黄灯的条件为AK,当AK=0时绿灯继续,当AK=1时立即由绿灯转为黄灯。设支道由绿灯转为黄灯的条件为BK,当BK=0时绿灯继续,当BK=1时立即由绿灯转为黄灯。
  4. 设主道两侧的绿灯、黄灯、红灯分别为AG1、AY1、AR1,AG2、AY2、AR2;AG1、AG2,AY1、AY2,AR1、AR2分别并联,即它们同时点亮或熄灭,分别用AG、AY、AR表示。
  5. 设支道的两侧绿灯、黄灯、红灯分别为BG1、BY1、BR1,BG2、BY2、BR2。BG1、BG2,BY1、BY2,BR1、BR2分别并联,即它们同时点亮或熄灭,分别用BG、BY、BR表示。用0表示灭、1表示亮,则两个方向的交通信号灯有4种输出状态,如表1所示。

表1 交通灯输出状态

输出状态

AG

AY

AR

BG

BY

BR

S0(00)

1

0

0

0

0

1

S1(01)

0

1

0

0

0

1

S2(10)

0

0

1

1

0

0

S3(11)

0

0

1

0

1

0

图2 十字路口交通信号灯控制系统结构图

由上述分析,得到总体结构如图2所示,其中C3、C27为计数器控制信号;当C3=1时,3秒定时器,也就是3进制计数器开始计数;当C27=1时,27秒定时器,也就是27进制计数器开始计数。CP为1Hz时钟输入信号;RESET为复位信号,低有效。

(2) 各功能模块设计、仿真和调试

(a) 工作原理

本实验的目的是通过设计一个交通灯控制系统,来控制十字路口的交通信号灯,并在LCD上显示交通灯的状态。主要任务包括正常交通灯控制和根据传感器信号的变化调整交通灯状态。

1. 交通灯控制逻辑

基本任务及要求

信号灯状态定义:

主道(A)和支道(B)各有红、黄、绿三种灯光。

主道和支道信号灯的初始状态:主道绿灯亮,支道红灯亮。

当支道有车时(BS = 1),且主道计时器计时结束(T30),主道转为红灯,支道转为绿灯。

信号灯从绿灯转为红灯时,先变黄灯持续3秒,再转为红灯。黄灯期间,对方方向的红灯开始计时。

特殊处理:

当主道和支道同时有车时(AS = 1 BS = 1),红、绿灯每隔30秒变换一次,实际绿灯亮27秒,黄灯3秒。

当仅一个方向有车时,该方向原为绿灯时,保持绿灯;原为红灯时,另一方向由绿转黄3秒,再转红灯,同时当前方向转为绿灯。

2. 状态机设计

状态机使用5个状态来表示交通灯的不同状态:

S0:主道绿灯,支道红灯

S1:主道黄灯,支道红灯

S2:主道红灯,支道绿灯

S3:主道红灯,支道黄灯

S4:主道红灯,支道红灯(过渡状态)

3. 计时器设计

不同状态下使用不同的计时器:

timer_30:用于主道和支道均有车时,主道绿灯亮27秒,主道黄灯亮3秒,计时30秒。

timer_27:主道绿灯实际亮27秒。

timer_20:主道和支道同时有车时,支道计时20秒。

timer_17:支道绿灯亮17秒。

timer_3:黄灯亮3秒。

4. 主时钟分频

为了简化设计,使用一个分频器将50MHz时钟信号分频为1Hz,用于控制计时器的计时。

5. 状态转换逻辑

初始状态:进入S0,主道绿灯亮,支道红灯亮。

状态转换:

S0S1:如果BS = 1 且主道计时结束(T27T30),转到S1

S1S23秒后(T3),转到S2

S2S3:支道计时结束(T17),转到S3

S3S03秒后(T3),转到S0

S4:如果T20时间到,转到S0

6. 输出逻辑

根据当前状态,设置交通灯的输出:

S0AG = 1, AY = 0, AR = 0BG = 0, BY = 0, BR = 1(主道绿灯,支道红灯)

S1AG = 0, AY = 1, AR = 0BG = 0, BY = 0, BR = 1(主道黄灯,支道红灯)

S2AG = 0, AY = 0, AR = 1BG = 1, BY = 0, BR = 0(主道红灯,支道绿灯)

S3AG = 0, AY = 0, AR = 1BG = 0, BY = 1, BR = 0(主道红灯,支道黄灯)

S4AG = 0, AY = 0, AR = 1BG = 0, BY = 0, BR = 1(主道红灯,支道红灯)

(b) Verilog源程序


module traffic_lcd ( 

    // 50MHz 时钟输入 

    input wire clk_50M, 

    // 复位按钮 

    input wire reset_btn, 

    // A方向信号 

    input wire AS, 

    // B方向信号 

    input wire BS, 

 

    // A方向绿灯 

    output wire AG, 

    // A方向黄灯 

    output wire AY, 

    // A方向红灯 

    output wire AR, 

    // B方向绿灯 

    output wire BG, 

    // B方向黄灯 

    output wire BY, 

    // B方向红灯 

    output wire BR, 

 

    // 红色视频信号(3位) 

    output wire [2:0] video_red, 

    // 绿色视频信号(3位) 

    output wire [2:0] video_green, 

    // 蓝色视频信号(2位) 

    output wire [1:0] video_blue, 

    // 水平同步信号 

    output wire video_hsync, 

    // 垂直同步信号 

    output wire video_vsync, 

    // 视频时钟信号 

    output wire video_clk, 

    // 数据使能信号 

    output wire video_de 

); 

 

    // 主颜色信号(2位) 

    // 用于控制主方向(A或B)的灯的颜色 

    wire [1:0] maincolor; 

    // 辅助颜色信号(2位) 

    // 用于控制辅助方向(非主方向)的灯的颜色 

    wire [1:0] sidecolor; 

    // 主方向灯的持续时间(5位) 

    wire [4:0] maintime; 

    // 辅助方向灯的持续时间(5位) 

    wire [4:0] sidetime; 

 

    // 交通灯控制器实例 

    // 根据输入的时钟、复位信号、AS、BS控制主颜色、辅助颜色、主方向和辅助方向的持续时间 

    // 并输出到AG, AY, AR, BG, BY, BR 

    traffic_light_controller traffic_controller_inst ( 

        .clk(clk_50M), 

        .reset_n(~reset_btn), // 注意:这里假设traffic_light_controller使用低电平复位 

        .AS(AS), 

        .BS(BS), 

        .maincolor(maincolor), 

        .sidecolor(sidecolor), 

        .maintime(maintime), 

        .sidetime(sidetime), 

        .AG(AG), 

        .AY(AY), 

        .AR(AR), 

        .BG(BG), 

        .BY(BY), 

        .BR(BR) 

    ); 

 

    // LCD控制器实例 

    // 根据输入的时钟、复位信号、主颜色、辅助颜色、主方向和辅助方向的持续时间 

    // 控制LCD的显示,包括颜色(video_red, video_green, video_blue)和同步信号(video_hsync, video_vsync) 

    lcd_top lcd_controller_inst ( 

        .clk_50M(clk_50M), 

        .reset_btn(reset_btn), 

        .maintime(maintime), 

        .sidetime(sidetime), 

        .maincolor(maincolor), 

        .sidecolor(sidecolor), 

        .video_red(video_red), 

        .video_green(video_green), 

        .video_blue(video_blue), 

        .video_hsync(video_hsync), 

        .video_vsync(video_vsync), 

        .video_clk(video_clk), 

        .video_de(video_de) 

    ); 

 

Endmodule


module traffic_light_controller (

    input wire clk,           // 1Hz 时钟信号

    input wire reset_n,       // 复位信号,低有效

    input wire AS,            // 主道车辆传感器输入

    input wire BS,            // 支道车辆传感器输入

    output reg[1:0]maincolor, // 主道交通灯颜色:0红,1黄,2绿

    output reg[1:0]sidecolor, // 支道交通灯颜色:0红,1黄,2绿

    output reg [4:0] maintime, // 主道计时器

    output reg [4:0] sidetime, // 支道计时器

    output reg AG, AY, AR,    // 主道交通灯输出:绿,黄,红

    output reg BG, BY, BR     // 支道交通灯输出:绿,黄,红

);



    parameter S0 = 3'b000; // 主道绿灯,支道红灯

    parameter S1 = 3'b001; // 主道黄灯,支道红灯

    parameter S2 = 3'b010; // 主道红灯,支道绿灯

    parameter S3 = 3'b011; // 主道红灯,支道黄灯

    parameter S4 = 3'b100; // 主道红灯,支道红灯(过渡状态)



    // 定义变量

    reg [2:0] state, next_state; // 当前状态和下一个状态

    reg [4:0] timer_30;          // 30秒计时器

    reg [4:0] timer_27;          // 27秒计时器

    reg [4:0] timer_20;          // 20秒计时器

    reg [4:0] timer_17;          // 17秒计时器

    reg [1:0] timer_3;           // 3秒计时器

    reg [24:0] counter;          // 分频计数器

    reg clk_1Hz;                 // 1Hz 时钟信号

    wire T30 = (timer_30 == 5'd0); // 30秒时间到

    wire T27 = (timer_27 == 5'd0); // 27秒时间到

    wire T20 = (timer_20 == 5'd0); // 20秒时间到

    wire T17 = (timer_17 == 5'd0); // 17秒时间到

    wire T3 = (timer_3 == 2'd0);   // 3秒时间到



    // 初始状态

    initial begin

        maincolor <= 0;

        sidecolor <= 0;

        state <= S0;

        counter <= 0;

        clk_1Hz <= 1;

        timer_30 <= 5'd30;

        timer_27 <= 5'd27;

        timer_20 <= 5'd20;

        timer_17 <= 5'd17;

        timer_3 <= 2'd3;

    end

   

    // 分频器:50MHz -> 1Hz

    always @(posedge clk or negedge reset_n) begin

        if (!reset_n) begin

            counter <= 25'd0;

            clk_1Hz <= 1;

        end else if (counter == 25'd2) begin

            counter <= 25'd0;

            clk_1Hz <= ~clk_1Hz;  // 产生1Hz的时钟信号

        end else begin

            counter <= counter + 1;

        end

    end

   

    // 计时器逻辑

    always @(posedge clk_1Hz or negedge reset_n) begin

        if (!reset_n) begin

            timer_30 <= 5'd30;

            timer_27 <= 5'd27;

            timer_20 <= 5'd20;

            timer_17 <= 5'd17;

            timer_3 <= 2'd3;

        end else begin

            // 30秒计时器

            if (state == S2 || state == S0) begin

                if (timer_30 > 0)

                    timer_30 <= timer_30 - 1;

                else

                    timer_30 <= 5'd30;

            end else

                timer_30 <= 5'd30;



            // 27秒计时器

            if (state == S0) begin

                if (timer_27 > 0)

                    timer_27 <= timer_27 - 1;

                else

                    timer_27 <= 5'd27;

            end else

                timer_27 <= 5'd27;



            // 20秒计时器

            if (state == S4 || (state == S0 && AS && BS)) begin

                if (timer_20 > 0)

                    timer_20 <= timer_20 - 1;

                else

                    timer_20 <= 5'd20;

            end else

                timer_20 <= 5'd20;



            // 17秒计时器

            if (state == S2) begin

                if (timer_17 > 0)

                    timer_17 <= timer_17 - 1;

                else

                    timer_17 <= 5'd17;

            end else

                timer_17 <= 5'd17;



            // 3秒计时器

            if (state == S1 || state == S3) begin

                if (timer_3 > 0)

                    timer_3 <= timer_3 - 1;

                else

                    timer_3 <= 2'd3;

            end else

                timer_3 <= 2'd3;

        end

    end



    // 状态转移

    always @(posedge clk or negedge reset_n) begin

        if (!reset_n)

            state <= S0;

        else

            state <= next_state;

    end



    // 下一个状态逻辑

    always @(*) begin

        case (state)

            S0: begin

                if (AS && BS) begin

                    if (T27)

                        next_state = S1;

                    else

                        next_state = S0;

                end else if (BS && (T27 || !AS))

                    next_state = S1;

                else if (AS && BS && T27)

                    next_state = S1;

                else if (T27)

                    next_state = S1;

                else

                    next_state = S0;

            end

            S1: begin

                if (T3)

                    next_state = S2;

                else

                    next_state = S1;

            end

            S2: begin

                if (T17)

                    next_state = S3;

                else if (T30)

                    next_state = S4;

                else

                    next_state = S2;

            end

            S3: begin

                if (T3)

                    next_state = S0;

                else

                    next_state = S3;

            end

            S4: begin

                if (T20)

                    next_state = S0;

                else

                    next_state = S4;

            end

            default: next_state = S0;

        endcase

    end



    // 输出逻辑

    always @(*) begin

        case (state)

            S0: begin

                AG = 1; AY = 0; AR = 0;

                BG = 0; BY = 0; BR = 1;

                maincolor <= 2'd2;

                sidecolor <= 2'd0;

                maintime <= (AS && BS) ? timer_27 : timer_30;

                sidetime <= timer_30;

            end

            S1: begin

                AG = 0; AY = 1; AR = 0;

                BG = 0; BY = 0; BR = 1;

                maincolor <= 2'd1;

                sidecolor <= 2'd0;

                maintime <= timer_3;

                sidetime <= timer_30;

            end

            S2: begin

                AG = 0; AY = 0; AR = 1;

                BG = 1; BY = 0; BR = 0;

                maincolor <= 2'd0;

                sidecolor <= 2'd2;

                maintime <= timer_30;

                sidetime <= timer_17;

            end

            S3: begin

                AG = 0; AY = 0; AR = 1;

                BG = 0; BY = 1; BR = 0;

                maincolor <= 2'd0;

                sidecolor <= 2'd1;

                maintime <= timer_30;

                sidetime <= timer_3;

            end

            S4: begin

                AG = 0; AY = 0; AR = 1;

                BG = 0; BY = 0; BR = 1;

                maincolor <= 2'd0;

                sidecolor <= 2'd0;

                maintime <= timer_20;

                sidetime <= timer_30;

            end

            default: begin

                AG = 1; AY = 0; AR = 0;

                BG = 0; BY = 0; BR = 1;

            end

        endcase

    end

endmodule


module lcd_top (

    input wire clk_50M,     //50MHz 閺冨爼鎸撴潏鎾冲弳



    input wire reset_btn,  //BTN6閹靛濮╂径宥勭秴閹稿鎸冲?閸忕绱濈敮锔界Х閹舵牜鏁哥捄顖ょ礉閹稿绗呴弮鏈佃礋1

    input wire [4:0] maintime,

    input wire [4:0] sidetime,

    input wire [1:0]maincolor,

    input wire [1:0]sidecolor,

    //閸ユ儳鍎氭潏鎾冲毉娣団?冲娇

    output wire [2:0] video_red,    //缁俱垼澹婇崓蹇曠閿??3娴??

    output wire [2:0] video_green,  //缂佽儻澹婇崓蹇曠閿??3娴??

    output wire [1:0] video_blue,   //閽冩繆澹婇崓蹇曠閿??2娴??

    output wire       video_hsync,  //鐞涘苯鎮撳銉礄濮樻潙閽╅崥灞绢劄閿涘淇婇崣?

    output wire       video_vsync,  //閸﹀搫鎮撳銉礄閸ㄥ倻娲块崥灞绢劄閿涘淇婇崣?

    output wire       video_clk,    //閸嶅繒绀岄弮鍫曟寭鏉堟挸鍤?

    output wire       video_de      //鐞涘本鏆熼幑顔芥箒閺佸牅淇婇崣鍑ょ礉閻€劋绨崠鍝勫瀻濞戝牓娈i崠?

);

  // generate pixel clock

  logic clk_pix;

  logic clk_pix_locked;





  clock_divider clock_div_inst (

      .clk(clk_50M),

      .rst(reset_btn),

      .clk_div(clk_pix)

  );

    wire [15:0] line_2_ascii;





  wire [7:0]main_bcd;

  wire [7:0]side_bcd;

 

  bin2bcd m(

      .bin(maintime),

      .bcd(main_bcd)

  );

 

  bin2bcd s(

      .bin(sidetime),

      .bcd(side_bcd)

  );



  wire [79:0] line_0; // 娑撹桨绨¢弬閫涚┒鐠у?纭风礉娑??娑撶寴scii閸楃姷鏁?8bit

  wire [79:0] line_1; // 56-bit line buffer, 7 bit per ascii character



         assign line_0 = (maincolor==0)?{8'h20,main_bcd[7:4]+8'h30,main_bcd[3:0]+8'h30,8'h20,8'h20,8'h20,8'h20,8'h20}

                          :(maincolor==1)?{8'h20,8'h20,8'h20,main_bcd[7:4]+8'h30,main_bcd[3:0]+8'h30,8'h20,8'h20,8'h20}

                          :{8'h20,8'h20,8'h20,8'h20,8'h20,main_bcd[7:4]+8'h30,main_bcd[3:0]+8'h30,8'h20};



        

          assign line_1 = (sidecolor==0)?{8'h20,side_bcd[7:4]+8'h30,side_bcd[3:0]+8'h30,8'h20,8'h20,8'h20,8'h20,8'h20}

                          :(sidecolor==1)?{8'h20,8'h20,8'h20,side_bcd[7:4]+8'h30,side_bcd[3:0]+8'h30,8'h20,8'h20,8'h20}

                          :{8'h20,8'h20,8'h20,8'h20,8'h20,side_bcd[7:4]+8'h30,side_bcd[3:0]+8'h30,8'h20};





reg [25:0] counter; // 璁℃暟鍣紝鐢ㄤ簬璁℃暟50,000,000涓椂閽熷懆鏈?

reg [5:0] number;

wire cnt_eq_1s;

assign cnt_eq_1s= counter==(4999_9999);

always @(posedge clk_50M or posedge reset_btn)

begin

    if (reset_btn)

    begin

        counter <= 26'd0; // 閲嶇疆璁℃暟鍣?

        number <= 6'd0;   // 閲嶇疆number

    end

    else if (counter == 26'd49_999_999) // 妫?鏌ヨ鏁板櫒鏄惁鍒拌揪50,000,000

    begin

        counter <= 26'd0; // 閲嶇疆璁℃暟鍣?

        number <= number + 6'd1; // number鍔?1

    end

    else

    begin

        counter <= counter + 26'd1; // 璁℃暟鍣ㄥ姞1

    end

end



dvi_module dvi_inst (

      .clk(clk_pix),

      .clk_locked(reset_btn),

      .maincolor(maincolor),

      .sidecolor(sidecolor),

      .video_red(video_red),

      .video_green(video_green),

      .video_blue(video_blue),

      .video_hsync(video_hsync),

      .video_vsync(video_vsync),

      .video_clk(video_clk),

      .video_de(video_de),

      .line_0_ascii(line_0),

      .line_1_ascii(line_1),

      .line_2_number(number)

  );





reg [7:0] ascii;

always @(posedge clk_50M)

begin

    if (reset_btn)

    begin

        ascii <= 8'd0;

    end

    else if (cnt_eq_1s)

    begin

        if (ascii == 8'd9)

        begin

            ascii <= 8'd0;

        end

        else

        begin

            ascii <= ascii + 1'b1;

        end

    end

end







endmodule
module ascii_rom_async (

    input  wire  [10:0] addr,

    output reg   [7:0] data

);



always @(*) begin

    case (addr)

        // code x30 (0)

                     11'h300: data = 8'b00000000; //

                  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值