功能数字钟
文章目录
实验目的
(1)在FPGA中实现具有以下功能的数字钟:准确授时;校准功能;准确报时。
(2)掌握在用Verilog语言编写代码时的语法结构。
(3)理解程序设计的逻辑结构。
分析设计平台及工具
Quartus II集成开发环境、Verilog语言、FPGA开发板等。
实验设计思路
从实验目的我们可以知道该功能数字钟系统包括以下几个功能模块:授时、报时、校准。
同时根据实验要求,在进行授时的时候,包括时、分、秒和星期的授时,其中分、秒位60进制,时为24进制,周为七进制。
在进行报时的过程中,要求在到达整点时,先每隔两秒发出“滴”声,随后在整点时,发出“嗒”声。然后通过改变输送到蜂鸣器的导通信号的频率,来改变蜂鸣器发声的频率,控制蜂鸣器产生“嘀、嗒”的报时声。
在进行授时的过程中,通过50MHz的基准时钟信号的输入,将50M分频得到1Hz的数字工作频率CLK_1Hz,来控制钟表的授时。
在进行校准的过程中,通过DisoWeek_n控制星期显示输出信号,通过AdjWeek、AdjtHour 、AdjtMin来进行星期、小时、和分钟的调节。当 AdjtWeek=1 时,每来一个标准秒脉冲 CLK_1HZ 的上升沿,星期增加基于一天。
在进行时间的显示时,Digitron_Out控制七段数码管的显示输出,共有八位总线。DigitronCS_Out为数码管的片选信号,共有六位总线。也称七段数码管的扫描驱动信号,扫描频率为 250KHz。
所以,根据其功能类别和实验要求,可以得出,实现功能数字钟需要以下几个模块:即计时模、校时模块、报时模块和数码显示模块。图2.1为系统原理示意图。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gfj93Yti-1656149962631)(C:\Users\ZanZhiYun\Desktop\数电实验2\2_1.png)]
如上述原理图,我们在进行Verilog语言进行编辑程序设计的时候,需要接口AdjWeek来调整星期,需要接口AdjHour来调整小时,需要接口AdjMin来调整分钟。同时,由于FPGA开发板上只有6个数码管,不足以将时分秒和星期全部展示出来,所以用到DispWeek来展示星期界面。
接口函数Digitron_Out(),DigitronCS_Out()是进行数码的展示输出的设计,而Buzzer_Out()是用来进行蜂鸣器的设计。
通过以上原理介绍,我们可以划分一下设计模块,如图2.2所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EVWR0L5r-1656149962634)(C:\Users\ZanZhiYun\Desktop\数电实验2\2_2.png)]
程序设计分析
在程序设计分析这一节,我截取了不同模块的关键代码部分进行了代码功能分析。
clock.v模块
该代码框架实现的是顶层模块对底层模块的调用。
module clock
(
);
endmodule
U1,U2,U3实现的是clock.v对底层模块的调用。
TimeKeeper_module U1
(
);
Digitron_TimeDisplay_module U2
(
);
Buzzer_module U3
(
);
TimeKeeper_module.v
当时钟信号处于上升沿时,如果计数器的值为T1HZ对应该电平状态最后一个点值时,Count置零,同时CLK_1HZ置为与原电平相反的电平值;如果计数器为其他值,则当达到敏感条件(即CLK处于上升沿)时,Count+1。
always @ ( posedge CLK )
begin
if( Count == T1HZ - 25'b1 )
begin
Count <= 0;
CLK_1HZ <= ~CLK_1HZ;
end
else
Count <= Count + 1;
end
当处于时钟信号上升沿或者处于复位信号下降沿时,如果复位信号为低电平,则各时间的各位恢复设定值,如果复位信号不是低电平,则当有时间调整信号时,则进行时间调整,同时通过判断语句进行时分秒和周的进位。
always @ ( posedge CLK_1HZ or negedge RSTn )
begin
if( !RSTn )
begin
SecL <= 0;
SecH <= 0;
MinL <= 0;
MinH <= 0;
HourL <= 0;
HourH <= 0;
Week <= 1;
end
else
begin
if( AdjtWeek == 1 ) //While AdjtWeek = 1, Adjust Week
begin
if( Week == 'd7 )
Week <= 1;
else
Week <= Week + 1;
end
else if( AdjtHour == 1 ) //Adjust Hour
begin
if( HourL == 'd9 )
begin
HourL <= 0;
HourH <= HourH + 1;
end
else
begin
if( HourH == 'd2 && HourL == 'd3 )
begin
HourL <= 0;
HourH <= 0;
end
else
HourL <= HourL + 1;
end
end
else if( AdjtMin == 1 ) //Adjust Minute
begin
if( MinL == 'd9)
begin
MinL <= 0;
if(MinH == 'd5)
MinH <= 0;
else
MinH <= MinH + 1;
end
else
MinL <= MinL + 1;
end
else if( SecL == 'd9 ) //Clock is Working
//......(此处略)
Digitron_TimeDisplay_module.v
parameter进行对预输出的11位数进行数码管编码的定义。
parameter _0 = 8'b0011_1111, _1 = 8'b0000_0110, _2 = 8'b0101_1011,
_3 = 8'b0100_1111, _4 = 8'b0110_0110, _5 = 8'b0110_1101,
_6 = 8'b0111_1101, _7 = 8'b0000_0111, _8 = 8'b0111_1111,
_9 = 8'b0110_1111, _Ri= 8'b0111_1111;
当时钟信号处于上升沿时,如果DispWeek_n处于低电平或者AdjtWeek处于高电平,六只数码管只显示最右边的第一个数码管。然后通过case列举7种情况,对应一周的7天。对于Count=100MS的情况而言,W_DigitronCS_Out = {…}用于六个数码管每隔100ms进行移位数值刷新。如果无操作动作的话,则Count计数循环加1,等到下一次操作输入,或下一轮的数码管刷新。
always @ ( posedge CLK )
begin
if( (DispWeek_n == 0) || (AdjtWeek == 1) ) //Digitron Display Week
begin
W_DigitronCS_Out = 6’b11_1110;
SingleNum = Week;
case(SingleNum)
'd0: W_Digitron_Out = _0;
'd1: W_Digitron_Out = _1;
'd2: W_Digitron_Out = _2;
'd3: W_Digitron_Out = _3;
'd4: W_Digitron_Out = _4;
'd5: W_Digitron_Out = _5;
'd6: W_Digitron_Out = _6;
'd7: W_Digitron_Out = _Ri;
endcase
end
else if( Count == T100MS )
begin
Count <= 23'd0;
W_DigitronCS_Out = {W_DigitronCS_Out[0],W_DigitronCS_Out[5:1]};
if(W_DigitronCS_Out == 6'd0)
W_DigitronCS_Out = 6'b11_1110;
case(W_DigitronCS_Out)
6'b11_1110: SingleNum = SecL;
6'b11_1101: SingleNum = SecH;
6'b11_1011: SingleNum = MinL;
6'b11_0111: SingleNum = MinH;
6'b10_1111: SingleNum = HourL;
6'b01_1111: SingleNum = HourH;
endcase
case(SingleNum)
'd0: W_Digitron_Out = _0;
'd1: W_Digitron_Out = _1;
'd2: W_Digitron_Out = _2;
'd3: W_Digitron_Out = _3;
'd4: W_Digitron_Out = _4;
'd5: W_Digitron_Out = _5;
'd6: W_Digitron_Out = _6;
'd7: W_Digitron_Out = _7;
'd8: W_Digitron_Out = _8;
'd9: W_Digitron_Out = _9;
endcase
end
else
Count <= Count + 1'b1;
end
Buzzer_module.v
当时钟信号处于上升沿的时候,如果时间到达59’50’'时,蜂鸣器每间隔两秒发出“Di”的声音,当时间到达整点的时候发出“Da”的声音。其中两个always@语句分别为定义蜂鸣器发声节点,和蜂鸣器发生动作。
always @( posedge CLK )
begin
if( MinH == 'd5 && MinL == 'd9 && SecH == 'd5 ) //While Time = 59'50"
begin
if( (SecL % 2) == 0)
Pulse_x <= Di; //Di
else
Pulse_x <= 20000;
end
else if( MinH == 0 && MinL == 0 && SecH == 0 && SecL == 0 ) //While Time = 00'00"
Pulse_x <= Da; //Da
else
Pulse_x <= 20000;
end
always @ ( posedge CLK )
begin
if( (Pulse_x == Di) | (Pulse_x == Da) )
begin
if( Count == Pulse_x )
begin
Count <= 23'd0;
W_buzzer <= ~W_buzzer;
end
else
Count <= Count + 1'b1;
end
else
begin
W_buzzer <= 1'b1;
Count <= 23'd0;
end
end
实验结果及分析
实验结果及分析这一节,我将Verilog程序烧录到FPGA开发板中,并进行了功能数字钟的功能展示。结果如下截图。
结果一
本章截图展示的是功能数字钟时分秒计时功能六个数码管自左到右,分别为时、分、秒。当程序开始运行时时间开始由00:00:00开始计时。
csdnimg.cn/7f3eb8afaa754a95b0681c6489504b56.jpeg)
结果二
当调节SW1为低电平后,钟表计时停止,数码管开始自动进行分的调整,值“分”(中间两位)按正序加1。当到达60时,开始进位。当把SW1调节为高电平后,钟表恢复计时。
结果三
当调节SW2为低电平时,数码管开始进行时的自动调整,值“时”按序加1,当满足进位条件时,Week+1。
结果四
当使KEY1处于低电平时,数码管左5位数码管熄灭,右一位显示星期数。如图此时为星期四。
结果五
如下截图展示的为在59’50’‘-00’00’'时,每间隔2秒进行报时的过程。
实验总结
在本次实验中,我进行了一次小型数字电路系统的分析。通过分析,我初步了解了一个数字电路系统的设计原则,设计思路和设计模块。我认识到一个完整的系统需要根据系统结构来对设计方法进行选择。
在功能数字钟这个实验中,程序块包括一个顶层模块,若干个底层模块和底层模块下的子模块。顶层模块实现了对底层模块的调用,底层模块实现对复杂系统功能的分块解决,而底层模块的子模块实现了对功能的进一步细化,于是一个较复杂的系统被分解为了若干个简单的系统的组成部分。这种思想一方面简化了系统设计过程,另一方面方便了设计者的调试。
在进行代码功能分析的过程中,我一方面遇到了语法和基础知识上的问题,另一方面我通过不断去复习基础知识和向同学请教,我逐步掌握了各个代码块的含义,和代码作者在进行代码设计时,进行的debug的巧妙思路。
这次实验我有很多收获,一方面我进一步了解了Verilog语言的语法和软件平台的使用方法;另一方面,我认识到有时候自己认为的不重要其实是自己没用意识到它的重要性,要想从事件中收获更多,就需要我们能够认真对待一件事情中的每一个细节。