功能:
基于Nexys4DDR开发板实现的数字钟,六位数码管显示时分秒,可切换24时制/12时制,有整点报时功能(led灯闪烁)。
Verilog代码:
`timescale 1ns / 1ps
//数字钟,输入100M时钟信号,控制数字显示器通过高频扫描来显示当前时间
module digital_clock(clk_100M, select, y, h, min, sh, led1, led2);
input clk_100M;
input h, min, sh;
output led1, led2;
output[7:0] y;
output[7:0] select;
reg led1;
wire led2;
reg[16:0] count;
reg[7:0] select, y;
wire clk_1hz, clk_1khz, clk_100M;
wire[3:0] s0, s1, m0, m1, h0, h1;
//变量说明:
//clk_100M是100M的时钟信号select是控制数码管亮暗的使能端,y是七段译码器的输出端
//led2是正点报时灯
//count用于记录时钟走过的秒数,clk_1hz是分频后1hz的时钟信号
//s0~h1记录秒、分、时的个十位
//h、min分别为分钟和小时校时,sh==0时为24时制,sh==1时为12时制,led1是上下午指示灯
//分频器获得1hz和1khz时钟信号,输入输出必须为wire型
frequency_divider fred(clk_1hz, clk_1khz, clk_100M);
//计时模块,每24*60*60秒为一轮
initial count = 0;
always@(posedge clk_1hz)
begin
case({h,min})
2'b01:
if(sh==0 && count < 17'd86341) count <= count + 6'd60;//24小时制的分钟校时
else if(sh==1 && count < 16'd43141) count <= count + 6'd60;//12小时制的分钟校时
else count <= 0;
2'b10:
if(sh==0 && count < 17'd82800) count <= count + 12'd3600;//24小时制的小时校时
else if(sh==0 && count >= 17'd82800) count <= 0;//24小时制清零
else if(sh==1 && count < 16'd43200) count <= count + 12'd3600;//12小时制的小时校时
else count <= 12'd3600;//12小时制清零
2'b00:
if(sh==0 && count < 17'd86399) count <= count + 1;
else if(sh==0 && count >= 17'd86399) count <= 0;
else if(sh==1 && count < 16'd46799) count <= count + 1;
else count <= 3600;
2'b11:
count <= count;
endcase
end
//获得当前时间的时分秒各位数
time_count t(count, s0, s1, m0, m1, h0, h1);
//12小时制的上下午指示灯,上午灭,下午亮
initial led1 = 0;
always@(h1) if(sh==1 && {h1,h0}==1) led1 <= ~led1;
always@(posedge sh)
if(count > 16'd43200)
begin
count <= count - 16'd43200;
led1 <= ~led1;
end
//正点报时
showtime show(clk_1hz, count, led2);
//获取当前时间的时分秒各位数的七段译码值
wire[7:0] y0, y1, y2, y3, y4, y5;
decoder4_8 d1(s0, y0);
decoder4_8 d2(s1, y1);
decoder4_8 d3(m0, y2);
decoder4_8 d4(m1, y3);
decoder4_8 d5(h0, y4);
decoder4_8 d6(h1, y5);
//数码管高频显示当前小时、分钟和秒
reg[2:0] flag;//flag相当于模6计数器,对应时分秒的六位数
initial
begin
flag = 0;
y = 0;
select = 0;
end
always@(posedge clk_1khz) flag = (flag+1)%6;
always@(flag)
begin
if(flag == 3'd0)//显示秒的个位
begin
select <= 8'b1111_1110;
y <= y0;
end
if(flag == 3'd1)//显示秒的十位
begin
select <= 8'b1111_1101;
y <= y1;
end
if(flag == 3'd2)//显示分钟的个位
begin
select <= 8'b1111_1011;
y <= y2;
end
if(flag == 3'd3)//显示分钟的十位
begin
select <= 8'b1111_0111;
y <= y3;
end
if(flag == 3'd4)//显示小时的个位
begin
select <= 8'b1110_1111;
y <= y4;
end
if(flag == 3'd5)//显示小时的十位
begin
select <= 8'b1101_1111;
y <= y5;
end
end
endmodule
//分频器
module frequency_divider(clk_1hz, clk_1khz, clk_100M);
input clk_100M;
output clk_1hz, clk_1khz;
reg[16:0] count1;
reg[9:0] count2;
reg clk_1khz, clk_1hz;
//变量说明:
//输入clk_100M为100M的时钟信号
//count1和count2是分频器计的数变量,clk_1khz和clk_1hz是分频器的输出
//中间变量必须在源程序中初始化!!!
initial
begin
count1 = 0;
count2 = 0;
clk_1khz = 0;
clk_1hz = 0;
end
//100M 100000分频得到1khz
always@(posedge clk_100M)
begin
if(count1 == 17'd49999)
begin
clk_1khz <= ~clk_1khz;
count1 <= 0;
end
else count1 <= count1 + 1;
end
//1khz 1000分频得到1hz
always@(posedge clk_1khz)
begin
if(count2 == 10'd499)
begin
clk_1hz <= ~clk_1hz;
count2 <= 0;
end
else count2 <= count2 + 1;
end
endmodule
//七段译码器
module decoder4_8(x, y);
input[3:0] x;
output[7:0] y;
reg[7:0] y;
always@(x)
case(x)
4'd0: y <= 8'h03;//数码管显示0
4'd1: y <= 8'h9f;//数码管显示1
4'd2: y <= 8'h25;//数码管显示2
4'd3: y <= 8'h0d;//数码管显示3
4'd4: y <= 8'h99;//数码管显示4
4'd5: y <= 8'h49;//数码管显示5
4'd6: y <= 8'h41;//数码管显示6
4'd7: y <= 8'h1f;//数码管显示7
4'd8: y <= 8'h01;//数码管显示8
4'd9: y <= 8'h09;//数码管显示9
endcase
endmodule
//时分秒计算器
module time_count(count, s0, s1, m0, m1, h0, h1);
input[16:0] count;
output[3:0] s0, s1, m0, m1, h0, h1;
reg[3:0] s0, s1, m0, m1, h0, h1;//分别对应秒、分、时的个位、十位
initial
begin
s0 = 0; s1 = 0; m0 = 0; m1 = 0; h0 = 0; h1 = 0;
end
always@(count)
begin
s0 <= (count%60)%10;//秒的个位
s1 <= (count%60-((count%60)%10))/10;//秒的十位
m0 <= (((count-count%60)/60)%60)%10;//分钟的个位
m1 <= ((((count-count%60)/60)-((count-count%60)/60)%10)%60)/10;//分钟的十位
h0 <= ((count-count%3600)/3600)%10;//小时的个位
h1 <= (((count-count%3600)/3600)-((count-count%3600)/3600)%10)/10;//小时的十位
end
endmodule
//正点报时,几点就亮几下
module showtime(clk_1hz, count, led2);
input clk_1hz;
input[16:0] count;
output led2;
reg led2;
reg[4:0] clock_number;
initial begin clock_number = 0; led2 = 0; end
always@(clk_1hz)
begin
if(clock_number == 0)
case(count)
17'd3598: clock_number <= 2;//马上1点
17'd7197: clock_number <= 4;//马上2点
17'd10796: clock_number <= 6;//马上3点
17'd14395: clock_number <= 8;//马上4点
17'd17994: clock_number <= 10;//马上5点
17'd21592: clock_number <= 12;//马上6点
17'd25192: clock_number <= 14;//马上7点
17'd28791: clock_number <= 16;//马上8点
17'd32390: clock_number <= 18;//马上9点
17'd35989: clock_number <= 20;//马上10点
17'd39588: clock_number <= 22;//马上11点
17'd43187: clock_number <= 24;//马上12点
17'd46786: clock_number <= 26;//马上13点
17'd50385: clock_number <= 28;//马上14点
17'd53984: clock_number <= 30;//马上15点
17'd57583: clock_number <= 32;//马上16点
17'd61182: clock_number <= 34;//马上17点
endcase
else
begin
led2 <= ~led2;
clock_number <= clock_number - 1;
end
end
endmodule
管脚约束文件.ucf
NET "y<7>" LOC=T10 | IOSTANDARD=LVCMOS33; #IO_L24N_T3_A00_D16_14
NET "y<6>" LOC=R10 | IOSTANDARD=LVCMOS33; #IO_25_14
NET "y<5>" LOC=K16 | IOSTANDARD=LVCMOS33; #IO_25_15
NET "y<4>" LOC=K13 | IOSTANDARD=LVCMOS33; #IO_L17P_T2_A26_15
NET "y<3>" LOC=P15 | IOSTANDARD=LVCMOS33; #IO_L13P_T2_MRCC_14
NET "y<2>" LOC=T11 | IOSTANDARD=LVCMOS33; #IO_L19P_T3_A10_D26_14
NET "y<1>" LOC=L18 | IOSTANDARD=LVCMOS33; #IO_L4P_T0_D04_14
NET "y<0>" LOC=H15 | IOSTANDARD=LVCMOS33; #IO_L19N_T3_A21_VREF_15
NET "select<0>" LOC=J17 | IOSTANDARD=LVCMOS33; #IO_L23P_T3_FOE_B_15
NET "select<1>" LOC=J18 | IOSTANDARD=LVCMOS33; #IO_L23N_T3_FWE_B_15
NET "select<2>" LOC=T9 | IOSTANDARD=LVCMOS33; #IO_L24P_T3_A01_D17_14
NET "select<3>" LOC=J14 | IOSTANDARD=LVCMOS33; #IO_L19P_T3_A22_15
NET "select<4>" LOC=P14 | IOSTANDARD=LVCMOS33; #IO_L8N_T1_D12_14
NET "select<5>" LOC=T14 | IOSTANDARD=LVCMOS33; #IO_L14P_T2_SRCC_14
NET "select<6>" LOC=K2 | IOSTANDARD=LVCMOS33; #IO_L23P_T3_35
NET "select<7>" LOC=U13 | IOSTANDARD=LVCMOS33; #IO_L23N_T3_A02_D18_14
NET "clk_100M" LOC=E3 | IOSTANDARD=LVCMOS33;
NET "min" LOC=J15 | IOSTANDARD=LVCMOS33; #IO_L24N_T3_RS0_15
NET "h" LOC=L16 | IOSTANDARD=LVCMOS33; #IO_L3N_T0_DQS_EMCCLK_14
NET "sh" LOC=M13 | IOSTANDARD=LVCMOS33; #IO_L13N_T2_MRCC_14
NET "sh" CLOCK_DEDICATED_ROUTE = FALSE;
NET "led1" LOC=H17 | IOSTANDARD=LVCMOS33; #IO_L18P_T2_A24_15
NET "led2" LOC=K15 | IOSTANDARD=LVCMOS33; #IO_L24P_T3_RS1_15