十字路口交通信号灯控制系统

十字路口交通信号灯控制系统

  • 主要任务
  • 开发平台
  • 时序分析
  • 电路原理图
  • 设计思路
    • 主控制器模块
    • 分频计数器模块
    • 定时器模块
    • 译码模块
  • 实现
    • 主控制模块
    • 分频计数器
    • 定时计数器
    • 译码模块
    • TOP模块
    • 仿真测试文件
    • 设计约束文件
  • 测试结果
    • 仿真测试结果
    • 云平台运行结果
  • 观看效果

主要任务

  • 设计一个用于十字路口的交通灯控制器,能显示十字路口东西、南北两个方向的红、黄、绿的指示状态;
  • 具有倒计时的功能,用两组数码管作为东西和南北方向的倒计时显示,主干道直行(绿灯)60秒后,左转(绿灯)40秒;支干道直行(绿灯)45秒后,左转(绿灯)30秒,在每次绿灯变成红灯的转换过程中,要亮黄灯5秒作为过渡。黄灯每秒闪亮一次。
  • 只考虑直行和左转车辆控制信号灯,右转车辆不受信号灯控制, 南北向车辆与东西向车辆交替方向,同方向等待车辆应先方向直行车辆而后放行左转车辆。

开发平台

系统开发工具 Vivado
系统开发语言 Verilog
仿真平台 杰创EDA远程二代网页版

时序分析

首先弄清楚主干路和支干路在一个周期内的变化状况,如图所示:
十字路口交通信号灯控制系统_第1张图片
十字路口交通信号灯控制系统_第2张图片

电路原理图

此电路原理图是在杰创EDA远程二代网页版上进行绘制的,如图所示十字路口交通信号灯控制系统_第3张图片

设计思路

交通信号灯系统控制的原理框图如图所示,将系统分成4个模块:

  1. 主控制器模块
  2. 定时计数器模块
  3. 分频计数器模块
  4. 译码模块

十字路口交通信号灯控制系统_第4张图片

主控制器模块

主控制器模块原理上是一个状态机,依据要求设计,设计出信号灯点亮规律的状态转换表,如表所示,其中0表示灭,1表示亮,状态表显示了信号灯在运行过程中每个状态应该持续的时间,以及状态之间的转换顺序。依据分频计数器,当分频计数器的时钟达到了对应时间则切换为下一个状态,就可以实现控制信号灯的亮灭。
十字路口交通信号灯控制系统_第5张图片

图中有八个状态,实际编程的时候还应该符加四个状态,用于表示黄灯的闪烁,这四个状态对应黄灯为0,表示黄灯熄灭,1s切换一次状态就可以达到黄灯每秒闪烁一次的效果,符加状态如下表所示:十字路口交通信号灯控制系统_第6张图片

分频计数器模块

整个系统采用的时钟是1khz,原因是为了显示四位数码管上多位数字,而信号灯的状态切换是以秒为单位进行的,因此需要将1khz的时钟信号转化成1hz的,设计分频计数器,每500个周期,分频时钟信号反转一次。

定时器模块

状态机上共有8个状态,以这8个状态为周期进行循环,系统执行一个周期共计需要195秒,因此设计定时计数器进行计数,定时到195秒时就归零重新计时。

译码模块

在讲译码模块之前,先讲一讲四位数码管如何使用,七段数码管是电子开发过程中常用的输出显示设备,本项目使用的是一个四八位一体,共阴极型七段数码管。右图是本实验用到的四八位一体,共阴极型,左图为单个静态数码管。

十字路口交通信号灯控制系统_第7张图片十字路口交通信号灯控制系统_第8张图片
由于此设计七段数码管公共端连接到GND(共阴极型),当数码管的中的那一个段(a,b,c,d,e,f,g)被输入高电平,则相应的这一段被点亮。反之则不亮。四位一体的七段数码管在单个静态数码管的基础上加入了用于选择哪一位数码管的位选信号(1,2,3,4)端口。四个数码管的a,b,c,d,e,f,g,h,dp都连接在了一起,4个数码管分别由各自的 位选信号来控制,当位选信号为低电平时该位数码管被选择。同一时刻只有一位数码管被选中并点亮,下一时刻则切换到相邻位数码管,但因为切换速度很快,在视觉暂留效应的帮助下,我们看到的就是四位数码管被整体点亮

为此可以设计出每个数字的译码表,如表所示

数字 十六进制下编码
0 7’h7e
1 7’h30
2 7’h6d
3 7’h79
4 7‘h33
5 7’h5b
6 7’h5f
7 7’h70
8 7’h7f
9 7’h7b

