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:59
to the 00:01:00
changes?
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 0000001
corresponding values 0
.
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 0000110
corresponding value is 3.