Diseño EDA (verilog) - reloj de tubo de siete segmentos

Descripción del título: Temporizador: muestra las horas (0-23 u 11), minutos (0-59) y segundos (0-59) en 6 tubos de siete segmentos, cada uno de los cuales ocupa 2 tubos. El reloj externo es de 50Mhz. Puede usar el botón para generar una tecla de señal de reinicio, cuando el botón se presiona inmediatamente (asincrónicamente), el tiempo se reinicia a 0 horas, 0 minutos y 0 segundos para reiniciar el tiempo.

1. Análisis de preguntas:

Análisis 1 : ¿Cómo realizar esta función?
    Necesitamos 6 registros de 7 bits (o un registro de 7 * 6 = 42 bits) para retener el tiempo de cada momento La visualización de los 4 contadores de "segundos" y "minutos" corresponde a un contador hexadecimal de 60. Módulo y "hora" corresponde a un contador de 24 bits.

Análisis 2 : ¿Cómo lograr un cambio cada segundo?
    De acuerdo con el reloj externo del sistema de 50 MHz, podemos escribir un contador, que registrará cada ciclo del cambio de reloj y generará un nivel al contar hasta 50 M. O cada vez que se cuenta 25M, el valor en un registro de salida se invierte. Entonces, para este registro, su ciclo es de 1Hz.

Análisis : ¿cómo lograr cambios similares 00:00:59a los 00:01:00?
     Para realizar esta lógica, es necesario utilizar la señal de acarreo correspondiente a "segundo" como señal de entrada de "minuto", y los minutos pueden contarse cuando hay una señal de acarreo. También debería haber una relación de acarreo similar entre "minuto" y "hora".


2. Código completo

module timer(
	// 控制输入
	input reset,  // 重置信号, 当其值为低电平时,发生重置
	input set,    // 置位标致位,当输入高电平时进行输入
	input clk50,    // 时钟信号
	input[1:0] setp,   // set_position 选择要输入的位置 00,表示秒位, 01 表示分位, 10表示时位,其余报错
	input[5:0] setv,   // set_value 输入的数值
	
	
	// 输出的 6个七段管
	output reg[6:0] second1,
	output reg[6:0] second2,
	output reg[6:0] munite1,
	output reg[6:0] munite2,
	output reg[6:0] hous1,
	output reg[6:0] hous2
);

wire set1, set2, set3;    // 对应每一个管子的设置 
wire car1, car2, carr3;   // 对应每一个管子的输出进位标志
wire clk1;

// 接收每个计数器的计数器值
wire[3:0] num1,num2,num3,num4,num5,num6;

// 接受每一个七段管的输出值
wire[6:0] tub1,tub2,tub3,tub4,tub5,tub6;


divclk1hz clock1(reset,clk50,clk1);

// 定义秒
counter60 c60_1(
	.clk(clk1),
	.in(1),
	.reset(reset),
	.set(set1),
	.inv(setv),
	.carry(car1),
	.out1(num1),
	.out2(num2)
);

// 定义分
counter60 c60_2(
	.clk(clk1),
	.in(car1),
	.reset(reset),
	.set(set2),
	.inv(setv),
	.carry(car2),
	.out1(num3),
	.out2(num4)
);

// 定义时
counter24 c24_2(
	.clk(clk1),
	.in(car2),
	.reset(reset),
	.set(set3),
	.inv(setv),
	.carry(car3),
	.out1(num5),
	.out2(num6)
);


// 将计数器输出的数值信号转化为七段管的亮暗状态
int2tube i1( .in(num1), .out(tub1) );
int2tube i2( .in(num2), .out(tub2) );
int2tube i3( .in(num3), .out(tub3) );
int2tube i4( .in(num4), .out(tub4) );
int2tube i5( .in(num5), .out(tub5) );
int2tube i6( .in(num6), .out(tub6) );

// 以下代码的作业就是链接各个模块
// 这里加入reset 的检测是为了异步处理
always @(posedge clk1 or negedge reset) begin
	if(!reset) begin
		second1 <= 8'b0000001;
		second2 <= 8'b0000001;
		munite1 <= 8'b0000001;
		munite2 <= 8'b0000001;
		hous1 <= 8'b0000001;
		hous2 <= 8'b0000001;
	end else begin
		second1 <= tub1;
		second2 <= tub2;
		munite1 <= tub3;
		munite2 <= tub4;
		hous1 <= tub5;
		hous2 <= tub6;
	end
end

// 设置置位信号
assign set1 = (set==1)?((setp == 0)?1:0):0;
assign set2 = (set==1)?((setp == 1)?1:0):0;
assign set3 = (set==1)?((setp == 2)?1:0):0;
endmodule

/** 60位计数器 */
module counter60(
	input clk,     // 时钟信号
	input in,      // 输入信号
	input reset,   // 重置信号, 当其值为低电平时,发生重置
	input set,     // 置位标致位,当输入高电平时进行输入
	input[5:0] inv,// 置位信号
	output reg carry,  // 进位信号
	output reg[3:0] out1,  // 输出十位
	output reg[3:0] out2   // 输出个位
);

