EDA design (verilog)-seven segment tube clock

Title description: Timer: Display hours (0-23 or 11), minutes (0-59), and seconds (0-59) on 6 seven-segment tubes, each occupying 2 tubes. The external clock is 50Mhz. You can use the button to generate a reset signal key, when the button is pressed immediately (asynchronously) the time is reset to 0 hours, 0 minutes, and 0 seconds to restart timing.

1. Question analysis:

Analysis 1 : How to realize this function?
    We need 6 7-bit registers (or a 7*6 = 42-bit register) to retain the time of each moment. The display of the 4 counters of "seconds" and "minutes" corresponds to a 60 hexadecimal count. Module, and "hour" corresponds to a 24-bit counter.

Analysis 2 : How to achieve a change every second?
    According to the system's external clock of 50 MHz, we can write a counter, which will record every cycle of the clock change, and output a level when counting to 50 M. Or every time 25M is counted, the value in an output register is reversed. Then for this register, its cycle is 1Hz.

Analysis : how to achieve similar 00:00:59to the 00:01:00changes?
     To realize this logic, it is necessary to use the carry signal corresponding to "second" as the input signal of "minute", and the minutes can be counted when there is a carry signal. There should also be a similar carry relationship between "minute" and "hour".


2. Comprehensive code

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. Test code

`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. Effect

The effect of asynchronous reset signal : It can be seen that after the reset signal enters the assignment, the values ​​of the six seven-segment tubes are restored to the 0000001corresponding values 0.
Insert picture description here

The effect of synchronous setting : When the set model enters the high point level, change the value of the set time (set the "second" value to 33), and the 0000110corresponding value is 3.
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_49736959/article/details/109247091