La epidemia es despiadada, el mundo es sentimental, vamos Wuhan,
En casa, no hagas nada, pon los cursos anteriores en Internet, y repasa por cierto.
Acabo de publicar el código, no demasiado detallado, todos ustedes son personas inteligentes, ¡definitivamente lo entenderán todo a la vez!
El titulo es asi
Diseño del sistema de control de señales
Contenido y requisitos:
Para diseñar un sistema de control de tráfico en una intersección, los requisitos de diseño específicos son los siguientes:
(1) Las direcciones este-oeste (indicadas por A) y norte-sur (indicadas por B) tienen luces verdes, amarillas y rojas, cuya duración es de 40 segundos, 5 segundos y 45 segundos, respectivamente. Diagrama de cambio de semáforo y sincronización Los diagramas se muestran en la Figura 1 y la Figura 2 respectivamente.
(2) El sistema está equipado con un reloj para mostrar el tiempo permitido de cada camino en forma de cuenta regresiva.
(3) Cuando ocurre una situación especial en cualquiera de las carreteras este-oeste o norte-sur, el sistema puede ser controlado manualmente por la policía de tránsito para ingresar inmediatamente a un estado operativo especial, es decir, la luz roja está encendida, el reloj detiene el cronometraje y todos los vehículos en las carreteras este-oeste, sur-norte dejan de pasar; una vez finalizado el estado de funcionamiento, el sistema reanuda el trabajo y continúa con el funcionamiento normal.
Figura 2 Diagrama de tiempos de los semáforos
(4) Complete todos los procesos: documentos de especificación de diseño, diseño de módulo, entrada de código, verificación de descarga, etc., y finalmente envíe un informe de diseño del curso sobre el diseño del curso en sí.
Este es el módulo de cronometraje para semáforos.
Lo principal es completar el módulo de cronometraje del semáforo, con pocos comentarios, ¡perdóname!
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
Módulo de pantalla de tubo digital
Este código es el código del módulo de visualización del tubo nixie que usa el átomo puntual, solo una simple modificación.
/*数码管显示模块*/
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
Módulo de retardo de botón
Se utiliza principalmente para eliminar el rebote del botón de inicio o parada.
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
Módulo de nivel superior
La principal realización de este módulo es crear una instancia de tres módulos y establecer un botón de inicio o parada, que es el botón de toma de control de emergencia.
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
¡Está bien, simple!
Diagrama de simulación
El siguiente es el diagrama de simulación. El tiempo de simulación está en milisegundos. Un segundo es demasiado largo y la simulación es demasiado problemática.
Este es el tiempo de simulación de luz verde, 40 s.
Este es el tiempo de simulación de la luz roja, 45 s.
Este es el tiempo de simulación de luz verde, 5 s.
Casi eso es todo