基于FGA的
VerilogHDL数字钟设
计
集团标准化办公室:[VV986T-J682P28-JP266L8-68PNN]
基于FPGA的Verilog HDL数字钟设计
专业班级 姓 名 学 号
一、实验目的
1.掌握可编程逻辑器件的应用开发技术?——设计输入、编译、仿真和器件编程;
2.熟悉一种EDA软件使用;
3.掌握Verilog设计方法;
4.掌握分模块分层次的设计方法;
5.用Verilog完成一个多功能数字钟设计;
6.学会FPGA的仿真。
二、实验要求 功能要求:
利用实验板设计实现一个能显示时分秒的多功能电子钟,基本功能:
1) 准确计时,以数字形式显示时、分、秒,可通过按键选择当前显示时间范围模
式;
2) 计时时间范围 00:00:00-23:59:59
3) 可实现校正时间功能;
4) 可通过实现时钟复位功能:00:00:00
扩展功能:
5) 定时报:时间自定(不要求改变),闹1分钟(1kHz)---利用板上LED或外接电路实
现。
6) 仿广播电台正点报时:XX:59:[51,53,55,57(500Hz);59(1kHz)] ---用板上LED或
外接
7) 报整点时数:XX:00:[00.5-XX.5](1kHz),自动、手动---用板上LED或外接
8) 手动输入校时;
9) 手动输入定时闹钟;
10) 万年历;
11) 其他扩展功能;
设计步骤与要求:
1) 计算并说明采用Basys2实验板时钟50MHz实现系统功能的基本原理。
2) 在Xilinx ISE13.1 软件中,利用层次化方法,设计实现模一百计数及显示的电
路系统,设计模块间的连接调用关系,编写并输入所设计的源程序文件。
3) 对源程序进行编译及仿真分析(注意合理设置,以便能够在验证逻辑的基础上尽
快得出仿真结果)。
4) 输入管脚约束文件,对设计项目进行编译与逻辑综合,生成下载所需.bit文件。
5) 在Basys2实验板上下载所生成的.bit文件,观察验证所设计的电路功能。
三、实验设计
功能说明:实现时钟,时间校时,闹铃定时,秒表计时等功能
1. 时钟功能:完成分钟/小时的正确计数并显示;秒的显示用LED灯的闪烁做指示;
时钟利用4位数码管显示时分;
2. 闹钟定时:实现定时提醒及定时报时,利用LED灯代替扬声器发出报时声音;
3. 时钟校时:当认为时钟不准确时,可以分别对分钟和小时位的值进行调整;
4. 秒表功能:利用4个数码管完成秒表显示: 可以实现清零、暂停并记录时间等功能。
秒表利用4位数码管计数;
方案说明:本次设计由时钟模块和译码模块组成。时钟模块中50MHz的系统时钟clk分频产生一个1Hz的使能控制信号enable,并以此产生1s的脉冲second_en以实现每秒计时,控制各个模式下的计数显示。
由模式控制信号选择当前数码管显示哪个状态:
mode=00,时钟常规显示状态,
mode=01,闹铃定时状态,
mode=10,时钟校时状态,
mode=11,秒表计时状态;
时钟:利用count,smin0,smin1,shour0,shour1的计数来实现,具体情况见程序;
校时:当turn=1时,调整分位smin1、smin0;当turn=0时,调整小时位shour1、shour0;
闹铃:当turn=1时,调整分位amin1、amin0;当turn=0时,调整小时位ahour1、ahour0;
秒表:当pause=0时,开始计时;当pause=1时,暂停。
四、实验代码
时钟模块
module clock(clk, clr, pause, turn, mode,
sec, min1, min0, hour1, hour0, alert, LD_alert ); input clk; //时钟信号(50MHz) input clr; //清零键 input pause; //秒表暂停键 input turn; //调整分还是小时位的控制 input [1:0]mode; //决定时钟显示功能状态 output sec; //接发光二极管 output [3:0]min1; //用于输出接数码管4
output [3:0]min0; //用于输出接数码管3 output [3:0]hour1; //用于输出接数码管2 output [3:0]hour0; //用于输出接数码管1 output alert; //接发光二极管,代替蜂鸣器 output LD_alert; //当闹铃设定后,发光二极管显示 wire sec; //秒位显示 wire LD_alert; //用于闹铃存在时的提醒显示 //wire clk1; //时钟1s //wire clk2; //时钟100ms,用于秒表最小计时单位 //wire clr1; reg [3:0]min1; //常规显示 reg [3:0]min0; //常规显示 reg [3:0]hour1; //常规显示 reg [3:0]hour0; //常规显示 reg [3:0]smin1; //校时
reg [3:0]smin0; //校时 reg [3:0]shour1; //校时 reg [3:0]shour0; //校时 reg [3:0]amin1; //闹铃 reg [3:0]amin0; //闹铃 reg [3:0]ahour1; //闹铃 reg [3:0]ahour0; //闹铃 reg [3:0]mmin1; //秒表 reg [3:0]mmin0; //秒表 reg [3:0]mhour1; //秒表 reg [3:0]mhour0; //秒表 reg alert; //当闹铃到时高电平输出 reg [7:0]count; reg [24:0]counter; reg enable;
reg en1,en2; wire second_en; always @ (posedge clk) //generate 1s begin if (clr) begin counter = 0; enable = 0; end else begin counter = counter +1; if (counter == 25'd249) // 仿真时可将闸门信号设为0.00001s,加快仿真速度 //
begin enable = ~enable; counter = 25'd0; end end end always @ (posedge clk) // begin if (clr) en2 <= 1'b0; begin en1 <= 1'b0; end else begin en1 <= enable; en2 <= en1; end endassign second_en = (!en1) && (en2); always @(posedge clk) begin if(clr) begin amin1<=0;
amin0<=0; ahour1<=0; ahour0<=0; smin1<=0; smin0<=0; shour1<=0; shour0<=0; mmin1<=0; mmin0<=0; mhour1<=0; mhour0<=0; count<=0; end else if (second_en) begin
count<=count+1; /////////////////////////////////////////////////////////////////////////////////////////// if(mode==2'b01) //闹铃调时状态 if(turn==1) //当turn为高电平时调整分位 if((amin1==5)&&(amin0==9)) begin amin1<=0; amin0<=0; end else if(amin0==9) begin amin1<=amin1+1; amin0<=0;
end else amin0<= amin0+1; else //当turn为低电平时调整小时位 if((ahour1==2)&&(ahour0==3)) begin ahour1<=0; ahour0<=0; end else if(ahour0==9) begin ahour1<=ahour1+1; ahour0<=0;
end else ahour0<=ahour0+1; //////////////////////////////////////////////////////////////////////////////////////// 态 if(mode==2'b10) //时钟调时状 if(turn==1) //当turn为高电平时调整分位 if((smin1==5)&&(smin0==9)) begin smin1<=0; smin0<=0; end else if(smin0==9)
begin smin1<=smin1+1; smin0<=0; end else smin0<=smin0+1; else //当turn为低电平时调整小时位 if((shour1==2)&&(shour0==3)) begin shour1<=0; shour0<=0; end else if(shour0==9)
begin shour1<=shour1+1; shour0<=0; end else shour0<=shour0+1; else //以下是常规显示 begin if(count==59) begin count<=0; smin0<=smin0+1; if (smin0==9) begin smin0<=0;
smin1<=smin1+1; if (smin1==5) begin smin1<=0; shour0<=shour0+1; if (shour0==3) begin shour0<=0; shour1<=shour1+1; if (shour1==2) shour1<=0; end end end end
end //////////////////////////////////////////////////////////////////////////////// if(mode==2'b11) begin //秒表计时状态 if(pause==0) //当pause为低电平时开始计时 begin mmin0<=mmin0+1; if(mmin0==9) begin mmin0<=0; mmin1<=mmin1+1; if(mmin1==9) begin
mmin1<=0; mhour0<=mhour0+1; if (mhour0==9) begin mhour0<=0; mhour1<=mhour1+1; if (mhour1==9) mhour1<=0; end end end end end end end
assign LD_alert=(amin1|amin0|ahour1|ahour0)1:0; //当闹铃有定时后LD_alert发光以示闹铃已定 assign sec=enable; //将秒针接到LED灯 always@(posedge clk) begin if(clr) alert<=0; else if((amin1==smin1)&&(amin0==smin0)&&(ahour1==shour1)&&(ahour0==shour0)) alert<=1; //对闹铃做检查,时间到时发光 else alert<=0; end //以下为选择显示模块
always @ (posedge clk) begin if(clr) begin min1<=0; min0<=0; hour1<=0; hour0<=0; end else begin case(mode) 2'b01: //mode=01时,显示闹铃模块 begin min1<=amin1;
min0<=amin0; hour1<=ahour1; hour0<=ahour0; end 2'b10: //mode=10时,显示校时模块 begin min1<=smin1; min0<=smin0; hour1<=shour1; hour0<=shour0; end 2'b11: //mode=11时,显示秒表模块 begin min1<=mmin1; min0<=mmin0; hour1<=mhour1;
hour0<=mhour0; end 2'b00: begin //其他状态,显示普通时钟模块 min1<=smin1; min0<=smin0; hour1<=shour1; hour0<=shour0; end endcase end end endmodule 译码模块
module display(q,ctr,h1,h0,m1,m0,clk,reset);
output[6:0]q; output[3:0] ctr; input[3:0] h1,h0,m1,m0; input clk,reset; reg[6:0] q; reg[25:0] count; reg[3:0] temp; reg[3:0] scan; //delay yanshi(clk,clk2); always @ (posedge clk) begin if (reset) begin count = 0; end
else begin count = count +1; end end always @ (posedge clk ) //Seg Scan begin if(reset) begin scan<=4'b0000; end else case(count[1:0]) // 仿真时将扫描信号频率加快1000倍 // case(count[11:10]) // 执行设计时将扫描频率改回 2'b00: scan<=4'b0111;
2'b01: scan<=4'b1011; 2'b10: scan<=4'b1101; 2'b11: scan<=4'b1110; endcase end assign ctr = scan; always @ (posedge clk) //Seg Scan begin if(reset) begin temp<=4'b0000; end else case(count[1:0]) // 仿真时将扫描信号频率加快1000倍 // case(count[11:10]) // 执行设计时将扫描频率改回
2'b00: temp<=h1; 2'b01: temp<=h0; 2'b10: temp<=m1; 2'b11: temp<=m0; endcase end always @(posedge clk) //数码管译码 begin if(reset) begin q<=7'b0000000; end else case(temp) 4'd0:q<=7'b0000001; //0
4'd1:q<=7'b1001111; //1 4'd2:q<=7'b0010010; //2 4'd3:q<=7'b0000110; //3 4'd4:q<=7'b1001100; //4 4'd5:q<=7'b0100100; //5 4'd6:q<=7'b0100000; //6 4'd7:q<=7'b0001111; //7 4'd8:q<=7'b0000000; //8 4'd9:q<=7'b0000100; //9 default:q<=7'b0000001; endcase end endmodule UCF文件
NET \"clk\" LOC = \"B8\"; # 50M
# Pin assignment for DispCtl # Connected to Basys2 onBoard 7q display NET \"q<6>\" LOC = \"L14\"; # Bank = 1, Signal name = CA NET \"q<5>\" LOC = \"H12\"; # Bank = 1, Signal name = CB NET \"q<4>\" LOC = \"N14\"; # Bank = 1, Signal name = CC NET \"q<3>\" LOC = \"N11\"; # Bank = 2, Signal name = CD NET \"q<2>\" LOC = \"P12\"; # Bank = 2, Signal name = CE NET \"q<1>\" LOC = \"L13\"; # Bank = 1, Signal name = CF NET \"q<0>\" LOC = \"M12\"; # Bank = 1, Signal name = CG #NET \"dp\" LOC = \"N13\"; # Bank = 1, Signal name = DP NET \"ctr<3>\" LOC = \"K14\"; # Bank = 1, Signal name = AN3 NET \"ctr<2>\" LOC = \"M13\"; # Bank = 1, Signal name = AN2 NET \"ctr<1>\" LOC = \"J12\"; # Bank = 1, Signal name = AN1 NET \"ctr<0>\" LOC = \"F12\"; # Bank = 1, Signal name = AN0 NET \"reset\" LOC = \"N3\"; # Bank = 2, Signal name = SW7
NET \"mode<1>\" LOC = \"E2\"; # Bank = 3, Signal name = SW6 NET \"mode<0>\" LOC = \"F3\"; # Bank = 3, Signal name = SW5 NET \"turn\" LOC = \"G3\"; # Bank = 3, Signal name = SW4 NET \"pause\" LOC = \"B4\"; # Bank = 3, Signal name = SW3 NET \"LD_alert\" LOC = \"P7\" ; # Bank = 3, Signal name = LD2 NET \"alert\" LOC = \"M11\" ; # Bank = 2, Signal name = LD1 NET \"sec\" LOC = \"M5\" ; # Bank = 2, Signal name = LD0 testbench
module tb_test; // Inputs reg clk; reg reset; reg [1:0] mode; reg turn; reg pause;
// Outputs wire [6:0] q; wire [3:0] ctr; wire sec; wire alert; wire LD_alert; // Instantiate the Unit Under Test (UUT) clk uut ( .clk(clk), .reset(reset), .mode(mode), .turn(turn), .pause(pause), .q(q), .ctr(ctr),
.sec(sec), .alert(alert), .LD_alert(LD_alert) ); parameter PERIOD = 10; always begin clk = 1'b0; #(PERIOD/2) clk= 1'b1; #(PERIOD/2); end initial begin // Initialize Inputs reset = 1; mode = 2'b00; turn = 0;
pause = 0; // Wait 100 ns for global reset to finish #500; reset = 0; mode = 2'b00; turn = 0; #600000; mode = 2'b01; turn = 0; #60000; mode = 2'b01; turn = 1; #60000; mode = 2'b10; turn = 0;
#60000; mode = 2'b10; turn = 1; #60000; mode = 2'b11; #60000; pause = 1; #60000; reset = 1; // Add stimulus here end endmodule 五、仿真
进入ISim仿真波形界面
(1)仿真,运行1ms,将波形结果调整为适合的大小。
(2)这时我们可以分别点开clock模块和display模块查看具体的信号变化是否正确。我们先看clock模块。
(3)当mode = 00时,实现正常时钟显示功能。在脉冲second_en到来时,count做计数加1,此时小时位是shour1,shour0,分钟位是smin1,smin0,将这几个相关信号在波形窗口中位置做个调整放到一起来查看。当count计数到59时,分钟位smin0实现加1变化,由0变为1;此时结果是正确的。
(4)当mode =2’b01时,实现闹铃模块。当turn=1时,调整分位amin1、amin0;当turn=0时,调整小时位ahour1、ahour0。将相关信号放在一起查看,由图可知,当turn为低时,调整小时位,ahour0计数加1,计数到9后清零且ahour1加1;当turn为高时,调整分钟位,amin0计数加1,计数到9后清零且ahouu1加1。结果显然是正确的。
(5)当mode = 2’b10时,实现校时功能。当turn=1时,调整分位smin1、smin0;当turn=0时,调整小时位shour1、shour0。将相关信号放在一起查看,由图可知,当turn为低时,调整小时位,shour0计数加1,计数到9后清零且shour1加1;当turn为高时,调整分钟位,smin0计数加1,计数到9后清零且shouu1加1。结果显然是正确的。
(6)当mode = 2’b11时,实现秒表计时功能。当pause=0时,开始计时;当pause=1时,暂停。由图可知,当pause=0时,mmin0计数加1,计数到9后清零且mmin1加1;当pause=1时,此时暂停秒表,mmin0的值保持为2。结果也是正确的。
(7)查看display模块。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- gamedaodao.net 版权所有 湘ICP备2024080961号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务