module clock(
input clk, //时钟
input rst, //复位键
input wire month_adj ,
input wire day_adj ,
input [0:4] key, //按键输入
input [0:0] qiehuan,
output [0:7] seg_cs, //数码管位选
output [0:7] seg_data0, //前四个数码管
output [0:7] led,
output [0:7] seg_data1 //后四个数码管
);
reg [3:0] day_l = 0;
reg [3:0] day_h = 0;
reg [3:0] month_l = 0 ;
reg [3:0] month_h = 0 ;
reg [0:26] cnt_1s = 0; //计时1s
reg [0:20] cnt_xd = 0; //消抖计时
reg [0:25] cnt_s = 0; //闪烁计时
reg [0:1] key_out; //输出按下哪一位按键
reg [0:17] cnt; //扫描计时
reg [0:3] count = 0; //用于移位的计数
reg [0:7] wz; //保存当前数码管位置
reg [0:2] cnt_wz; //决定哪一位数码管亮
reg [0:3] num = 0; //用于段码输送
reg [0:7] smg; //保存输送的段码
reg [0:1] who = 0; //决定调整哪一个时间单元
reg [0:7] light; //保存LED的值
reg [7:0] s = 0; //记录小时
reg [7:0] f = 0; //记录分钟
reg [7:0] m = 0; //记录秒
reg [7:0] cd = 0; //传递变量
reg [3:0] gw = 0; //个位
reg [3:0] sw = 0; //十位
reg [17:0] shift_reg = 0; //移位寄存器
reg DIR = 1'b0; //分频计
reg state = 1'b0; //时钟状态
reg shine = 1'b0; //暗灭状态
parameter xd = 21'd2000000; //计时_20ms
parameter CNT_1S_MAX = 26'd50_000_000 ;//The frequency is 1Hz,and the period is 1s.
reg [25:0] cnt_11s;
wire cnt_1s_flag ;
reg clk_1hz ;
assign cnt_1s_flag = (cnt_11s==(CNT_1S_MAX-1'b1));
always @ (posedge clk) begin
if(cnt_1s_flag) begin
cnt_11s<=26'd0;
clk_1hz<=~clk_1hz;
end
else begin
cnt_11s<=cnt_11s+1'b1;
clk_1hz<=clk_1hz;//It's best not to omit.
end
end
always @ (posedge clk_1hz or negedge rst ) begin
if(!rst) begin
day_h<=4'd0;
day_l<=4'd0;
month_h<=4'd0;
month_l<=4'd0;
end
else begin
if(month_adj) begin//While month_adj=1,adjust month.
if(month_l == 4'd9) begin
month_l<=4'd0;
month_h<=month_h+1'b1;
end
else if((month_h==4'd1) && (month_l==4'd2))begin
month_l<=4'd0;
month_h<=4'd0;
end
else begin
month_l<=month_l+1'b1;
month_h<=month_h;//It's best not to omit.
end
end
else if(!day_adj) begin //While day_adj=1,adjust day.
if(day_l==4'd9) begin
day_l<=4'd0;
if(day_h==4'd2)
day_h<=4'd0;
else
day_h<=day_h+1'b1;
end
else begin
day_l<=day_l+1'b1;
day_h<=day_h;
day_l <= day_l;
end
end
else if(day_l==4'd9) begin
day_l<=4'd0;
if(day_h==4'd3) begin
day_h<=4'd0;
if(month_l==4'd9)begin
month_l<=4'd0;
month_h<=month_h+1'b1;
end
else if((month_h==4'd1) && (month_l==4'd2)) begin
month_l<=4'd0;
month_h<=4'd0;
// if(day==4'd7)
// day<=4'd1;
end
// else
month_l <= month_l + 1;
end
else
day_h<=day_h+1'b1;
end
else
day_l<=day_l+1'b1;
end
end
always@(posedge clk) begin //消抖计时
if(key == 5'b00000) //抖动即重新开始
cnt_xd <= 0;
else if(cnt_xd == xd)
cnt_xd <= xd;
else
cnt_xd <= cnt_xd + 1;
end
always@(posedge clk) begin
if(cnt_xd == 0)
key_out <= 0;
else if(cnt_xd == (xd - 21'b1)) //产生1个时间单位的按键信号
case(key) //根据键入得到对应的值
5'b10000: key_out <= 1;
5'b00100: key_out <= 2;
5'b00010: key_out <= 3;
endcase
else
key_out <= 0; //0表示无按键按下
end
always@(posedge clk) begin
if(key_out == 1)
state <= ~state; //状态变换,0表示时钟运行,1表示时间调整
else
state <= state;
end
always@(posedge clk) begin
if(state == 1)
begin
if(key_out == 2)
begin
who = who + 1;
if(who == 3)
who = 0;
else
who = who;
end
end
else
who = 0;
end
always@(posedge clk) begin //数码管扫描计时
if(cnt == 18'd200000) //500Hz
begin
cnt <= 0;
DIR <= 1'b1; //产生一个上升沿
end
else
begin
cnt <= cnt +1;
DIR <= 1'b0;
end
end
always@(posedge DIR) begin
if(cnt_wz == 7)
cnt_wz <= 0;
else
cnt_wz <= cnt_wz + 1; //cnt_wz表示不同数码管的状态
end
always@(posedge clk) begin //根据cd的值来计算不同类型的时间
case(cnt_wz)
3'd0: cd <= s;
3'd3: cd <= f;
3'd6: cd <= m;
default: cd <= cd;
endcase
end
always@(posedge clk) begin //计时1s
if(state == 0)
begin
if(cnt_1s == 27'd100000000) //若感觉计时非1s,可以修改这里的数值
cnt_1s <= 0;
else
cnt_1s <= cnt_1s + 1;
end
else
cnt_1s <= 0;
end
always@(posedge clk) begin //控制数码管的闪烁
if(state == 1)
begin
if(cnt_s == 26'd50000000) //0.5s变换
begin
cnt_s <= 0;
shine <= ~shine; //暗灭转换
end
else
cnt_s <= cnt_s + 1;
end
else
cnt_s <= 0;
end
always@(posedge clk) begin //时间计算逻辑单元
if(!rst)
m = 0;
else if(state == 0)
if(cnt_1s == 27'd100000000)
m = m +1; //秒计时
else if(m == 60) //若秒计时到60
begin
f = f + 1; //分+1
m = 0;
if(f == 60) //若分到60
begin
s = s + 1; //小时+1
f = 0;
if(s == 24) //若时到24
s = 0; //小时归零
else
s = s;
end
else
f = f;
end
else
m = m;
else
begin
if(key_out == 3) //进入时间调制状态
case(who)
2'd0: begin
s = s + 1;
if(s == 24)
s = 0;
else
s = s;
end
2'd1: begin
f = f + 1;
if(f == 60)
f = 0;
else
f = f;
end
2'd2: begin
m = m + 1;
if(m == 60)
m = 0;
else
m = m;
end
default: m = m;
endcase
else
begin
s = s;
f = f;
m = m;
end
end
end
always@(posedge clk) //用来控制移位
begin
if(count == 9) //由于这里原码为8bit,故只需要移位10位就可以得到结果
count <= 0;
else
count <= count + 1;
end
always@(posedge clk) begin //下面程序完成二进制码到BCD码的变换
if(count == 0)
shift_reg={10'b0000000000,cd};
else if (count<=8)
begin
if(shift_reg[11:8] >= 5) //大于等于5就加3,下面同理
begin
if(shift_reg[15:12] >= 5)
begin
shift_reg[15:12]=shift_reg[15:12]+2'b11;
shift_reg[11:8]=shift_reg[11:8]+2'b11;
shift_reg = shift_reg<<1;
end
else
begin
shift_reg[15:12]=shift_reg[15:12];
shift_reg[11:8]=shift_reg[11:8]+2'b11;
shift_reg=shift_reg<<1;
end
end
else
begin
if(shift_reg[15:12] >= 5)
begin
shift_reg[15:12]=shift_reg[15:12]+2'b11;
shift_reg[11:8]=shift_reg[11:8];
shift_reg=shift_reg<<1;
end
else
begin
shift_reg[15:12]=shift_reg[15:12];
shift_reg[11:8]=shift_reg[11:8];
shift_reg=shift_reg<<1;
end
end
end
end
always@(posedge clk) begin
if(count==9) //移位结束
begin
gw <= shift_reg[11:8]; //个位
sw <= shift_reg[15:12]; //十位
end
else
begin
gw <= gw;
sw <= sw;
end
end
always@(posedge clk) begin
case(cnt_wz) //决定哪一位数码管亮
3'd0: begin
if(shine == 0) //shine为0表示亮
wz <= 8'b10000000;
else if(who == 0) //shine为1且为当前时间类型,灭
wz <= 8'b00000000;
else //不为当前时间类型,仍保持亮
wz <= 8'b10000000;
end
3'd1: begin
if(shine == 0)
wz <= 8'b01000000;
else if(who == 0)
wz <= 8'b00000000;
else
wz <= 8'b01000000;
end
3'd2: wz <= 8'b00100000;
3'd3: begin
if(shine == 0)
wz <= 8'b00010000;
else if(who == 1)
wz <= 8'b00000000;
else
wz <= 8'b00010000;
end
3'd4: begin
if(shine == 0)
wz <= 8'b00001000;
else if(who == 1)
wz <= 8'b00000000;
else
wz <= 8'b00001000;
end
3'd5: wz <= 8'b00000100;
3'd6: begin
if(shine == 0)
wz <= 8'b00000010;
else if(who == 2)
wz <= 8'b00000000;
else
wz <= 8'b00000010;
end
3'd7: begin
if(shine == 0)
wz <= 8'b00000001;
else if(who == 2)
wz <= 8'b00000000;
else
wz <= 8'b00000001;
end
default: wz <= 8'b00000000;
endcase
end
always@(posedge clk) begin
if(qiehuan == 1)
begin
case(cnt_wz) //数码管要要显示的数值
4'd0: num <= sw; //输送十位
4'd1: num <= gw; //输送个位
4'd2: num <= 12; //12无意义,仅用于下面的判断
4'd3: num <= sw;
4'd4: num <= gw;
4'd5: num <= 12; //本12同理上面
4'd6: num <= sw;
4'd7: num <= gw;
default: num <= 0;
endcase
end
else if(qiehuan == 0)
begin
case(cnt_wz) //数码管要要显示的数值
4'd0: num <= 2; //输送十位
4'd1: num <= 0; //输送个位
4'd2: num <= 2; //12无意义,仅用于下面的判断
4'd3: num <= 3;
4'd4: num <= month_h;
4'd5: num <= month_l; //本12同理上面
4'd6: num <= day_h;
4'd7: num <= day_l;
default: num <= 0;
endcase
end
end
always @(posedge clk) begin
if(num <= 9)
case(num) //根据num的值决定输出的段码
4'd0: smg <= 8'b11111100;
4'd1: smg <= 8'b01100000;
4'd2: smg <= 8'b11011010;
4'd3: smg <= 8'b11110010;
4'd4: smg <= 8'b01100110;
4'd5: smg <= 8'b10110110;
4'd6: smg <= 8'b10111110;
4'd7: smg <= 8'b11100000;
4'd8: smg <= 8'b11111110;
4'd9: smg <= 8'b11110110;
default: smg <= 8'b00000000;
endcase
else
smg <= 8'b00000010; //不同类型间的分隔符
end
always@(posedge clk) //LED仅用于状态的判断,若不需要可以去掉
case(who)
2'd0: light <= 8'b10000000;
2'd1: light <= 8'b11000000;
2'd2: light <= 8'b11100000;
endcase
assign seg_data0 = smg; //段码输送
assign seg_data1 = smg;
assign seg_cs = wz; //位选输送
assign led = light; //LED输送
endmodule
set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports clk]
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports rst]
#数码管位选
set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports {seg_cs[0]}]
set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {seg_cs[1]}]
set_property -dict {PACKAGE_PIN C1 IOSTANDARD LVCMOS33} [get_ports {seg_cs[2]}]
set_property -dict {PACKAGE_PIN H1 IOSTANDARD LVCMOS33} [get_ports {seg_cs[3]}]
set_property -dict {PACKAGE_PIN G1 IOSTANDARD LVCMOS33} [get_ports {seg_cs[4]}]
set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {seg_cs[5]}]
set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {seg_cs[6]}]
set_property -dict {PACKAGE_PIN G6 IOSTANDARD LVCMOS33} [get_ports {seg_cs[7]}]
#数码管段选
set_property -dict {PACKAGE_PIN B4 IOSTANDARD LVCMOS33} [get_ports {seg_data0[0]}]
set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports {seg_data0[1]}]
set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports {seg_data0[2]}]
set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {seg_data0[3]}]
set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {seg_data0[4]}]
set_property -dict {PACKAGE_PIN B3 IOSTANDARD LVCMOS33} [get_ports {seg_data0[5]}]
set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {seg_data0[6]}]
set_property -dict {PACKAGE_PIN D5 IOSTANDARD LVCMOS33} [get_ports {seg_data0[7]}]
#另一组数码管段选
set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports {seg_data1[0]}]
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {seg_data1[1]}]
set_property -dict {PACKAGE_PIN D3 IOSTANDARD LVCMOS33} [get_ports {seg_data1[2]}]
set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {seg_data1[3]}]
set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {seg_data1[4]}]
set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {seg_data1[5]}]
set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {seg_data1[6]}]
set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {seg_data1[7]}]
#八个LED
set_property -dict {PACKAGE_PIN F6 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN G3 IOSTANDARD LVCMOS33} [get_ports {led[2]}]
set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {led[3]}]
set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {led[4]}]
set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {led[5]}]
set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {led[6]}]
set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {led[7]}]
#五个按键
set_property -dict {PACKAGE_PIN R11 IOSTANDARD LVCMOS33} [get_ports {key[0]}]
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {key[1]}]
set_property -dict {PACKAGE_PIN R15 IOSTANDARD LVCMOS33} [get_ports {key[2]}]
set_property -dict {PACKAGE_PIN V1 IOSTANDARD LVCMOS33} [get_ports {key[3]}]
set_property -dict {PACKAGE_PIN U4 IOSTANDARD LVCMOS33} [get_ports {key[4]}]
set_property PACKAGE_PIN P5 [get_ports {qiehuan[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {qiehuan[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports day_adj]
set_property IOSTANDARD LVCMOS33 [get_ports month_adj]
set_property PACKAGE_PIN N4 [get_ports month_adj]
set_property PACKAGE_PIN R1 [get_ports day_adj]
如图,最左边的一个拨码开关可以切换时间与日期的界面,最右边的两个拨码开关可以调整日期,3个按键可以调整日期。