目录
设计方案概述
1、分频器模块设计
2、计数器模块设计
3、LED显示模块设计
4、顶层模块设计
本任务设计了一个简易数字钟,能实现小时、分钟和秒的计时及显示,其中,通过控制时、分和秒实现时钟计时的计数模块是本次设计的核心。
计数模块的关键在于能够理解三个计时单位之间的联系,即秒计数满60产生一个向分钟的进位,分钟计数满60产生一个向小时的进位,这两个进位信号将小时、分和秒联系起来,是理解本设计的关键点。
为时钟设计一个初值设置控制信号,按下设置信号时能利用开发板上的拨码开关或按键对时间进行校对设置。
任务分析
计数信号来自于开发板提供的时钟信号,这里采用的晶振频率为10KHz,而秒的计数周期是1秒,因此需要对该时钟信号进行分频(10KHz→1Hz),因此,分频器模块是本任务中另一个重要模块。
根据常识,“秒”、“分”和“小时”之间存在各自独立又互相联系的计数和进位关系,“秒”和“分”的计数模式相同,每计数满60个时钟清零并重新开始计数,相当于一个六十进制的计数器。“小时”的计数模式是每计数满24个时钟就进行清零并重新开始计数,相当于一个二十四进制的计数器。所以,六十进制和二十四进制的计数器模块设计是本任务的核心模块。
“秒”、“分”和“小时”的计时过程都需要通过LED显示器进行显示,所以还需要设计显示控制模块。
根据以上分析,本任务需要设计的模块如下:
分频器模块;
分、秒和小时的计数器模块;
显示控制模块。
module freq_div(clk, clk_1); //clk:输入时钟信号; clk_1: //输出时钟信号
input clk;
output clk_1;
reg[13:0] counter=14'd0; //定义计数器,用于计数时钟(计数10000,需要用14位计数器)
reg clk_1=0;
always@(posedge clk)
if(counter == 14'd4999) //如果等于4999
begin
counter <= 14'b0; //把counter恢复成0
clk_1 <= ~clk_1; //把clk_1翻转
end
else
counter <= counter + 1'b1; //counter 继续计数
endmodule
`timescale 1us/1ns
module tb_led_clock();
reg CLK;
parameter period = 100; //100us = 1/(10K) Hz
top inst_top(.clk(CLK));
initial
begin
CLK= 0;
forever
#(period/2) CLK = ~CLK;
end
endmodule
信号名 |
I/O |
位宽 |
含义 |
clk_1 |
I |
1 bit |
分频后周期为1s的时钟输出 |
hor |
O |
5 bits |
小时计数结果的输出(0-23) |
min |
O |
6 bits |
分钟计数结果的输出(0-59) |
sec |
O |
6 bits |
秒钟计数结果的输出(0-59) |
module count(clk_1, sec, min, hor);
input clk_1;
reg scarry, mcarry, hcarry;
output reg [4:0] hor=23;
output reg [5:0] min=59;
output reg [5:0] sec=49;
always@(posedge clk_1)
begin
if (sec==6'b111011) //秒针计数到59
begin
sec <= 6'b000000;
scarry <= 1'b1; //秒向分进位1
end
else
begin
sec <= sec+1'b1;
scarry <= 1'b0;
end
end
always@(posedge scarry)
begin
if (min == 6'b111011) //分针计数到59
begin
min <= 6'b000000;
mcarry <= 1'b1; //分向小时进位1
end
else
begin
min <= min+1'b1;
mcarry <= 1'b0;
end
end
always@(posedge mcarry)
begin
if (hor==5'b10111) //计数到23
hor <= 5'b00000;
else
hor <= hor+1'b1;
end
endmodule
`timescale 1ms/1ps
module tb_count();
reg CLK_1;
parameter period=1000;
count T1(.clk_1(CLK_1));
initial
begin
CLK_1= 0;
forever
#(period/2) CLK_1 = ~CLK_1; //周期为1s,用作测试
end
endmodule
信号名 |
I/O |
位宽 |
含义 |
clk |
I |
1bits |
时钟信号,10KHz基频(用作动态数码管的移位扫描) |
clk_1 |
I |
1bits |
时钟信号,1Hz频率(用作整点提示led的延时) |
hor |
I |
5 bits |
时计数结果,hour |
min |
I |
6 bit |
分钟计数结果,minute |
sec |
I |
6 bits |
秒计数结果,second |
led_SEL |
O |
3 bits |
控制数码管动态扫描的位累加变量 |
led_dis |
O |
8 bits |
数码管段选,"7段+1dp" |
led |
O |
4 bits |
4个led灯,作整点提示 |
module led_dis(
clk, clk_1,
hor,min,sec,
led_SEL,
led_dis,
led
);
input clk,clk_1;
input [4:0] hor;
input [5:0] min;
input [5:0] sec;
reg [3:0] horh,horl;
reg [3:0] minh,minl;
reg [3:0] sech,secl;
reg [3:0] disp_Temp;
reg [2:0] led_count=3'b000;
output reg [2:0] led_SEL=3'b000;
output reg [7:0] led_dis=8'b101_1011;
output reg [3:0] led;
reg [7:0] disp_code=8'b101_1011;
reg [3:0] led_remind=4'b0000;
integer i;
always@(hor) //将hour的二进制码转换成BCD码,并将十位数、个位数保存至horh、horl
begin
horh=4'd0;
horl=4'd0;
for(i=4;i>=0;i=i-1)
begin
if(horh>=5)
horh=horh+3;
if(horl>=5)
horl=horl+3;
horh = horh<<1;
horh[0] = horl[3];
horl = horl<<1;
horl[0]= hor[i];
end
end
always@(min) //将minute的二进制码转换成BCD码,并将十位数、个位数保存至minh、minl
begin
minh=4'd0;
minl=4'd0;
for(i=5; i>=0; i=i-1)
begin
if(minh>=5)
minh=minh+3;
if(minl>=5)
minl=minl+3;
minh = minh<<1;
minh[0] = minl[3];
minl = minl<<1;
minl[0]= min[i];
end
end
always@(sec) //将second的二进制码转换成BCD码,并将十位数、个位数保存至sech、secl
begin
sech=4'd0;
secl=4'd0;
for(i=5; i>=0; i=i-1)
begin
if(sech>=5)
sech=sech+3;
if(secl>=5)
secl=secl+3;
sech = sech<<1;
sech[0] = secl[3];
secl = secl<<1;
secl[0]= sec[i];
end
end
always@(led_SEL)
begin
case(led_SEL+1)
3'b000: disp_Temp <= horh;
3'b001: disp_Temp <= horl;
3'b010: disp_Temp <= 10;
3'b011: disp_Temp <= minh;
3'b100: disp_Temp <= minl;
3'b101: disp_Temp <= 10;
3'b110: disp_Temp <= sech;
3'b111: disp_Temp <= secl;
default: disp_Temp <= horh;
endcase
end
always@(disp_Temp) //--显示转换
begin
case(disp_Temp) //低位数的可能值:0~9
5'd0: disp_code <=8'b0011_1111;
5'd1: disp_code <=8'b0000_0110;
5'd2: disp_code <=8'b0101_1011;
5'd3: disp_code <=8'b0100_1111;
5'd4: disp_code <=8'b0110_0110;
5'd5: disp_code <=8'b0110_1101;
5'd6: disp_code <=8'b0111_1101;
5'd7: disp_code <=8'b0000_0111;
5'd8: disp_code <=8'b0111_1111;
5'd9: disp_code <=8'b0110_1111;
default: disp_code <=8'b0100_0000; //显示'-'
endcase
end
always@(posedge clk)
begin //扫描累加
led_dis <= disp_code;
led_SEL <= led_SEL + 1'b1;
end
always@(posedge clk_1)
begin
if(min==59 && sec>54) //在59分55秒开始提示
led_count<=led_count+1;
else
led_count<=3'b000;
end
always@(led_count)
begin
case(led_count)
3'b000: led_remind <= 4'b0000;
3'b001: led_remind <= 4'b0001;
3'b010: led_remind <= 4'b0011;
3'b011: led_remind <= 4'b0111;
3'b100: led_remind <= 4'b1111;
default:led_remind <= 4'b0000;
endcase
led<=led_remind;
end
endmodule
`timescale 1us/1ns
module tb_led_dis();
reg [4:0] HOR;
reg [5:0] MIN, SEC;
reg CLK,CLK_1;
parameter period = 100; //100us = 1/(10K) Hz
led_dis T3(.clk(CLK),.clk_1(CLK_1).hor(HOR),.min(MIN),.sec(SEC));
parameter delay = 1000000;
initial
begin
CLK= 0;
forever
#(period/2) CLK = ~CLK;
end
initial
begin
CLK_1= 0;
forever
#(period/2) CLK_1 = ~CLK_1; //周期为1s,用作测试
end
initial
begin
#delay HOR=5'd1; MIN=6'd12; SEC=6'd35;
#delay HOR=5'd11; MIN=6'd59; SEC=6'd12;
#delay HOR=5'd00; MIN=6'd34; SEC=6'd56;
#delay HOR=5'd23; MIN=6'd28; SEC=6'd00;
#delay ;
end
endmodule
先设置top.v为顶层文件(右键“top”→Set as Top-Level Entity)
module top(
clk,
hor, min, sec,
led_dis, led_SEL,
led
);
input clk;
output [4:0] hor;
output [5:0] min, sec;
output [2:0] led_SEL;
output [7:0] led_dis;
output [3:0] led;
wire clk_1;
freq_div inst_fre_div(
.clk(clk),
.clk_1(clk_1)
);
wire [4:0] hor;
wire [5:0] min,sec;
count inst_count(
.clk_1(clk_1),
.hor(hor),
.min(min),
.sec(sec)
);
wire [7:0] led_dis;
wire [2:0] led_SEL;
wire [3:0] led;
led_dis inst_led(
.clk(clk),
.clk_1(clk_1),
.hor(hor),.min(min),.sec(sec),
.led_SEL(led_SEL),
.led_dis(led_dis),
.led(led)
);
endmodule
PS:直接编写一个tb_led_clock.v就可以了,不用指定其顶层还是底层模块
`timescale 1us/1ns
module tb_led_clock();
reg CLK;
parameter period = 100; //100us = 1/10K Hz
top inst_top(.clk(CLK));
initial
begin
CLK= 0;
forever
#(period/2) CLK = ~CLK;
end
endmodule