基于Verilog HDL的数字时钟设计
一、实验内容:
利用FPGA实现数字时钟设计,附带秒表功能及时间设置功能。时间设置由开关S1和S2控制,分别是增和减。开关S3是模式选择:0是正常时钟显示;1是进入调分模式;2是进入调时模式;3是进入秒表模式,当进入秒表模式时,S1具有启动和停止功能,S2具有复位归零功能。只有四位数码管,所以没有做万年历,下一步会在这个基础上加入定时闹钟。
二、实验板
自个制作的实验板,用的是Altera CycloneIII EP3C40Q240C8N。上面的这块板是简单的外围电路,有流水灯、EEPROM、蜂鸣器、MAX3232、拨码开关、开关按键。PS2解码、VGA、AD转换等外围电路正在筹划中。
二、实验原理图设计
1、数码管原理图:利用74HC245驱动7段共阴极数码,其中F_X是代表接入到FPGA的I/O口。
2、开关原理图
三、整体架构设计
1、模块结构
2、RTL Viewer
四、各个击破
第1步:数码管显示,四位数码管的a~g、dp都是复用的,得先让四位数码管能分别显示不同的数据。大家都应该想到了“同步动态扫描”。我是这样做的:每位数码工作5ms,并采取流水方式进行循环操作(列扫描),每位数码即将工作那一刻,同时给a~g送入数据,数据保留5ms并进行定时更新数据(行扫描),行与列保持同步。定时开关,定时发送数据。下图有点错误,其实是在低电平是有效的,高低电平反了。
第2步:小数点显示,为了与时钟显示格式更为逼真,让中间的小数点一直亮着(充分利用资源吧),其他小数点要灭掉,很不幸运,不能直接把data_dp管脚直接拉高或拉低,这里是给该管脚产生周期为20ms,占空比为3/4的一个时钟信号,下图高低电平反了。
第3步:要让不同数码显示不同数据,那么就得事先编好每位数码管要显示的数据。由于时钟与秒表显示的最大数据不一样,得单独编码,这步很简单,一看代码就知道。
第4步:开关的信号输入,涉及到开关,那么就得消抖。这里借鉴特权的方法实现的。
把要做的实验思路搞清楚后,那么数字时钟设计应该很快就会完成。
五、各模块的信号输入/输出定义
Setting.v |
||
Pin Name |
I/O |
Description |
clk |
input |
主时钟27MHZ |
rst_n |
input |
系统复位,低有效 |
add_in |
input |
开关S1的输入 |
sub_in |
input |
开关S2的输入 |
model_in |
input |
开关S3的输入 |
Hour_Ten |
output |
时的十位 |
Hour_One |
output |
时的个位 |
Minute_Ten |
output |
分的十位 |
Minute_One |
output |
分的个位 |
Display_Model |
output |
控制时钟与秒表的显示切换 |
M_Start |
output |
启动/停止秒表计数器 |
M_Reset |
output |
复位归零 |
control_wei.v |
||
Pin Name |
I/O |
Description |
clk |
input |
主时钟27MHZ |
rst_n |
input |
系统复位,低有效 |
select_wei |
output |
控制数码管流水工作 |
miaobiao.v |
||
Pin Name |
I/O |
Description |
clk |
input |
主时钟27MHZ |
rst_n |
input |
系统复位,低有效 |
M_Start |
input |
启动/停止秒表计数器 |
M_Reset |
input |
复位归零 |
S_data1 |
output |
秒表:第一位数码管数据编码 |
S_data2 |
output |
秒表:第二位数码管数据编码 |
S_data3 |
output |
秒表:第三位数码管数据编码 |
S_data4 |
output |
秒表:第四位数码管数据编码 |
control_display.v |
|||
Pin Name |
I/O |
Description |
|
clk |
input |
主时钟27MHZ |
|
rst_n |
input |
系统复位,低有效 |
|
H_data1 |
input |
时钟:第一位数码管数据 |
|
H_data2 |
|
时钟:第二位数码管数据 |
|
H_data3 |
input |
时钟:第三位数码管数据 |
|
H_data4 |
input |
时钟:第四位数码管数据 |
|
S_data1 |
input |
秒表:第一位数码管数据 |
|
S_data2 |
input |
秒表:第二位数码管数据 |
|
S_data3 |
input |
秒表:第三位数码管数据 |
|
S_data4 |
input |
秒表:第四位数码管数据 |
|
Display_Model |
input |
控制时钟与秒表的显示切换 |
|
data |
output |
送出7段a~g数据 |
|
data_dp |
output |
小数点 |
clock_top.v |
||
Pin Name |
I/O |
Description |
clk |
input |
主时钟27MHZ |
rst_n |
input |
系统复位,低有效 |
add_in |
input |
开关S1的输入 |
sub_in |
input |
开关S2的输入 |
model_in |
input |
开关S3的输入 |
data |
output |
送出7段a~g数据 |
select_wei |
output |
控制数码管流水工作 |
data_dp |
output |
小数点 |
六:代码的实现
control_wei.v


