1. 实验目的
(1). 秒表的显示时间分为 6 个十进制数字,从 00:00:00-59:59:99 循环计数
(2). 包含一个同步清零信号 reset;包含一个启动信号 go,开始或暂停计数;
(3). 对 N4 实验板 100MHZ 时钟源进行分频,每 0.01s 产生一个计数脉冲。
2. 实验内容
(1)原理描述
整个停表的工作流程是这样的:首先,stopwatch 模块会根据时钟信号 clk 和 go 信号的状态进行计时,每过 0.01 秒就会在 dv2、dv1 上加 1。然后,当 dv1 加到 9 时,会将 dv1 归零,并将 dv2 加 1,当 dv2 加到 9 时,会将 dv2 归零,并将秒数 sec1 加 1。以此类推,当 sec1 加到 9 时,会将 sec1 归零,并将 sec2 加 1,以此类推,当 sec2 加到 5 时,会将 sec2 归零,并将分钟数 min1 加 1。以此类推,当 min1 加到 9 时,会将 min1 归零,并将 min2 加 1。这样就实现了停表的计时功能。
同时,scan_seg_disp 模块会根据各位数字的值和段选信号来控制七段数码管的显示。
然后,在另一个时钟下升沿(posedge)的 always 块中,会根据 dv_tick 信号的状态来更新停表各位的数值。
(2)Verilog HDL设计源代码描述(要求:注释)
`timescale 1ns / 1ps
module stopwatch_top(
input clk,go,reset,
output [7:0] an,
output [7:0] sseg // seven segment digital tube
);
/*
stopwatch模块是实现停表功能的核心,它接受三个输入信号:clk、go、reset。clk 是时钟信号,go 是启动/暂停信号,reset 是复位信号。stopwatch 模块输出六个信号:min2、min1、sec2、sec1、dv2、dv1,分别表示停表显示的分钟、秒、0.01 秒。
*/
wire [3:0] min2,min1,sec2,sec1,dv2,dv1;
scan_seg_disp uut1(
.clk(clk),
.reset(reset),
.hex5(min2),
.hex4(min1),
.hex3(sec2),
.hex2(sec1),
.hex1(dv2),
.hex0(dv1),
.dp_in(6'b101011),
.an(an),
.sseg(sseg)
);
/*
scan_seg_disp 模块是将停表的数字显示在七段数码管上的模块,它接受八个输入信号:hex5、hex4、hex3、hex2、hex1、hex0、dp_in 和 an,分别表示各位数字、小数点和段选信号。scan_seg_disp 模块输出一个信号:sseg,表示七段数码管的段码信号。
*/
stopwatch uut2(
.clk(clk),
.go(go),
.reset(reset),
.min2(min2),
.min1(min1),
.sec2(sec2),
.sec1(sec1),
.dv2(dv2),
.dv1(dv1)
);
endmodule
//停表模块
module stopwatch(
input clk,go,reset,
output [3:0] min2,min1,sec2,sec1,dv2,dv1 //分,秒,0.01 秒,电子停表的分度值 division value 为 0.01 秒
);
localparam COUNT = 1000000;//100Mhz 的频率,计数 10^6,为0.01s
reg [19:0] dv_reg;//计时器,2^20=1024*1024>10^6
reg [3:0] min2_reg,min1_reg,sec2_reg,sec1_reg,dv2_reg,dv1_reg;
reg dp;
wire dv_tick;
//生成计数器 ms_reg,10M 的计数器,每 0.01 秒生成一个脉冲
always@(posedge clk)
begin
if(reset)
dv_reg <=0;
else if(go == 1)
begin
if(dv_reg < COUNT)
dv_reg <= dv_reg + 1;
else
dv_reg <= 0;
end
end
assign dv_tick = (dv_reg == COUNT) ? 1'b1: 1'b0;//每 0.01s 产生一个标志位
always@(posedge clk) begin
if(reset) begin
min2_reg <=4'b0000;
min1_reg <=4'b0000;
sec2_reg <=4'b0000;
sec1_reg <=4'b0000;
dv2_reg <=4'b0000;
dv1_reg <=4'b0000;
end
else if(dv_tick) begin
if(dv1_reg!=4'd9)
dv1_reg <= dv1_reg + 1;
else begin
dv1_reg <= 4'd0;
if(dv2_reg!=4'd9)
dv2_reg <= dv2_reg + 1;
else begin
dv2_reg <= 4'd0;
if(sec1_reg!=4'd9)
sec1_reg <= sec1_reg + 1;
else begin
sec1_reg <=4'd0;
if(sec2_reg!=4'd5)
sec2_reg <= sec2_reg + 1;
else begin
sec2_reg <= 4'd0;
if(min1_reg!=4'd9)
min1_reg <= min1_reg + 1;
else begin
min1_reg <= 0;
if(min2_reg!=4'd5)
min2_reg <= min2_reg + 1;
else
min2_reg <= 0;
end
end
end
end
end
end
end
assign min2 = min2_reg;
assign min1 = min1_reg;
assign sec2 = sec2_reg;
assign sec1 = sec1_reg;
assign dv2 = dv2_reg;
assign dv1 = dv1_reg;
endmodule
//数码管扫描模块
module scan_seg_disp (
input clk, reset,
input [3:0] hex5,hex4,hex3, hex2, hex1,hex0,
input [5:0] dp_in,
output reg [7:0] an,
output reg [7:0] sseg
);
localparam N=20;
reg [N-1:0] cnt;
reg [3:0] hex;
reg dp;
always @(posedge clk)
begin
if(reset) begin
cnt <= 0;
hex <= 4'd10;
end
else
begin
cnt <= cnt + 1;
case (cnt[N-1:N-3])
3'b000: begin
hex <= hex0;
an <= 8'b11111110;
dp <= dp_in[0];
end
3'b001: begin
hex <= hex1;
an <= 8'b11111101;
dp <= dp_in[1];
end
3'b010: begin
hex <= hex2;
an <= 8'b11111011;
dp <= dp_in[2];
end
3'b011: begin
hex <= hex3;
an <= 8'b11110111;
dp <= dp_in[3];
end
3'b100: begin
hex <= hex4;
an <= 8'b11101111;
dp <= dp_in[4];
end
3'b101: begin
hex <= hex5;
an <= 8'b11011111;
dp <= dp_in[5];
end
default: cnt <= 0;
endcase
end
end
always@ (*)
begin
case(hex)
4'h0:sseg[6:0] = 7'b0000001;
4'h1:sseg[6:0] = 7'b1001111;
4'h2:sseg[6:0] = 7'b0010010;
4'h3:sseg[6:0] = 7'b0000110;
4'h4:sseg[6:0] = 7'b1001100;
4'h5:sseg[6:0] = 7'b0100100;
4'h6:sseg[6:0] = 7'b0100000;
4'h7:sseg[6:0] = 7'b0001111;
4'h8:sseg[6:0] = 7'b0000000;
4'h9:sseg[6:0] = 7'b0000100;
default: sseg[6:0] = 7'b0000001;
endcase
sseg[7]= dp;
end
endmodule
(3)TestBeach仿真代码及仿真结果
`timescale 1ns / 1ps
module stopwatch_tb;
// Inputs
reg clk;
reg go;
reg reset;
// Outputs
wire [7:0] an;
wire [7:0] sseg;
// Instantiate the UUT
stopwatch_top uut (
.clk(clk),
.go(go),
.reset(reset),
.an(an),
.sseg(sseg)
);
// Clock period definition
parameter CLK_PERIOD = 10;
// Testbench logic
always begin
#(CLK_PERIOD / 2) clk = 0;
#(CLK_PERIOD / 2) clk = 1;
end
initial begin
reset = 1;
go = 0;
#5 reset = 0;
#5 go = 1;
#50 go = 0;
#5 go = 1;
#50 $finish;
end
endmodule
(4)XDC文件配置
set_property PACKAGE_PIN E3 [get_ports clk]
set_property IOSTANDARD LVCMOS18 [get_ports clk]
set_property IOSTANDARD LVCMOS18 [get_ports go]
set_property IOSTANDARD LVCMOS18 [get_ports {an[7]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[6]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[5]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[4]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {an[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[7]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[6]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[5]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[4]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[3]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[2]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[1]}]
set_property IOSTANDARD LVCMOS18 [get_ports {sseg[0]}]
set_property IOSTANDARD LVCMOS18 [get_ports reset]
set_property PACKAGE_PIN J17 [get_ports {an[0]}]
set_property PACKAGE_PIN J18 [get_ports {an[1]}]
set_property PACKAGE_PIN T9 [get_ports {an[2]}]
set_property PACKAGE_PIN J14 [get_ports {an[3]}]
set_property PACKAGE_PIN P14 [get_ports {an[4]}]
set_property PACKAGE_PIN T14 [get_ports {an[5]}]
set_property PACKAGE_PIN K2 [get_ports {an[6]}]
set_property PACKAGE_PIN U13 [get_ports {an[7]}]
set_property PACKAGE_PIN L18 [get_ports {sseg[0]}]
set_property PACKAGE_PIN T11 [get_ports {sseg[1]}]
set_property PACKAGE_PIN P15 [get_ports {sseg[2]}]
set_property PACKAGE_PIN K13 [get_ports {sseg[3]}]
set_property PACKAGE_PIN N17 [get_ports reset]
set_property PACKAGE_PIN J15 [get_ports go]
set_property PACKAGE_PIN H15 [get_ports {sseg[7]}]
set_property PACKAGE_PIN K16 [get_ports {sseg[4]}]
set_property PACKAGE_PIN R10 [get_ports {sseg[5]}]
set_property PACKAGE_PIN T10 [get_ports {sseg[6]}]
(5)下板测试
3.实验体会
使用verilog实现一个简单的秒表,对bcd加法与n4板,数码管的动态显示应用有了更加深入的了解