reg[5:0] inner;  // 内置计数器
always @(posedge clk or posedge set or negedge reset) begin
	if(!reset) begin       // 检测是否要进行重置 低电平有效
		inner <= 0;
		carry <= 0;
		out1 <= 0;
		out2 <= 0;
	end else if(set) begin // 检测是否要进行置数 高电平有效
		inner <= inv;
		out1 <= inv / 10;
		out2 <= inv % 10;
	end else begin
		if(in) begin // 没有重置和置数时,in为高电平时进行加数
			if(inner < 58) begin  // 如果没到58就继续数
				inner <= inner + 1;
			end else if(inner == 58)begin // 到58结束时输出进位信号,这样在59结束时(新的1秒开始)就可以
				carry <= 1;        // 并且进行进位
				inner <= inner + 1;
			end else begin      // 如果到了59, 那么下一时刻就要进行从 0 开始数 
				inner <= 0;
				carry <= 0;
			end
		end
		out1 <= inner / 10;
		out2 <= inner % 10;
	end
end
endmodule


/** 24位计数器 */
module counter24(
	input clk,     // 时钟信号
	input in,      // 输入信号
	input reset,   // 重置信号, 当其值为低电平时,发生重置
	input set,     // 置位标致位,当输入高电平时进行输入
	input[5:0] inv,// 置位信号
	output reg carry,  // 进位信号
	output reg[3:0] out1,  // 输出十位
	output reg[3:0] out2   // 输出个位
);

reg[4:0] inner;  // 内置计数器
always @(posedge clk or posedge set or negedge reset) begin
	if(!reset) begin       // 检测是否要进行重置 低电平有效
		inner <= 0;
		carry <= 0;
		out1 <= 0;
		out2 <= 0;
	end else if(set) begin // 检测是否要进行置数 高电平有效
		inner <= inv;
		out1 <= inv / 10;
		out2 <= inner % 10;
	end else begin
		if(in) begin  // 没有重置和置数时,in为高电平时进行加数
			if(inner < 23) begin  // 如果没到59就继续数
				inner <= inner + 1;
				carry <= 0;
			end else begin      // 如果到了59, 那么下一时刻就要进行从 0 开始数 
				inner <= 0;
				carry <= 1;       // 并且进行进位
			end
		end
		out1 <= inner / 10;
		out2 <= inner % 10;
	end
	
end
endmodule

/** 将数值信号转化为七段管的亮暗状态 */
module int2tube(
	input[3:0] in,
	output reg[6:0] out
);

always @(in) begin
	case (in)
		0: out <= 8'b0000001;
		1: out <= 8'b0011111;
		2: out <= 8'b0010010;
		3: out <= 8'b0000110;
		4: out <= 8'b1001100;
		5: out <= 8'b0100100;
		6: out <= 8'b0100000;
		7: out <= 8'b0001111;
		8: out <= 8'b0000000;
		9: out <= 8'b0000100;
	endcase
end

endmodule

/** 分频模块,每数到25M改变一个让一个输出寄存器clk1里的值发生反转 */
module divclk1hz(reset,clk50,clk1);
input clk50,reset;   //clk50 为输入50Mhz 信号,reset 为复位信号
output reg clk1;     // 新产生的1hz 信号
integer i=0;         //50Mhz 频率下,周期计数器
always@(posedge clk50) begin
	if(!reset) begin 
		i=0;
		clk1 = 0;
	end else begin
		if(i==30) begin i=0; clk1=~clk1;  // 25000000 这里的i应该=25M,但是为了更方便的展示效果,我将i的值改为了30,这样七段管里的数值会改变的更快。
	end
	else i=i+1;
	end
end
endmodule

3. Código de prueba

`timescale 10 ns/ 1 ns
module timer_vlg_tst();
reg clk50;
reg reset;
reg set;
reg [1:0] setp;
reg [5:0] setv;

wire [6:0]  hous1;
wire [6:0]  hous2;
wire [6:0]  munite1;
wire [6:0]  munite2;
wire [6:0]  second1;
wire [6:0]  second2;	

timer i1 ( 
	.clk50(clk50),
	.hous1(hous1),
	.hous2(hous2),
	.munite1(munite1),
	.munite2(munite2),
	.reset(reset),
	.second1(second1),
	.second2(second2),
	.set(set),
	.setp(setp),
	.setv(setv)
);


initial begin 
	// 初始化外部时钟 
	clk50 = 0; 
	// 重置一遍timer模块
	reset = 1; #5 reset =0; #5 reset =1;
	set = 0;
	// 准备将秒位设置到55秒
		setv = 33; setp = 0;
// 等待2100 个时间单位,观察时间变化
	# 2100;
	// 进行数值修改
	set = 1;
	// 修改完毕,结束修改信号
	#1 set = 0;
	// 运行900 时间单位,观察效果,进行复位
	#900 reset = 0;
	// 复位信号归位
	#5 reset = 1;
	// 运行900个单位以后停止运行
	#900 $stop;
	
end


always begin
	#1 clk50 =~ clk50;
end

endmodule

4. Efecto

El efecto de la señal de reinicio asíncrona : se puede ver que después de que la señal de reinicio ingresa a la asignación, los valores de los seis tubos de siete segmentos se restauran a los 0000001valores correspondientes 0.
Inserte la descripción de la imagen aquí

El efecto de la configuración síncrona : cuando el modelo establecido ingresa al nivel de punto alto, cambie el valor del tiempo establecido (establezca el "segundo" valor en 33), y el 0000110valor correspondiente es 3.
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_49736959/article/details/109247091
Recomendado
Clasificación