输出数据的时候,在管脚上输出相应的编码,控制时钟以快速频率切换就可以实现显示两位数字效果。默认使用两位数字来显示倒计时,有红灯倒计时大于99秒的情况,也就是超出两位数字所表示的范围,规定超过99秒则不显示

源码免费下载链接

实现

主控制模块

module traffic_light (
    clk,
	rst_n,
	count,
	ew,
	sn
);
input clk,rst_n;
input [7:0] count;
output [5:0] ew,sn; 
reg [5:0] ew,sn;
reg [3:0] pre_state,next_state;
reg [12:0] counter=13'b0;
reg clk_5hz=1'b0;

parameter 
S0=4'b0000,   //主干路四个状态
S1=4'b0001,
S2=4'b0010,
S3=4'b0011,

S4=4'b0100,   //支干路四个状态
S5=4'b0101,
S6=4'b0110,
S7=4'b0111,

S8=4'b1000,   //主干路直行黄灯
S9=4'b1001,   //主干路左转黄灯
S10=4'b1010,  //支干路直行黄灯
S11=4'b1011;  //支干路左转黄灯

always @ (negedge clk or negedge rst_n) 
begin
    if(!rst_n)
        pre_state<=S0;
    else
    	pre_state<=next_state;
end

always @ (negedge clk) begin          //这段代码是用来实现黄灯的闪烁功能
   if(count>=60&&count<65)
        begin
        counter <=counter+1'b1;      
        if (counter == 'd499)begin     //计数,形成0.5秒的时钟
        clk_5hz <= !clk_5hz;
        counter <= 'd0;
        end   
    end 

    else if(count>=105&&count<110)
        begin
        counter <=counter+1'b1;
        if (counter == 'd499)begin
        clk_5hz <= !clk_5hz;
        counter <= 'd0;
        end
    end  

    else if(count>=155&&count<160)
        begin
        counter <=counter+1'b1;
        if (counter == 'd499)begin
        clk_5hz <= !clk_5hz;
        counter <= 'd0;
        end
    end

    else if(count>=190&&count<195)
        begin
        counter <=counter+1'b1;
        if (counter == 'd499)begin
        clk_5hz <= !clk_5hz;
        counter <= 'd0;
        end
    end        
    else     
       counter <='d0;                        
end

always @ (clk or pre_state) 
begin
    next_state<=3'bxxx;    
    if(count>=60 && count<65) begin               //主干路直行黄灯
        if(clk_5hz) next_state<=S8;
        else
            next_state <=S1; end              
    else if(count==8'd65)                        //主干路左转绿灯
        next_state<=S2;   
    else if(count>=8'd105 && count<8'd110)begin    //主干路左转黄灯
        if(clk_5hz) next_state <=S9;
        else
            next_state<=S3;end
    else if (count==8'd110)                        //支干路直行绿灯
        next_state<=S4;    
    else if (count>=8'd155 && count<8'd160)begin   //支干路直行黄灯
        if(clk_5hz) next_state <=S10;
        else
            next_state<=S5;end
    else if (count==8'd160)                        //支干路左转绿灯
        next_state<=S6;
    else if (count>=8'd190 && count<8'd195)begin   //支干路左转黄的
        if(clk_5hz) next_state <=S11;   
        else
            next_state<=S7;end 
    else if (count == 0)                      //主干路直行绿灯
        next_state<=S0;                 
    else    next_state <=pre_state; 
end

always @ (pre_state) 
begin
    case (pre_state)                            //状态编码
                
        S0:begin ew<=6'b001100;sn<=6'b001001;end
        
        S1:begin ew<=6'b001010;sn<=6'b001001;end

        S2:begin ew<=6'b100001;sn<=6'b001001;end

        S3:begin ew<=6'b010001;sn<=6'b001001;end

        S4:begin ew<=6'b001001;sn<=6'b001100;end

        S5:begin ew<=6'b001001;sn<=6'b001010;end

        S6:begin ew<=6'b001001;sn<=6'b100001;end

        S7:begin ew<=6'b001001;sn<=6'b010001;end

        S8:begin ew<=6'b001000;sn<=6'b001001;end       

        S9:begin ew<=6'b000001;sn<=6'b001001;end

        S10:begin ew<=6'b001001;sn<=6'b001000;end

        S11:begin ew<=6'b001001;sn<=6'b000001;end

        default:begin ew<=6'b001100;sn<=6'b001001;end
    endcase
        
end

endmodule

分频计数器

module countdiv (
	clk,
	rst_n,
	clk_1hz
);

input clk,rst_n;
output clk_1hz;
reg clk_1hz=1'b0;
reg [12:0] count_clk=13'b0;
always @ (negedge clk) begin       //监听时钟下降沿
     count_clk <= count_clk + 1'b1; 
     if(count_clk == 'd499)begin      //当计数器为449时,进行信号翻转   
     clk_1hz <= !clk_1hz;
     count_clk <= 'd0;                //计数器归零
     end
end
endmodule

定时计数器

module counter (
	clk,
	rst_n,
	out,
	en
);

input clk,rst_n,en;
output [7:0] out;
reg [7:0] out;

always @ (negedge clk or negedge rst_n)   //监听1hz的时钟信号
begin
    if (!rst_n)                           //初始化为0
        out<=8'd0;
    else if(!en)
        out<=out;
    else if(out==8'd194)                  //当值为194时,下一个                                          
    	out<=8'd0;                        //时钟下降沿到来置为0
    else
    	out<=out+1'b1; 			          //增1计数
end
    
endmodule

译码模块

module tubeControl (
	clk,          //1khz时钟
    clk_1hz,      //1hz时钟
	rst_n,        //复位
	count,        //计数时间
	out_main,     //主干路a、b、c、d、e、f、g输出
    out_minor,    //支干路a、b、c、d、e、f、g输出
	sel_main,     //主干路片选信号
    sel_minor    //支干路片选信号
);


input clk,rst_n;
input clk_1hz;
input [7:0] count;

output [6:0] out_main;
output [6:0] out_minor;

output [1:0] sel_main;
output [1:0] sel_minor;

reg [1:0] sel_main;
reg [1:0] sel_minor;

reg [6:0] out_main;
reg [6:0] out_minor;

reg [6:0] num_main;
reg [6:0] num_minor;

reg [3:0] main_second=4'd10;
reg [3:0] main_minute=4'd10;

reg [3:0] minor_second=4'd10;
reg [3:0] minor_minute=4'd10;

reg [3:0] cnt_main;
reg [3:0] cnt_minor;  

//译码表
parameter   NUM_0=7'h7e;
parameter   NUM_1=7'h30;
parameter   NUM_2=7'h6d;
parameter   NUM_3=7'h79;
parameter   NUM_4=7'h33;
parameter   NUM_5=7'h5b;
parameter   NUM_6=7'h5f;
parameter   NUM_7=7'h70;
parameter   NUM_8=7'h7f ;
parameter   NUM_9=7'h7b;
parameter   NUM_10=7'h00;          //这里表示不显示的译码

always @ (negedge clk) 
begin
    if(!rst_n)
        num_main<='d0;
    else if(count <= 8'd59)     //主干路直行绿灯倒计时
        num_main<=60-count;     
    else if(count<=8'd64)       //主干路直行黄灯倒计时
        num_main<=65-count;
    else if(count<=8'd 104)      //主干路左转绿灯倒计时
        num_main<=105-count;
    else if (count<=8'd109)      //主干路左转黄灯倒计时 	   
        num_main<=110-count; 
    else if(count<=8'd194)       //其他情况下红灯倒计时
        num_main<=195-count;
                        
end

always @ (negedge clk) 
begin
    if(!rst_n)
        num_minor<='d0;
    else if(count<=8'd109)        //其他情况下红灯倒计时
        num_minor<=110-count;
    else if(count<=8'd154)        //支干路直行绿灯倒计时
        num_minor<=155-count;    
    else if(count<=8'd159)        //支干路直行黄灯倒计时
        num_minor<=160-count;
    else if(count<=8'd189)       //支干路左转绿灯倒计时
        num_minor<=190-count;
    else if(count<=8'd194)       //支干路左转黄灯倒计时
        num_minor<=195-count;
end

always @ (num_minor) 
begin
    if(num_minor==0)begin        //初始化
        minor_second<=10;
        minor_minute<=10;end
    else if(num_minor>99)begin   //倒计时值大于99时,不显示
        minor_second<=10;
        minor_minute<=10;end
    else
        begin
        minor_second<=num_minor%10;     //计算倒计时时间
        minor_minute<=num_minor/10;
        end     
end

always @ (num_main) begin
    if(num_main==0)begin        //初始化
        main_second<=10;
        main_minute<=10;end
    else if(num_main>99)begin   //倒计时值大于99时,不显示
        main_minute<=10;
        main_second<=10;end
    else
        begin
        main_minute<=num_main/10;
        main_second<=num_main%10;
        end       
end



always @ (*) begin
    case(sel_main)        //主干路片选控制
        2'b10:cnt_main <= main_second;
        2'b01:cnt_main <= main_minute; 
   endcase
end

always @ (*) begin
    case(sel_minor)       //支干路片选控制
        2'b10:cnt_minor <= minor_second;
        2'b01:cnt_minor <= minor_minute; 
   endcase
end

always @ (*)                //译码
    case (cnt_main) 
        0: out_main=NUM_0;
        1: out_main=NUM_1;
        2: out_main=NUM_2;
        3: out_main=NUM_3;
        4: out_main=NUM_4;
        5: out_main=NUM_5;
        6: out_main=NUM_6;
        7: out_main=NUM_7;
        8: out_main=NUM_8;
        9: out_main=NUM_9;
        10:out_main=NUM_10;    
    endcase      

always @ (*)
    case (cnt_minor) 
        0: out_minor=NUM_0;
        1: out_minor=NUM_1;
        2: out_minor=NUM_2;
        3: out_minor=NUM_3;
        4: out_minor=NUM_4;
        5: out_minor=NUM_5;
        6: out_minor=NUM_6;
        7: out_minor=NUM_7;
        8: out_minor=NUM_8;
        9: out_minor=NUM_9;
        10:out_minor=NUM_10;
    endcase  

always @ (posedge clk,negedge rst_n)    //高频率切换片选管脚
begin                                   //达到显示两位数效果
    if(!rst_n)  
        sel_main<=2'b10;
    else
        sel_main<={sel_main[0],sel_main[1]};
end 

always @ (posedge clk,negedge rst_n) 
begin      
    if(!rst_n)  
        sel_minor<=2'b10;
    else
        sel_minor<={sel_minor[0],sel_minor[1]};
end

endmodule


TOP模块

module top (
	clk,
	rst_n,
	en,
	ew,
	sn,
	out_main,
	out_minor,
	sel_main,
	sel_minor
);
input clk,rst_n,en;
output [5:0] ew,sn;
wire [7:0] count;
wire [5:0] ew,sn;
output out_main;
output out_minor;
output [1:0] sel_main;
output [1:0] sel_minor;
wire [6:0] out_main;
wire [6:0] out_minor;
wire clk_1hz;

countdiv U0(         //分频计数器模块
    .clk(clk),
    .rst_n(rst_n),
    .clk_1hz(clk_1hz));


counter U1(          //时钟计数器模块
	.clk(clk_1hz),
	.rst_n(rst_n),
	.out(count),
	.en(en));

traffic_light U2(    //主控制器模块
	.clk(clk),
	.rst_n(rst_n),
	.count(count),
	.ew(ew),
	.sn(sn));
tubeControl U3(      //数码管译码模块
	.clk(clk),
    .clk_1hz(clk_1hz),
    .rst_n(rst_n),
    .count(count),
   .out_main(out_main),
    .out_minor(out_minor),
    .sel_main(sel_main),
    .sel_minor(sel_minor));   	
endmodule

仿真测试文件

module top_tb;
reg clk,rst_n,en;
wire [5:0] ew,sn;
wire [6:0] out_main;
wire [6:0] out_minor;
wire [1:0] sel_main;
wire [1:0] sel_minor;
top U1(
	.clk(clk),
	.rst_n(rst_n),
	.en(en),
	.ew(ew),
	.sn(sn),
	.out_main(out_main),
	.out_minor(out_minor),
	.sel_main(sel_main),
	.sel_minor(sel_minor));

initial
begin
    clk<=1'd0;
    forever #500 clk=~clk;        //仿真一个1khz的时钟信号
end

initial
begin
    rst_n=1'b1;                    //初始化参数
    en=1'b0;
    #1 rst_n=1'b0;
    #1 rst_n=1'b1;en=1'b1;

end

endmodule

设计约束文件

set_property PACKAGE_PIN E3 [get_ports clk]
set_property PACKAGE_PIN K5 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports {sn[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sn[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sn[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ew[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ew[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ew[0]}]

set_property PACKAGE_PIN B9 [get_ports en]
set_property IOSTANDARD LVCMOS33 [get_ports en]

t_property IOSTANDARD LVCMOS33 [get_ports {out_main[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_main[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_main[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_main[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_main[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_main[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_main[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {out_minor[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel_main[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel_main[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel_minor[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel_minor[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {ew[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ew[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ew[3]}]
set_property PACKAGE_PIN M14 [get_ports {ew[4]}]
set_property PACKAGE_PIN L14 [get_ports {ew[5]}]
set_property PACKAGE_PIN K13 [get_ports {ew[1]}]
set_property PACKAGE_PIN M15 [get_ports {ew[2]}]
set_property PACKAGE_PIN T9 [get_ports {sn[4]}]
set_property PACKAGE_PIN L12 [get_ports {sn[5]}]
set_property PACKAGE_PIN D5 [get_ports {sn[1]}]
set_property PACKAGE_PIN D6 [get_ports {sn[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sn[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sn[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sn[3]}]
set_property PACKAGE_PIN D3 [get_ports {out_main[6]}]
set_property PACKAGE_PIN C4 [get_ports {out_main[5]}]
set_property PACKAGE_PIN D16 [get_ports {out_main[4]}]
set_property PACKAGE_PIN C7 [get_ports {out_main[3]}]
set_property PACKAGE_PIN D8 [get_ports {out_main[2]}]
set_property PACKAGE_PIN A12 [get_ports {out_main[1]}]
set_property PACKAGE_PIN D9 [get_ports {out_main[0]}]
set_property PACKAGE_PIN E12 [get_ports {sel_main[1]}]
set_property PACKAGE_PIN E13 [get_ports {sel_main[0]}]
set_property PACKAGE_PIN E11 [get_ports {out_minor[6]}]
set_property PACKAGE_PIN T10 [get_ports {out_minor[5]}]
set_property PACKAGE_PIN R5 [get_ports {out_minor[4]}]
set_property PACKAGE_PIN T5 [get_ports {out_minor[3]}]
set_property PACKAGE_PIN R6 [get_ports {out_minor[2]}]
set_property PACKAGE_PIN R7 [get_ports {out_minor[1]}]
set_property PACKAGE_PIN D14 [get_ports {out_minor[0]}]
set_property PACKAGE_PIN D15 [get_ports {sel_minor[1]}]
set_property PACKAGE_PIN F12 [get_ports {sel_minor[0]}]

set_property PACKAGE_PIN L15 [get_ports {ew[3]}]
set_property PACKAGE_PIN L13 [get_ports {ew[0]}]
set_property PACKAGE_PIN C6 [get_ports {sn[3]}]
set_property PACKAGE_PIN A2 [get_ports {sn[0]}]


测试结果

仿真测试结果

此测试很重要,如果没有云平台进行测试只能进行仿真,仿真文件如上所示,时间单位为1us,每500us进行时钟信号反转就形成了1khz的时钟信号。
仿真结果如图所示,宏观上看首先测试信号灯是否显示正确,观察ew(表示主干路方向),sn(表示支干路方向)两个值
十字路口交通信号灯控制系统_第9张图片再观察微观测试结果,截取了一个有代表意义的片段60秒至65秒,这段时间主干路直行黄灯正在闪烁,对应ew的值在0a和08之间变换,由状态表知是在S1状态和S8状态之间切换,每1秒切换一次,一次持续0.5秒,实现了黄灯的闪烁。
十字路口交通信号灯控制系统_第10张图片

再来观察数码管的仿真结果,截取了一个有意义的片段60秒到65秒,60秒是状态S0和S1的交界处,容易出错。系统采用的共阴极4位数码管,片选信号0表示有效,1表示无效,所以片选信号1表示十位,片选2表示个位根据译码表知,60秒前是7e 30代表01秒,是直行绿灯最后一秒倒计时;60秒后倒计时是7e 5b代表05秒,表示黄灯5秒倒计时的开始。
十字路口交通信号灯控制系统_第11张图片
195秒时仿真结果,195秒后重新开始循环。
十字路口交通信号灯控制系统_第12张图片

云平台运行结果

通常情况仿真结果正确就已经完成了,这里提供云平台的运行结果,仅用来观察系统运行结果,

十字路口交通信号灯控制系统_第13张图片

十字路口交通信号灯控制系统_第14张图片
十字路口交通信号灯控制系统_第15张图片
十字路口交通信号灯控制系统_第16张图片
十字路口交通信号灯控制系统_第17张图片
十字路口交通信号灯控制系统_第18张图片
十字路口交通信号灯控制系统_第19张图片
十字路口交通信号灯控制系统_第20张图片

观看效果

视频展示效果
观看效果

如果有不清楚的地方欢迎留言评论
第一次写文章,欢迎大家交流,批评。

你可能感兴趣的:(十字路口交通信号灯控制系统,经验分享,verilog)