1 /***********************************************/ 2 //四位数码管进行流水控制,每位数码管工作5MS 3 /***********************************************/ 4 module control_wei( 5 clk, 6 rst_n, 7 select_wei, 8 ); 9 input clk; 10 input rst_n; 11 output[3:0] select_wei; 12 13 /**********************************************/ 14 parameter T5MS = 18'd134_999; 15 /**********************************************/ 16 reg[3:0] select_wei; 17 reg[17:0] cnt; 18 always @(posedge clk or negedge rst_n) 19 if(!rst_n) cnt <= 18'd0; 20 else if(cnt == T5MS) 21 cnt <= 18'd0; 22 else 23 cnt <= cnt + 1'b1; 24 /**********************************************/ 25 //通过移位方式进行流水工作,定时开关 26 always @(posedge clk or negedge rst_n) 27 if(!rst_n) begin 28 select_wei <= 4'd7; 29 end 30 else if(cnt == T5MS) begin 31 if(select_wei == 4'd14) 32 select_wei <= 4'd7; 33 else 34 select_wei <= { 1'b1,select_wei[3:1]}; 35 end 36 endmodule 37 38
setting.v


1 module setting( 2 //input 3 clk, 4 rst_n, 5 add_in,//增加按钮 6 sub_in,//减去按钮 7 model_in,//模式选择 8 9 //output 10 Hour_Ten, 11 Hour_One, 12 Minute_Ten, 13 Minute_One, 14 Display_Model, 15 M_Start, 16 M_Reset, 17 ); 18 input clk; 19 input rst_n; 20 input add_in; 21 input sub_in; 22 input model_in; 23 24 output [1:0] Hour_Ten; 25 output [3:0] Hour_One; 26 output [2:0] Minute_Ten; 27 output [3:0] Minute_One; 28 output Display_Model; 29 output M_Start; 30 output M_Reset; 31 32 /************************************/ 33 parameter T20MS = 20'd539_999; 34 parameter T1S = 25'd26_999_999; 35 parameter T60S = 31'd1_619_999_999; 36 /************************************************/ 37 //检测下降沿脉冲key_en = key_rst_r & (~key_rst); 38 //key_rst_r要晚一个时钟节拍才能得到key_rst的值 39 //key_rst在1变为0时,key_en置位 40 //key_rst 1 1 0 1 1 41 //key_rst_r 1 1 0 1 1 42 //~key_rst 0 0 1 0 0 43 //-------------------------- 44 //key_en 0 0 1 0 0 45 46 //检测上升沿脉冲key_en = (~key_rst_r) & key_rst; 47 //key_rst在0变为1时,key_en置位 48 //key_rst 0 0 1 0 0 49 //key_rst_r 0 0 1 0 0 50 51 //key_rst 0 0 1 0 0 52 //~key_rst_r 1 1 0 1 1 53 //-------------------------- 54 //key_en 0 0 1 0 0 55 /************************************************/ 56 reg[2:0] key_rst; 57 always @(posedge clk or negedge rst_n) 58 if(!rst_n) key_rst <= 3'b111; 59 else key_rst <= {add_in,sub_in,model_in}; 60 61 reg[2:0] key_rst_r; 62 always @(posedge clk or negedge rst_n) 63 if(!rst_n) key_rst_r <= 3'b111; 64 else key_rst_r <= key_rst; 65 66 wire[2:0] key_en; 67 assign key_en = key_rst_r & (~key_rst); 68 /*