The epidemic is ruthless, the world is sentimental, Wuhan come on,
At home, do nothing, put the previous courses on the Internet, and review by the way.
Just posted the code, not too detailed, you are all smart people, you will definitely understand it all at once!
The title is like this
Signal control system design
Content and requirements:
To design an intersection traffic control system, the specific design requirements are as follows:
(1) East-west (indicated by A) and north-south (indicated by B) directions have green, yellow, and red lights, the duration of which is 40 seconds, 5 seconds and 45 seconds, respectively, the schematic diagram and timing of the switching of traffic lights The diagrams are shown in Figure 1 and Figure 2 respectively.
(2) The system is equipped with a clock to display the allowable time of each road in a countdown manner.
(3) When a special situation occurs on any one of the east-west or north-south roads, the system can be manually controlled by the traffic police to immediately enter a special operating state, that is, the red light is all on, the clock stops timing, and all vehicles on the east-west, north-south roads stop passing; when special After the running state is over, the system resumes work and continues normal operation.
Figure 2 Timing diagram of traffic lights
(4) Complete all processes: design specification documents, module design, code input, download verification, etc., and finally submit a course design report on the course design itself.
This is the timing module for traffic lights
The main thing is to complete the timing module of the traffic light, with few comments, forgive me!
module traffic_led(
input sys_clk,
input sys_rst_n,
input en, //使能标记位
output reg greenA, //LED灯
output reg greenB,
output reg redA,
output reg redB,
output reg yellowA,
output reg yellowB,
output reg [5:0] timeA,
output reg [5:0] timeB
);
//parameter NUM_MAX=26'd50_000_000; //1s延迟
parameter NUM_MAX=26'd50_000; //1ms,仿真时用的,1s太长了
parameter state0=4'b0001;
parameter state1=4'b0010;
parameter state2=4'b0100;
parameter state3=4'b1000;
reg [25:0] count; //延时1s 20ns 1000_000_000/20ns=50_000_000次
reg s_flag;//秒标记位
reg [5:0] count45; //45s延时
reg flag45; //45s标记位
reg [3:0] current_state;
reg [3:0] next_state;
//1s延时函数
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
count <=26'd0;
else if(en) begin
if(count < NUM_MAX-1'b1) begin
count <= count + 1'b1;
s_flag<=1'b0;
end
else begin
s_flag<=1'b1;
count<=26'd0;
end
end
else
count <= count;
end
//45s延时
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
count45 <=6'd45;
flag45 <=1'b0;
end
else if(en) begin
if(s_flag) begin
if(count45 == 6'b1) begin
count45 <=6'd45;
flag45 <=1'b1;
end
else begin
count45<=count45 - 1'b1;
flag45 <=1'b0;
end
end
else begin
count45 <= count45;
flag45 <= flag45;
end
end
else begin
count45 <=count45;
flag45 <=flag45;
end
end
/*这是用状态机实现的,我使用的是两段式*/
//状态的跳转(时序逻辑)
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
current_state<=state0;
else
current_state <= next_state;
end
//各个状态的下动作
always @(posedge sys_clk) begin
if(en)begin
case(current_state)
state0:begin
if(count45 == 6'd5)
next_state=state1;
else begin
greenA <=1'b0;
greenB <=1'b1;
redA <=1'b1;
redB <=1'b0;
yellowA<= 1'b1;
yellowB <=1'b1;
timeA <=count45;
timeB <=6'd0;
end
end
state1:begin
if(flag45)
next_state=state2;
else begin
greenA <=1'b1;
greenB <=1'b1;
redA <=1'b1;
redB <=1'b0;
yellowA<= 1'b0;
yellowB <=1'b1;
timeA <=count45;
timeB <=6'd0;
end
end
state2:begin
if(count45 == 6'd5)
next_state=state3;
else begin
greenA <=1'b1;
greenB <=1'b0;
redA <=1'b0;
redB <=1'b1;
yellowA<= 1'b1;
yellowB <=1'b1;
timeA <= 6'd0;
timeB <=count45;
end
end
state3:begin
if(flag45)
next_state=state0;
else begin
greenA <=1'b1;
greenB <=1'b1;
redA <=1'b0;
redB <=1'b1;
yellowA<= 1'b1;
yellowB <=1'b0;
timeA <= 6'd0;
timeB <=count45;
end
end
default:next_state=state0;
endcase
end
else begin
greenA <=1'b1;
greenB <=1'b1;
redA <=1'b0;
redB <=1'b0;
yellowA<= 1'b1;
yellowB <=1'b1;
end
end
endmodule
Digital tube display module
This code is the code of the nixie tube display module that uses the punctual atom, just a simple modification.
/*数码管显示模块*/
module seg_led(
input sys_clk , // 时钟信号
input sys_rst_n , // 复位信号
input [5:0] timeA,
input [5:0] timeB,
input [3:0] point , // 小数点具体显示的位置,从高到低,高电平有效
input en , // 数码管使能信号
input sign , // 符号位(高电平显示“-”号)
output reg [3:0] seg_sel, // 数码管位选,最左侧数码管为最高位
output reg [7:0] seg_led // 数码管段选
);
//分频参数
localparam CLK_DIVIDE=4'd10;
localparam MAX_NUM =13'd5000; //10分频,用于1ms计时
reg [3:0] clk_cnt ; // 时钟分频计数器,十分频,计数5个系统周期
reg dri_clk ; // 数码管的驱动时钟,5MHz 200ns
reg [15:0] num; //要显示的BCD数字
reg [12:0] cnt0; // 数码管驱动时钟计数器,1000_000ns/200ns=5000 13bit
reg flag; // 标志信号(标志着cnt0计数达1ms)
reg [1:0] cnt_sel ; // 数码管位选计数器
reg [3:0] num_disp ; // 当前数码管显示的数据
reg dot_disp ; // 当前数码管显示的小数点
//拆分显示
wire [3:0] data0 ; // 个位数9 4bit
wire [3:0] data1 ; // 十位数
wire [3:0] data2 ; // 百位数
wire [3:0] data3 ; // 千位数
assign data0 = timeA % 4'd10;
assign data1 = timeA /4'd10;
assign data2 = timeB % 4'd10;
assign data3 = timeB / 4'd10;
//对系统时钟10分频(1 5个系统周期 0 5个系统周期),得到的频率为5Mhz的数码管驱动时钟 200ms
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
clk_cnt <= 4'b0;
dri_clk <= 1'b1; //信号开始为1
end
else if(clk_cnt==CLK_DIVIDE/2-1'b1) begin
clk_cnt <= 4'b0;
dri_clk <= ~dri_clk;
end
else begin
clk_cnt <=clk_cnt + 1'b1;
dri_clk <= dri_clk;
end
end
//将14位2进制数转换为8421bcd码(即使用4位二进制数表示1位十进制数)
always @(posedge dri_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
num <= 16'b0;
else begin
if(!point[3]) begin
num[15:12] <= data3;
num[11:8] <= data2;
num[ 7:4] <= data1;
num[ 3:0] <= data0;
end
else begin
if(data2 || point[2]) begin
num[11:0]<={data2,data1,data0};
if(sign)
num[15:12] <= 4'd11;//d11表示负号
else
num[15:12] <= 4'd0;
end
else begin
if(data1 || point[1]) begin
num[15:12] <= 4'd10;
num[7:0]<={data1,data0};
if(sign)
num[11:8] <= 4'd11;//d11表示负号
else
num[11:8] <= 4'd0;
end
else begin
num[15:12] <= 4'd10;
num[11:8] <= 4'd10;
num[3:0]<= data0;
if(sign)
num[7:4] <= 4'd11;//d11表示负号
else
num[7:4] <= 4'd0;
end
end
end
end
end
//数码管驱动时钟,计时1ms,输出一个时钟周期的脉冲信号flag
always @ (posedge dri_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
cnt0 <=13'b0;
flag <=1'b0;
end
else if(cnt0 < MAX_NUM -1'b1) begin
cnt0 <=cnt0 + 1'b1;
flag <= 1'b0;
end
else begin
flag <= 1'b1;
cnt0 <= 1'b0;
end
end
//cnt_sel从0计数到3,用于选择当前处于显示状态的数码管
always @ (posedge dri_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_sel <= 2'b0;
else if(flag) begin
if(cnt_sel < 3)
cnt_sel=cnt_sel+1'b1;
else
cnt_sel <= 2'b0;
end
else
cnt_sel <=cnt_sel;
end
//进行循环位选
always @ (posedge dri_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
seg_sel <= 4'b1111; //位选信号低电平有效
num_disp <= 4'd10; //默认不显示
dot_disp <= 1'b1; //默认不显示小数点
end
else begin
if(en) begin
case (cnt_sel)
2'd0 :begin
seg_sel <= 4'b1110; //显示数码管最低位
num_disp <= num[3:0] ; //显示的数据
dot_disp <= ~point[0]; //显示的小数点
end
2'd1 :begin
seg_sel <= 'b1101; //显示数码管第1位
num_disp <= num[7:4] ;
dot_disp <= ~point[1];
end
2'd2 :begin
seg_sel <= 4'b1011; //显示数码管第2位
num_disp <= num[11:8];
dot_disp <= ~point[2];
end
2'd3 :begin
seg_sel <= 4'b0111; //显示数码管第3位
num_disp <= num[15:12];
dot_disp <= ~point[3];
end
default: begin
seg_sel <= 4'b1111; //位选信号低电平有效
num_disp <= 4'd10; //默认
dot_disp <= 1'b1; //默认不显示小数点
end
endcase
end
else begin
seg_sel <= 4'b1111; //位选信号低电平有效
num_disp <= 4'd10; //默认显示
dot_disp <= 1'b1; //默认不显示小数点
end
end
end
always @ (posedge dri_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
seg_led <= 8'hc0;
else begin
case(num_disp)
4'd0 : seg_led <= {dot_disp,7'b1000000}; //显示数字 0
4'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 1
4'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 2
4'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 3
4'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 4
4'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 5
4'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 6
4'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 7
4'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 8
4'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 9
4'd10: seg_led <= 8'b11111111; //不显示任何字符
4'd11: seg_led <= 8'b10111111; //显示负号(-)
default:
seg_led <={dot_disp,7'b11111111};//其他不显示
endcase
end
end
endmodule
Button delay module
Mainly used to debounce the start or stop button
module key_debounce(
input sys_clk, //外部50M时钟
input sys_rst_n, //外部复位信号,低有效
input key, //外部按键输入
output reg key_flag, //按键数据有效信号
output reg key_value //按键消抖后的数据
);
//reg define
reg [31:0] delay_cnt;
reg key_reg;
//*****************************************************
//** main code
//*****************************************************
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_reg <= 1'b1;
delay_cnt <= 32'd0;
end
else begin
key_reg <= key;
if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为20ms)
else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时
if(delay_cnt > 32'd0)
delay_cnt <= delay_cnt - 1'b1;
else
delay_cnt <= delay_cnt;
end
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_flag <= 1'b0;
key_value <= 1'b1;
end
else begin
if(delay_cnt == 32'd1) begin //当计数器递减到1时,说明按键稳定状态维持了20ms
key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
key_value <= key; //并寄存此时按键的值
end
else begin
key_flag <= 1'b0;
key_value <= key_value;
end
end
end
endmodule
Top-level module
The main realization of this module is to instantiate three modules and set a start or stop button, which is the emergency takeover button.
module trafficlight(
input sys_clk,
input sys_rst_n,
input key, //开始或停止交通灯
output greenA,
output greenB,
output redA,
output redB,
output yellowA,
output yellowB,
output [3:0] seg_sel, // 数码管位选,最左侧数码管为最高位
output [7:0] seg_led // 数码管段选
);
parameter POINT=4'd0000;
parameter SIGN=1'b0;
wire [5:0] timeA;
wire [5:0] timeB;
wire key_flag;
wire key_value;
reg en;
//开始或停止交通灯
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
en<=1'b1;
else begin
if(key_flag && (~key_value)) //判断按键是否有效按下
en<=~en;
else
en<=en;
end
end
traffic_led u_traffic_led(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.greenA(greenA),
.greenB(greenB),
.redA(redA),
.redB(redB),
.yellowA(yellowA),
.yellowB(yellowB),
.en(en),
.timeA(timeA),
.timeB(timeB)
);
seg_led u_seg_led(
.sys_clk(sys_clk) , // 时钟信号
.sys_rst_n(sys_rst_n) , // 复位信号
.timeA(timeA),
.timeB(timeB), // 6位数码管要显示的数值
.point( POINT) , // 小数点具体显示的位置,从高到低,高电平有效
.en(en) , // 数码管使能信号
.sign(SIGN) , // 符号位(高电平显示“-”号)
.seg_sel(seg_sel), // 数码管位选,最左侧数码管为最高位
.seg_led(seg_led) // 数码管段选
);
key_debounce u_key_debounce(
.sys_clk(sys_clk), //外部50M时钟
.sys_rst_n(sys_rst_n), //外部复位信号,低有效
.key(key), //外部按键输入
.key_flag(key_flag), //按键数据有效信号
.key_value(key_value) //按键消抖后的数据
);
endmodule
That's ok, simple!
Simulation diagram
The following is the simulation diagram. The simulation time is in milliseconds. One second is too long and the simulation is too troublesome.
This is the green light simulation time, 40s
This is the simulation time of the red light, 45s
This is the green light simulation time, 5s
Almost that's it