设计要求:设计一个十字路口交通控制系统,其东西、南北两个方向除了有红、黄、绿灯指示是否允许通行外,还设有时间显示,以倒计时方式显示每一路允许通行的时间,绿灯、黄灯、红灯的持续时间分别是45、5和50秒。当东西或南北两路中任一道上出现特殊情况,例如有消防车,警车要去执行任务,此时交通控制系统应可由交警手动控制立即进入特殊运行状态,即两条道上的所有车辆皆停止通行,红灯全亮,时钟停止计时,且其数字在闪烁。当特殊运行状态结束后,管理系统恢复原来的状态,继续正常运行。
实现主干道和支干道的红绿灯,并实现时间显示功能;
实现绿灯,黄灯,红灯的持续时间固定的交通控制功能;
当东西或南北两路中任一道上出现特殊情况,交通控制系统应可由交警手动控制立即进入特殊运行状态的功能;
实现绿灯,黄灯,红灯的持续时间可调的交通控制功能;
此设计使用一个译码器。
发现了一个有意思的现象。十六进制数有着一种性质。例如8‘h52化为二进制数就是8’h0101_0010,4’h0101是十进制的5,4’h0010是十进制的2。(大佬勿喷!!!)
这为接下来的译码提供了很大的便利。因为是利用四位数码管显示。故使用一个16位的数来存储倒计数值。数码管的动态显示方面读者自行查询原理。我在此就不再详细叙述。
以下将详细讲解各个模块的代码。
1.分频模块:红绿灯的基础时钟是一秒。故先将50MHZ时钟进行分频,在连接到倒计时模块中去。分频模块代码应该是很好写的。在此也不详细叙说了。此模块中引入了R_key_set,G_key_set,Y_key_set,key.当key按下时是暂停。当检测到R_key_set,G_key_set,Y_key_set三个中任意一个上升沿将分频计数器清零(这波操作的意义我也说不清楚,读者自行理解,哈哈哈!)
2.倒计时模块:前面讲述过十六进制数的特点。在此模块中定义了一个16位的dis_num.dis_num的前八位代表一个方向的时间,后八位代表另外一个方向的时间。当复位时回到红灯50s,绿灯45s的初始状态。当检测到R_key_set,G_key_set,Y_key_set任意一个处于低电平表示此时正在调整红绿灯的倒计时时间。所以将此时调整好的值Time_red,Time_green,Time_yellow赋值给dis_num,从预定值开始倒计时。此模块中引出了两个信号S1,S2是连接进亮灯模块的。后面再说。
每个方向的倒计时都有三个状态。红灯态,绿灯态黄灯态。S1表示一个方向的状态,S2表示另一个方向状态。倒计时的设计思路还是挺简单的,每来一个1s的时钟上升沿就时间的个位减一。到了x_0的时候跳转到(x-1)_9即可。
dis_num[3:0]表示个位,[7:4]表示十位
计时到00的时候跳转到下一个亮灯状态继续倒计时就可以了
3.数码管显模块:在之前的设计中总喜欢使用1kHZ的时钟来进行数码管的动态显示。这次设计使用了另外一种思路
两种方法均可行。看读者的习惯了。
在此模块中有三种显示状态1.倒计时 2.暂停闪烁 3.时间设置
数码管的段选值取决于state的值由于上面叙说过十六进制的好处。在此时便能译出你所需要的段码。具体见下方代码。
4.time_set_key模块:此次设计使用的BASYS2开发板板子自带按键消抖所以此次设计未使用按键消抖。此次按键反应是按下有效。当按下后会产生一个20ns的尖峰脉冲。输出到时间设置模块。关于尖峰脉冲的产生方法以后会更新的。
下面的两个模块就比较简单了。就不叙述了。请读者依据代码分析。
下面是源码。亲测可以使用。
顶层模块:
module top(
clk, //clock signal
rst_n, //restoration key
key, //pause key
R_key_set, //Red light time setting key
G_key_set, //Green light time setting key
Y_key_set, //Yellow light time setting key
key_up, //time adds key
key_down, //time degradation key
light_1, //east-west direction light
light_2, //south-north direction light
sel, //Nixie tube selected
seg //Nixie tube segment
);
input clk;
input key;
input rst_n;
input key_up;
input key_down;
input R_key_set;
input G_key_set;
input Y_key_set;
output [3:0]sel;
output [7:0]seg;
output [2:0]light_1;
output [2:0]light_2;
wire clk_1s; //分频产生的1S时钟
wire [15:0]dis_num; //数码管译码
wire [7:0]Time_red; //红灯持续时间
wire [7:0]Time_green; //绿灯持续时间
wire [7:0]Time_yellow; //黄灯持续时间
wire flag_up; //时间增加按键(key_up)按下产生的尖峰脉冲
wire flag_down; //时间减少按键(key_down)按下产生的尖峰脉冲
wire [1:0]S1; //东西方向红绿灯亮灯的状态
wire [1:0]S2; //南北方向红绿灯亮灯的状态
/*****************************分频模块*****************************************/
/****************************************************************************/
div1 uut_div1(
.key(key),
.clk(clk),
.rst_n(rst_n),
.R_key_set(R_key_set),
.G_key_set(G_key_set),
.Y_key_set(Y_key_set),
.clk_1s(clk_1s)
);
/****************************************************************************/
/****************************************************************************/
/***************************正常倒计时模块**************************************/
/****************************************************************************/
normal uut_normal(
.rst_n(rst_n),
.clk_1s(clk_1s),
.key(key),
.S1(S1),
.S2(S2),
.R_key_set(R_key_set),
.G_key_set(G_key_set),
.Y_key_set(Y_key_set),
.Time_red(Time_red),
.Time_green(Time_green),
.Time_yellow(Time_yellow),
.dis_num(dis_num)
);
/****************************************************************************/
/****************************************************************************/
/**************************数码管显示模块***************************************/
/****************************************************************************/
decode uut_decode(
.clk(clk),
.rst_n(rst_n),
.key(key),
.seg(seg),
.sel(sel),
.R_key_set(R_key_set),
.G_key_set(G_key_set),
.Y_key_set(Y_key_set),
.Time_red(Time_red),
.Time_green(Time_green),
.Time_yellow(Time_yellow),
.dis_num(dis_num)
);
/****************************************************************************/
/****************************************************************************/
/****************************时间设置(加减按键)模块******************************/
/****************************************************************************/
time_set_key uut_time_set_key(
.clk(clk),
.rst_n(rst_n),
.key_up(key_up),
.key_down(key_down),
.flag_up(flag_up),
.flag_down(flag_down)
);
/****************************************************************************/
/****************************************************************************/
/**************************时间设置模块****************************************/
/****************************************************************************/
time_set uut_time_set(
.clk(clk),
.rst_n(rst_n),
.flag_up(flag_up),
.flag_down(flag_down),
.R_key_set(R_key_set),
.G_key_set(G_key_set),
.Y_key_set(Y_key_set),
.Time_red(Time_red),
.Time_green(Time_green),
.Time_yellow(Time_yellow)
);
/****************************************************************************/
/****************************************************************************/
/**************************红绿灯的亮灯模块*************************************/
/****************************************************************************/
light uut_light(
.clk(clk),
.rst_n(rst_n),
.key(key),
.S1(S1),
.S2(S2),
.light_1(light_1),
.light_2(light_2)
);
/****************************************************************************/
/****************************************************************************/
endmodule
分频模块代码:
module div1(
key,
clk,
R_key_set,
G_key_set,
Y_key_set,
rst_n,
clk_1s
);
input key;
input clk;
input rst_n;
input R_key_set;
input G_key_set;
input Y_key_set;
output reg clk_1s;
reg [27:0]cnt;
/******************************上升沿判断************************************/
/**************************************************************************/
reg R_key_set_temp;
reg G_key_set_temp;
reg Y_key_set_temp;
wire pedge;
assign pedge = ((~R_key_set_temp)&R_key_set)|((~G_key_set_temp)&G_key_set)|((~Y_key_set_temp)&Y_key_set);
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
R_key_set_temp <= 1'b0;
G_key_set_temp <= 1'b0;
Y_key_set_temp <= 1'b0;
end
else begin
R_key_set_temp <= R_key_set;
G_key_set_temp <= G_key_set;
Y_key_set_temp <= Y_key_set;
end
/**************************************************************************/
/**************************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
cnt <= 0;
clk_1s <= 0;
end
else if(!key)
cnt <= cnt;
else if(pedge)
cnt <= 0;
else begin
if(cnt < 28'd24999999)
cnt <= cnt+1'b1;
else
begin
cnt <= 0;
clk_1s <= ~clk_1s;
end
end
endmodule
倒计时模块代码:
module normal(
clk_1s,
rst_n,
key,
R_key_set,
Time_red,
G_key_set,
Time_green,
Y_key_set,
Time_yellow,
dis_num,
S1,
S2
);
input clk_1s;
input rst_n;
input key;
input R_key_set;
input [7:0]Time_red;
input G_key_set;
input [7:0]Time_green;
input Y_key_set;
input [7:0]Time_yellow;
output reg [15:0]dis_num;
output reg [1:0]S1,S2;
always@(posedge clk_1s or negedge rst_n)
begin
if(!rst_n)
begin
dis_num[7:0] <= 8'h45;
S1 <= 2'd0;
end
else if((!G_key_set)|(!R_key_set)|(!Y_key_set))begin
S1 <= 2'd0;
dis_num[7:0] <= Time_green;
end
else if(!key)
S1 <= S1;
else begin
case(S1)
2'd0:begin
dis_num[3:0] <= dis_num[3:0]-1;
if(dis_num[3:0]==4'h0)
begin
dis_num[3:0] <= 4'h9;
dis_num[7:4] <= dis_num[7:4]-1;
end
if(dis_num[7:0]==8'h0)
begin
dis_num[7:0] <= Time_yellow;
S1 <= 2'd1;
end
end
2'd1:begin
dis_num[3:0] <= dis_num[3:0]-1;
if(dis_num[3:0]==4'h0)
begin
dis_num[3:0] <= 4'h9;
dis_num[7:4] <= dis_num[7:4]-1;
end
if(dis_num[7:0]==8'h0)
begin
dis_num[7:0] <= Time_red;
S1 <= 2'd2;
end
end
2'd2:begin
dis_num[3:0] <= dis_num[3:0]-1;
if(dis_num[3:0]==4'h0)
begin
dis_num[3:0] <= 4'h9;
dis_num[7:4] <= dis_num[7:4]-1;
end
if(dis_num[7:0]==8'h0)
begin
dis_num[7:0] <= Time_green;
S1 <= 2'd0;
end
end
endcase
end
end
always@(posedge clk_1s or negedge rst_n)
if(!rst_n)
begin
dis_num[15:8] <= 8'h50;
S2 <= 2'd0;
end
else if((!G_key_set)|(!R_key_set)|(!Y_key_set))begin
S2 <= 2'd0;
dis_num[15:8] <= Time_red;
end
else if(!key)
S2 <= S2;
else begin
case(S2)
2'd0:begin
dis_num[11:8] <= dis_num[11:8]-1;
if(dis_num[11:8]==4'h0)
begin
dis_num[11:8] <= 4'h9;
dis_num[15:12] <= dis_num[15:12]-1;
end
if(dis_num[15:8]==8'h0)
begin
dis_num[15:8] <= Time_green;
S2 <= 2'd1;
end
end
2'd1:begin
dis_num[11:8] <= dis_num[11:8]-1;
if(dis_num[11:8]==4'h0)
begin
dis_num[11:8] <= 4'h9;
dis_num[15:12] <= dis_num[15:12]-1;
end
if(dis_num[15:8]==8'h0)
begin
dis_num[15:8] <= Time_yellow;
S2 <= 2'd2;
end
end
2'd2:begin
dis_num[11:8] <= dis_num[11:8]-1;
if(dis_num[11:8]==4'h0)
begin
dis_num[11:8] <= 4'h9;
dis_num[15:12] <= dis_num[15:12]-1;
end
if(dis_num[15:8]==8'h0)
begin
dis_num[15:8] <= Time_red;
S2 <= 2'd0;
end
end
endcase
end
endmodule
译码模块:
module decode(
dis_num,
clk,
rst_n,
R_key_set,
G_key_set,
Y_key_set,
Time_red,
Time_green,
Time_yellow,
seg,
key,
sel
);
input clk;
input key;//紧急按键
input rst_n;
input R_key_set;
input G_key_set;
input Y_key_set;
input [7:0]Time_green;
input [7:0]Time_red;
input [7:0]Time_yellow;
input [15:0]dis_num;
output reg [7:0]seg;
output reg [3:0]sel;
reg [3:0]state;//数据选择
reg [20:0]cnt_1;
/*****************************************************************************************************/
/*****************************************************************************************************/
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_1 <= 0;
else begin
if(cnt_1 == 21'd100000)
cnt_1 <= 21'd0;
else
cnt_1 <= cnt_1+1;
end
end
reg [24:0]cnt_flash;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_flash <= 0;
else if((cnt_flash<25'd25000000) & (!key))
cnt_flash <= cnt_flash+1'b1;
else
cnt_flash <= 25'd0;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
sel <= 4'b1111;
end
else if(!key) begin
if(cnt_flash < 25'd1250_0000)
sel <= 4'b1111;
else begin
if(cnt_1 < 21'd25000)
sel <= 4'b1110;
else if(cnt_1 < 21'd50000)
sel <= 4'b1101;
else if(cnt_1 < 21'd75000)
sel <= 4'b1011;
else if(cnt_1 < 21'd100000)
sel <= 4'b0111;
end
end
else begin
if(cnt_1 < 21'd25000)
sel <= 4'b1110;
else if(cnt_1 < 21'd50000)
sel <= 4'b1101;
else if(cnt_1 < 21'd75000)
sel <= 4'b1011;
else if(cnt_1 < 21'd100000)
sel <= 4'b0111;
end
end
/*****************************************************************************************************/
/*****************************************************************************************************/
always@(posedge clk or negedge rst_n)
if(!rst_n)
state <= 4'h0;
else if(!R_key_set)begin
if(cnt_1 < 21'd25000)
state <= 4'h0;
else if(cnt_1 < 21'd50000)
state <= 4'h0;
else if(cnt_1 < 21'd75000)
state <= Time_red[3:0];
else if(cnt_1 < 21'd100000)
state <= Time_red[7:4];
end
else if(!G_key_set)begin
if(cnt_1 < 21'd25000)
state <= 4'h0;
else if(cnt_1 < 21'd50000)
state <= 4'h0;
else if(cnt_1 < 21'd75000)
state <= Time_green[3:0];
else if(cnt_1 < 21'd100000)
state <= Time_green[7:4];
end
else if(!Y_key_set)begin
if(cnt_1 < 21'd25000)
state <= 4'h0;
else if(cnt_1 < 21'd50000)
state <= 4'h0;
else if(cnt_1 < 21'd75000)
state <= Time_yellow[3:0];
else if(cnt_1 < 21'd100000)
state <= Time_yellow[7:4];
end
else begin
if(cnt_1 < 21'd25000)
state <= dis_num[3:0];
else if(cnt_1 < 21'd50000)
state <= dis_num[7:4];
else if(cnt_1 < 21'd75000)
state <= dis_num[11:8];
else if(cnt_1 < 21'd100000)
state <= dis_num[15:12];
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
seg <= 8'b0000_0000;
else begin
case(state)
4'h0: seg <= 8'b0000_0011;
4'h1: seg <= 8'b1001_1111;
4'h2: seg <= 8'b0010_0101;
4'h3: seg <= 8'b0000_1101;
4'h4: seg <= 8'b1001_1001;
4'h5: seg <= 8'b0100_1001;
4'h6: seg <= 8'b0100_0001;
4'h7: seg <= 8'b0001_1111;
4'h8: seg <= 8'b0000_0001;
4'h9: seg <= 8'b0000_1001;
default:seg <= 8'b0000_0011;
endcase
end
end
endmodule
时间设置(按键时间加减)产生尖峰脉冲:
module time_set_key(
clk,
rst_n,
key_up,
key_down,
flag_up,
flag_down
);
input clk;
input rst_n;
input key_up;
input key_down;
output reg flag_up;
output reg flag_down;
/****************************时间增加按键尖峰**********************************/
/***************************************************************************/
reg state_up;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
state_up <= 0;
flag_up <= 0;
end
else begin
case(state_up)
0:begin
if(key_up) begin
state_up <= 1;
flag_up <= 1;
end
end
1:begin
flag_up <= 0;
if(!key_up)
state_up <= 0;
end
default:state_up <= 0;
endcase
end
/***************************************************************************/
/***************************************************************************/
/****************************时间减少按键尖峰**********************************/
/***************************************************************************/
reg state_down;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
state_down <= 0;
flag_down <= 0;
end
else begin
case(state_down)
0:begin
if(key_down) begin
state_down <= 1;
flag_down <= 1;
end
end
1:begin
flag_down <= 0;
if(!key_down)
state_down <= 0;
end
default:state_down <= 0;
endcase
end
/***************************************************************************/
/***************************************************************************/
endmodule
根据尖峰脉冲实现时间加减:
module time_set(
clk,
rst_n,
flag_up,
flag_down,
R_key_set,
G_key_set,
Y_key_set,
Time_red,
Time_green,
Time_yellow
);
input clk;
input rst_n;
input flag_up;
input flag_down;
input R_key_set;
input G_key_set;
input Y_key_set;
output reg [7:0]Time_red;
output reg [7:0]Time_green;
output reg [7:0]Time_yellow;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
Time_red <= 8'h50;
Time_green <= 8'h45;
Time_yellow <= 8'h5;
end
else if(!R_key_set)begin
if(flag_up)
begin
Time_red[3:0] <= Time_red[3:0]+1'b1;
if(Time_red[3:0]==4'h9)
begin
Time_red[3:0] <= 4'h0;
Time_red[7:4] <= Time_red[7:4]+1'b1;
end
if(Time_red == 8'h99)
Time_red <= 8'h0;
end
if(flag_down)
begin
Time_red[3:0] <= Time_red[3:0]-1'b1;
if(Time_red[3:0]==4'h0)
begin
Time_red[3:0] <= 4'h9;
Time_red[7:4] <= Time_red[7:4]-1'b1;
end
if(Time_red == 8'h0)
Time_red <= 8'h99;
end
end
else if(!G_key_set)begin
if(flag_up)
begin
Time_green[3:0] <= Time_green[3:0]+1'b1;
if(Time_green[3:0]==4'h9)
begin
Time_green[3:0] <= 4'h0;
Time_green[7:4] <= Time_green[7:4]+1'b1;
end
if(Time_green == 8'h99)
Time_green <= 8'h0;
end
if(flag_down)
begin
Time_green[3:0] <= Time_green[3:0]-1'b1;
if(Time_green[3:0]==4'h0)
begin
Time_green[3:0] <= 4'h9;
Time_green[7:4] <= Time_green[7:4]-1'b1;
end
if(Time_green == 8'h0)
Time_green <= 8'h99;
end
end
else if(!Y_key_set)begin
if(flag_up)
begin
Time_yellow[3:0] <= Time_yellow[3:0]+1'b1;
if(Time_yellow[3:0]==4'h9)
begin
Time_yellow[3:0] <= 4'h0;
Time_yellow[7:4] <= Time_yellow[7:4]+1'b1;
end
if(Time_yellow == 8'h99)
Time_yellow <= 8'h0;
end
if(flag_down)
begin
Time_yellow[3:0] <= Time_yellow[3:0]-1'b1;
if(Time_yellow[3:0]==4'h0)
begin
Time_yellow[3:0] <= 4'h9;
Time_yellow[7:4] <= Time_yellow[7:4]-1'b1;
end
if(Time_yellow == 8'h0)
Time_yellow <= 8'h99;
end
end
endmodule
红绿亮灯模块:
module light(
clk,
rst_n,
key,
S1,
S2,
light_1,
light_2
);
input clk;
input rst_n;
input key;
input [1:0]S1;
input [1:0]S2;
output reg [2:0]light_1;
output reg [2:0]light_2;
always@(posedge clk or negedge rst_n)
if(!rst_n)
light_1 <= 3'b000;
else if(!key)
light_1 <= 3'b100;
else begin
case(S1)
2'd0:light_1 <= 3'b010;
2'd1:light_1 <= 3'b001;
2'd2:light_1 <= 3'b100;
default:light_1 <= 3'b000;
endcase
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
light_2 <= 3'b000;
else if(!key)
light_2 <= 3'b100;
else begin
case(S2)
2'd0:light_2 <= 3'b100;
2'd1:light_2 <= 3'b010;
2'd2:light_2 <= 3'b001;
default:light_2 <= 3'b000;
endcase
end
endmodule