基于 FPGA 实现多功能数字钟
摘要
本文利用Verilog HDL语言自顶向下的设计方法设计多功能数字钟,并通过
ISE完成综合、仿真。此程序通过下载到FPGA 芯片后,可应用于实际的数字钟显
示中,实现了基本的计时显示和设置,调整时间,闹钟设置的功能。
[关键词] FPGA;Verilog HDL;数字钟
一、多功能数字钟的设计
设计一个多功能数字时钟,具有时分、秒计数显示、闹钟功能。能够利用按
键实现对闹钟时间的设定并在当前显示时间到时后能够进行闹钟提示。能够利用
按键实现“较时”、“较分”功能,随时对数码管的显示进行校正和校对。数字
中系统主要由系统时钟,三个功能按键(mode,turn,change),FPGA,数码管
和蜂鸣器部分组成。
数码管
显示模块
分
频
模
块
Clk
计时模块
闹钟模块
蜂
鸣
器
控制模块
图: 多功能数字钟总体设计模块
以下就各个模块说明其功能
1. 分频模块
由于 FPGA 内部提供的时钟信号频率大约为 50MHz,在这需要将它转化成 1Hz 的标准时钟
信号供数字钟的计时显示;在此我采用了级联分频法。
RTL 图如下:
代码如下:
//fenpin
module fenpin(clk,clk_1Hz,clk_100Hz,clk_1k);
output clk_1Hz,clk_100Hz,clk_1k;
input clk;
reg clk_1Hz=0,clk_3=0,clk_1=0,clk_2=0,clk_1k=0;
reg [6:0] cnt1=0,cnt2=0,cnt3=0,cnt4=0,cnt5=0;
wire clk_100Hz;
always @(posedge clk)
begin
if ( cnt1 < 156/2-1)
/////////////////////////////////////////////156 分频,生成 1MHz 信号
begin
cnt1 <= cnt1 + 1;
end
else
begin
cnt1 <= 0;
clk_1 <= ~clk_1;
end
end
always @(posedge clk_1)
if ( cnt2 < 156/2-1)
/////////////////////////////////////100 分频,生成 10000Hz 信号
begin
cnt2 <= cnt2 + 1;
end
else
begin
cnt2 <= 0;
clk_2 <= ~clk_2;
end
always @(posedge clk_2)
if ( cnt5 < 10/2-1)
/////////////////////////////////////////10 分频,生成 1kHz 标准信号
begin
cnt5<= cnt5 + 1;
end
else
begin
cnt5<= 0;
clk_1k<= ~clk_1k;
end
always @(posedge clk_2)
if ( cnt3 < 100/2-1)
//////////////////////////////////////////100 分频,生成 100Hz 信号
begin
cnt3 <= cnt3 + 1;
end
else
begin
cnt3 <= 0;
clk_3 <= ~clk_3;
end
assign clk_100Hz=clk_3;
always @(posedge clk_3)
if ( cnt4 < 100/2-1)
/////////////////////////////////////////100 分频,生成 1Hz 标准信号
begin
cnt4<= cnt4 + 1;
end
else
begin
cnt4<= 0;
clk_1Hz<= ~clk_1Hz;
end
endmodule
最终输出的是 1Hz,100Hz,1kHz 的标准时钟信号 clk_1Hz ,clk_100Hz,clk_1k。
2、 计时模块
原理:m 是模式按键,当 m=0 时,进入计时模式,在计时模式下可以进行时间调整。num3,
num4 产生加速调整时间,当其值为 1 时,可以快速调整时间,该调整时间的频率由 clk 提
供。counta,count1 是手动调节时间。Turn 接按键,可以改变当前调节的是小时还是分钟,
长按 turn 键还可以使秒钟信号清零。sec1,min1,hour1 输出的是计时的秒,分,时。
RTL 图如下:
代码如下:
//jishi
module jishi(clk,clk_1Hz,
turn,//// turn: 接按键,在手动校时功能时,选择是调整小时,还是分钟;若长时间按住该键,还可使
秒信号清零,用于精确调时
mode,count1,counta,sec1,min1,hour1,num3,num4);
input clk,clk_1Hz,turn,num3,num4;
input mode;
input count1,counta;
output [7:0] sec1,min1;
output [7:0] hour1;
wire clk_1Hz,ct1,cta,turn,num3,num4;
reg [7:0] sec1=0,min1=0;
reg [7:0] hour1=0;
reg [1:0] m;
wire count1,counta;
reg minclk,hclk;
always @(posedge mode) //mode 信号控制系统在三种功能间转换
begin
if(m==4) m<=0;
else m<=m+1;
end
/////秒钟计时模块//////
always @(posedge clk_1Hz)
if((sec1==8'h59)|turn&(!m))///////若长时间按住该键,还可使秒信号清零,用于精确调时。
begin
sec1<=0; //按住“turn”按键一段时间,秒信号可清零,该功能用于手动精确调时
if(!(turn&(!m))) minclk<=1;///产生进位
end
else begin
if(sec1[3:0]==4'b1001)
begin sec1[3:0]<=4'b0000;
sec1[7:4]<=sec1[7:4]+1; end
else sec1[3:0]<=sec1[3:0]+1;
minclk<=0;
end
////////分钟计时模?///
assign m_clk=minclk||count1;/////m_clk 产生进位或校正改变
assign ct1=(num3&clk)|(!num3&m_clk); //ct1 用于计时、校时中的分钟计数
always @(posedge ct1)
begin
if(min1==8'h59) begin
min1<=0; hclk<=1; end
else
begin
if(min1[3:0]==9)
begin min1[3:0]<=0;
min1[7:4]<=min1[7:4]+1; end
else min1[3:0]<=min1[3:0]+1;
hclk<=0;
end
end
////////小时计时模块///
assign h_clk=hclk||counta;//////h_clk 产生进位或校正改变
assign cta=(num4&clk)|(!num4&h_clk); //cta 用于计时、校时中的小时计数
always @(posedge cta)
if(hour1==8'h23) hour1<=0;
else
if(hour1[3:0]==9)
begin hour1[7:4]<=hour1[7:4]+1;
hour1[3:0]<=0; end
else hour1[3:0]<=hour1[3:0]+1;
endmodule
3、 闹钟模块
原理:num1,num2 产生加速调整时间,当其值为 1 时,可以快速调整时间,该调整时间的
频率由 clk 提供。countb,count2 是手动调节闹钟时间。amin,ahour 是输出的闹钟的分钟和
小时,LD_alert 指示当前是否开启闹钟。
RTL 图如下:
代码如下:
// Alarm
module Alarm(clk,amin,ahour,num1,num2,count2,countb,LD_alert);
input clk,num1,num2,count2,countb;
output [7:0] amin;
output [7:0] ahour;
output LD_alert;
wire LD_alert;
reg [7:0] amin=0;
reg [7:0] ahour=0;
assign ct2=(num1&clk)|(!num1&count2); //ct2 用于定时状态下调整分钟信号
assign LD_alert=(ahour|amin)?1:0;//指示是否进行了闹铃定时
always @(posedge ct2)
if(amin==8'h59) amin<=0;
else
if(amin[3:0]==9)
begin amin[3:0]<=0;
amin[7:4]<=amin[7:4]+1; end
else amin[3:0]<=amin[3:0]+1;
assign ctb=(num2&clk)|(!num2&countb); ////ctb 用于定时状态调节小时信号
always @(posedge ctb)
if(ahour==8'h23) ahour<=0;
else
if(ahour[3:0]==9)
begin ahour[3:0]<=0; ahour[7:4]<=ahour[7:4]+1;
end
else ahour[3:0]<=ahour[3:0]+1;
endmodule
4、 控制模块(1)
原理:m 是模式按键,当 m=0 时,指当前输出的是计时功能;当 m=1 时,指当前调整的是
闹钟时间;当 m=2 时,指当前调整的是计时时间;当 m=3 时,此时 turn 按键可用于跑表的
暂停与开始。change 接按键,手动调整时,每按一次,计数器加 1;如果长按,则连续快
速加 1,用于快速调时和定时;turn 接按键,在手动校时功能时,选择是调整小时,还是分
钟;若长时间按住该键,还可使秒信号清零,用于精确调时。count1,count2,counta,countb 分
别是用来调节计时时间和闹钟时间。LD_min,LD_hour,指示当前调节的是分钟还是小时。
RTL 图
代码如下:
// ctrol
module ctrol(change,turn,count1,count2,counta,countb,pause,LD_min,LD_hour,mode);
input change,mode,turn;
output count1,count2,counta,countb,pause,LD_min,LD_hour;
reg [1:0] m;
reg fm=0,count1=0,count2=0,counta=0,countb=0,pause=0,LD_min=0,LD_hour=0;
wire mode,turn,change;
always @(posedge mode) //mode 信号控制系统在三种功能间转换
begin
if(m==4) m<=0;
else m<=m+1;
end
always @(posedge turn)//////////接按键,在手动校时功能时,选择是调整小时,还是分钟;
begin
fm<=~fm;
end
always @ (m or fm or change)
begin
case(m)
3: begin ////////3:跑表功能;
if(fm)
pause=1;
else
pause=0;
end
2:
begin ////////2:调节时间功能;
if(fm)
begin
else
count1<=change; {LD_min,LD_hour}<=2; end//////指示当前调整的是分钟
begin counta<=change;
{LD_min,LD_hour}<=1; end/////指示当前调整的是小时
{count2,countb}<=0;
end
1:
begin
//////1:调节闹钟功能
if(fm)
begin
else
count2<=change;
{LD_min,LD_hour}<=2; end/////指示当前调整的是分
begin countb<=change; {LD_min,LD_hour}<=1; end/////指示当前调整的是小时
{count1,counta}<=0;
end
0: begin {count1,count2,counta,countb,LD_min,LD_hour}<=0;end ////0:计时功能
endcase
end
endmodule
5、 控制模块(2)
原理:此模块是加速调节时间模块,count1,count2,counta,countb 是手动调节时间,当长时间
按这些键时,num1,num2,num3,num4 的值会发生变化,当他们值有为 1 时,对应的调节会
快速加 1。
代码如下:
// faster
module faster(clk,num1,num2,num3,num4,count1,count2,counta,countb);
input clk;
input count1,count2,counta,countb;
output num1,num2,num3,num4;
wire count1,count2,counta,countb;
reg[2:0] loop1=0,loop2=0,loop3=0,loop4=0;
reg num1,num2,num3,num4;
always @(negedge clk)//如果长时间按下“change”键,则生成“num*”信号用于连续快速加 1
if(count2)
begin
if(loop1==3) begin loop1<=0; num1<=1; end
else
begin loop1<=loop1+1; num1<=0; end
end
else begin loop1<=0;
num1<=0; end
always @(negedge clk)
if(countb)
begin
if(loop2==3) begin loop2<=0; num2<=1; end
else
begin loop2<=loop2+1;
num2<=0; end
end
else begin loop2<=0;
num2<=0; end
always @(negedge clk)
if(count1)
begin
if(loop3==3) begin loop3<=0; num3<=1; end
else
begin loop3<=loop3+1;
num3<=0; end
end
else begin loop3<=0;
num3<=0; end
always @(negedge clk)
if(counta)
begin
if(loop4==3) begin loop4<=0; num4<=1; end
else
begin loop4<=loop4+1;
num4<=0; end