《基于VerilogHDL语言多功能数字钟设计毕业设计论文.doc》由会员分享,可在线阅读,更多相关《基于VerilogHDL语言多功能数字钟设计毕业设计论文.doc(32页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、NJUST多功能数字钟设计基于VerilogHDL语言 学院: 电子工程与光电技术学院学号: 912104220139 姓名: 指导教师: 2014年11月21日星期五摘要:基于FPGA平台,运用Verilog语言编写设计一多功能数字钟,包括基本的时钟,校时校分,整点报时功能。扩展闹钟,秒表,万年历,键盘输入功能。Abstract:FPGA-based platform, using Verilog language to design a multi-functional digital clock, including basic function of clock, school hou
2、rs, school minutes,the whole point timekeeping. And extended function of alarm clock, stopwatch, calendar, keyboard input.关键词:多功能数字钟,可编程逻辑器件,EDA设计,VerilogKeywords:multi-functional digital clock, FPGA, EDA disign, Verilog目录1 设计要求22 设计方案选择及思路分析23 各子模块设计原理和分析33.1 分频模块33.2 时分秒模块53.3 时分调整模块63.4 报时模块73.5
3、扫描显示模块73.6 秒表模块93.7 闹钟模块103.8 万年历模块123.9 键盘扫描模块134 调试仿真155 编程下载166 结论167 参考文献178 实验感想179 源代码171 设计要求基于FPGA可编程逻辑器件,用quatusII软件设计一个多功能数字钟,其基本要求如下: 1.有基础的计时显示功能,即时、分、秒显示在6个七段管上2.K0,K1,K2,K3分别为系统使能(暂停),时钟清零,校时,校分开关。由于按键是长期处于“1”状态,故在这里采用低电平“0”为有效电平(本人认为原要求中“1”为有效电平不合理)。3. 使时钟具有整点报时功能(当时钟计到5953”时开始报时,在595
4、3”, 5955”,5957”时报时频率为500Hz,5959”时报时频率为1KHz, )。提高部分要求:添加按键:K4,K5分别为设置位选择,设置位加一。K6,K7为组合功能选择,当K6K7值:(11)为时钟功能,(10)为秒表功能,(01)为闹钟设置,(00)为万年历功能。 1.闹时功能,按动方式键,使电路工作于预置状态,此时显示器与时钟脱开,而与预置计数器相连,利用前面手动校时,校分方式进行预置,预置后回到正常模式。当计时计至预置的时间时,扬声器发出闹铃信号,时间为半分钟,闹铃信号可以用开关“止闹”,按下此开关后,闹铃声立刻中止,正常情况下应将此开关释放,否则无闹时作用。2.秒表功能。按
5、start键开始计秒,按stop键停止计秒并保持显示数不变,直到复位信号加入。3.万年历功能,4使用4*4矩阵键盘输入设置信号2 设计方案选择及思路分析 由于之前参加过华为杯电子设计大赛,当时采用的是VerilogHDL语言,而且EDA实验一曾经做过用器件搭数字钟的实验,如果再用原理图方法的话没有挑战性,而且VerilogHDL语言更为灵活方便,因此决定采用其完成本次电子设计。设计的总体部分按照要求可以分为基本模块:分频模块、时钟计时及调整模块、扫描显示。附加模块:万年历、整点报时、闹钟功能和秒表功能。其总体设计框图如下:嗡鸣器闹钟报时秒表日月年计数分频秒分时计数扫描显示3 各子模块设计原理和
6、分析3.1 分频模块初步分析后面所需要的信号频率,分频器的功能主要有4个:分别是产生计时用的标准秒脉冲1HZ信号;闹钟及万年历设置时用的2HZ闪烁信号整点报时及显示扫描用的1kHZ高音频信号和500HZ低音频信号。分析系统时钟为48M,经过48K的分频后得到1K信号,再经过2分频可以得到500HZ方波,1K经过5分频得到200HZ信号,最后100分频得到的2HZ信号,再2分频得到1HZ的时钟。原理框图如下图5所示。1HZ2HZ200HZ1K48M500HZ 图5 分频信号框图 Verilog设计分频器很简单,在偶数分频时,在输入脉冲下直接计数到所分频数的一半,然后翻转即可。如:always(p
7、osedge clk)begin f1k=(count48k48000/2)?1b1:1b0; if(count48k=48000-1)count48k=0; elsecount48k=count48k+1;end但是奇数分频则要复杂得多,若奇数分频不要求占空比为50%,原理同偶数分频,可计数到(N-1)/2翻转,此时占空比接近50%。但如果要求占空比为准确的50%,通过查阅资料得知也可以实现的。原理如下图always (posedge f1k) /上升沿计数if(count5p=4) count5p=0;elsecount5p=count5p+1;/posedge wave /上升沿波形al
8、ways (posedge f1k ) begin if(count5p2)f200p =1; elsef200p =0;end /negedge counteralways (negedge f1k ) /下降沿计数if(count5n=4) count5n=0;elsecount5n=count5n+1;/negedge wavealways (negedge f1k) /下降沿波形begin if(count5n2)f200n =1; elsef200n =0;end assign f200hz=f200n|f200p; /波形相或仿真波形如下,clk设置频率为4800M,则f1k的周期
9、为10us,仿真结果正确。3.2 时分秒模块均用BCD码来保存便于后期显示,时分秒的情况基本相同,现详细分析秒的进位情况。用4位寄存器来保存秒个位,4位寄存器来保存秒十位。时分秒一共需要24位寄存器。在1HZ的脉冲下,秒个位计数,当满10时即4ha时向秒十位进位,秒个位清零;秒十位满6即4h6时向分个位进位,秒十位清零以此类推,特别在时十位处理时有些不同,当小时整体满24即8h24时,清零,(向天进位,为以后万年历做铺垫)。代码如下,(此处把年月日的计数一起处理)beginsecond3:0=second3:0+1b1;if(second3:0=4ha)beginsecond3:0=4h0;s
10、econd7:4=second7:4+1b1;if(second7:4=4h6)beginsecond7:4=4h0;minute3:0=minute3:0+1b1;if(minute3:0=4ha)beginminute3:0=4h0;minute7:4=minute7:4+1b1;if(minute7:4=4h6)beginminute7:4=4h0;hour3:0=hour3:0+1b1;if(hour3:0=4ha)beginhour3:0=4h0;hour7:4=hour7:4+1b1;if(hour=8h24)beginhour7:4=4h0;day3:0=day3:0+1b1;i
11、f(day3:0=4ha)beginday3:0=4h0;day7:4=day7:4+1b1;if(day7:4=4h3)beginday7:4=4h0;month3:0=month3:0+1b1;if(month3:0=4ha)beginmonth3:0=4h0;month7:4=month7:4+1b1;if(month7:0=8h12)beginmonth=8h0;year=year+1;endendendendendendendendendendend仿真波形:仿真结果正确3.3 时分调整模块调整模块的功能包括暂停计时,清零,校时,校分。在Verilog中很容易实现,暂停:在时分秒计数
12、模块前加一个条件,当key0不等于0时计时,那么低电平0有效时就不计时,即暂停。清零:always(posedge clk_1hz or negedge key1)/key1控制清零beginif(key1=0)/clearbeginhour=8b0;minute=8b0;second=8b0;end校时和校分一致,当key2=0时,时个位加一,个位满十时,向十位进一位。校时:else if(key7:6=2b11 & key2=0)beginhour3:0=hour3:0+1b1;if(hour3:0=4ha)beginhour3:0=4h0;hour7:4=hour7:4+1;if(hou
13、r7:4=4h6)hour7:4=4h0;endend校分:else if(key7:6=2b11 & key3=0)beginminute3:0=minute3:0+1b1;if(minute3:0=4ha)beginminute3:0=4h0;minute7:4=minute7:4+1;if(minute7:4=4h6)minute7:4=4h0;endend3.4 报时模块以分和秒为敏感表,检测当分为59时,秒为53,55,57时,beep_r寄存器放入500hz;秒为59时,beep_r寄存器放入1khz。always(minute or second)if(minute=8h59)
14、/59分钟时case(second) /秒为53、55、57低音报时 8h53,8h55, 8h57:beep_r=clk_500hz;8h59:beep_r=clk_1k;default:beep_r=1b0;endcaseelsebeep_r=1b0;3.5 扫描显示模块扫描显示模块是一个重点模块,理解其工作原理很重要。先定义一个32位的寄存器装载要显示的内容,方便在功能扩展时直接把想要显示的内容送到该寄存器就行了。采用扫描显示,只要扫描的周期小于10ms,人眼就感觉不到闪烁。通过1k的频率控制扫描,一共扫描8位,则显示的频率为125hz,扫描周期为8ms。这样还可以节省管脚,方便操作。原
15、理简述,通过快速循环扫描产生8位的位码和段码,循环因子当然也是8.在循环中把8位中对应的当前位的位码置为0,同时把该为对应的数保存到寄存器。同时把刚才寄存器中的值翻译为对应的七段管码值送到段码中。always(posedge clk_1k)begin/display_function chosecase(key7:6)2b11:display=hour,4ha,minute,4ha,second;/正常计时2b10:display=hour1,4ha,minute1,4ha,second1;/设置闹钟2b01:display=min,4ha,sec,4ha,ms;/秒表2b00:display
16、=year,month,day;/万年历endcasecase(count1)3d0:dis_data=display3:0;3d1:dis_data=display7:4;3d2:dis_data=display11:8;3d3:dis_data=display15:12;3d4:dis_data=display19:16;3d5:dis_data=display23:20;3d6:dis_data=display27:24;3d7:dis_data=display31:28;endcasecase(count1)3d0:dig_r=8b11111110;3d1:dig_r=8b111111
17、01;3d2:dig_r=8b11111011;3d3:dig_r=8b11110111;3d4:dig_r=8b11101111;3d5:dig_r=8b11011111;3d6:dig_r=8b10111111;3d7:dig_r=8b01111111;endcasecount1=count1+1; case(dis_data)4h0:seg_r=8hc0;4h1:seg_r=8hf9;4h2:seg_r=8ha4;4h3:seg_r=8hb0;4h4:seg_r=8h99;4h5:seg_r=8h92;4h6:seg_r=8h82;4h7:seg_r=8hf8;4h8:seg_r=8h8
18、0;4h9:seg_r=8h90;4ha:seg_r=8hbf;default:seg_r=8hff; endcaseend3.6 秒表模块秒表模块是一个相对独立的模块,用单独的分、秒、毫秒寄存器计数。通过key6:7=10来选择功能,key4清零,key5暂停。秒表的计数模块与时分秒的大同小异。/先把1k的信号分频为0.01s的信号always(posedge clk_1k)beginf100hz=(count1010/2)?1b1:1b0;if(count10=10-1)count10=0;elsecount10=count10+1;endalways(posedge f100hz )be
19、ginif(key7:4=4b0111)/若没有暂停,(key4=1)beginms3:0=ms3:0+1b1;if(ms3:0=4ha)beginms3:0=4h0;ms7:4=ms7:4+1b1;if(ms7:4=4ha)beginms7:4=4h0;sec3:0=sec3:0+1b1;if(sec3:0=4ha)beginsec3:0=4h0;sec7:4=sec7:4+1b1;if(sec7:4=4h6)beginsec7:4=4h0;min3:0=min3:0+1b1;if(min3:0=4ha)beginmin3:0=4h0;min7:4=min7:4+1b1;endif(min=
20、8h60)min=8h0;endendendendendelse if(key4=0)/清零beginms=0;sec=0;min=0;endend3.7 闹钟模块闹钟模块主要包括存储时分的寄存器,设置闹钟,闹钟音乐,对比是否到达设定时刻几个子模块。其中音乐模块最为复杂,也是本设计的亮点,单独在一个文件中编写。/设置闹钟always(negedge key)if(key7:6=2b01) /选择闹钟设置beginif(!key2)hour1=hour+1;else if(!key3)minute1=minute1+1;end/对比是否到达设定时刻always(minute or second)
21、if(minute=minute1&hour=hour1)beep2=beep1;elsebeep2=1b0;/调用音乐模块cannon music(.clk(clk),.beep1(beep1);/音乐模块,采用曲子cannon片段产生音乐原理:对嗡鸣器而言,每个音调都有其对应的频率。在当前节拍时,给出相应的频率的脉冲即可发出对应的音调。通过查找相关资料得出音调与频率的对应关系如下:音符 频率/HZ 半周期/us(N) -低1DO 262 1908 #1DO# 277 1805低2RE 294 1700 #2RE# 311 1608低3MI 330 1516 #3MI# 340 1470低4
22、FA 349 1433 #4FA# 370 1350低5SO 392 1276 #5SO# 415 1205低6LA 440 1136 #6LA# 466 1072低7SI 494 1012 #7SI# 524 0954中1DO 523 0956 #1DO# 554 0903中2RE 578 0842 #2RE# 622 0804中3MI 659 0759 #3MI# 682 0733中4FA 698 0716 #4FA# 740 0676中5SO 784 0638 #5SO# 831 0602中6LA 880 0568 #6LA# 932 0536中7SI 988 0506 #7SI# 10
23、46 478高1DO 1046 478 #1DO# 1109 451高2RE 1175 426 #2RE# 1245 402高3MI 1318 372 #3MI# 1356 368高4FA 1397 358 #4FA# 1480 338高5SO 1568 319 #5S0# 1661 292高6LA 1760 284 #6LA# 1865 268高7SI 1976 253 #7SI# 2066 242(来自百度知道)卡农简谱:然后通过计算定义好每个音阶对应的频率。250ms为一个节拍,把每一个节拍的频率送到beep即可播放音乐。代码太长,放到最后。3.8 万年历模块万年历的存储计数模块在前面已
24、经和时分秒一起完成,这里只需要调整设置模块。这里采用另外一种设置的方式,移位设置。万年历一共有三组数,共8位,若分别用一个键去设置,太浪费资源,而且如果是年的话要从0到2014一个一个累加设置也不现实。故采用移位设置,每一位分别设置,并控制每一位的最大值。这样只需要两个键即可完成功能,一个移位,一个控制累加。其中,为了突出当前正在设置的位,将该位闪烁。闪烁的方法是用一个低频信号(2hz)与原来的高频扫描的位码相或。这样低频信号为“1”时会掩盖该位的位码,使其不显示,只要在低频信号为“0”时才正常显示。/设置万年历reg 2:0setpoint;always(negedge key4)if(ke
25、y7:6=2b00 & key4=0)setpoint=setpoint+1;always(negedge key5)if(key7:6=2b00 & key5=0)case(setpoint)3d0:begin day3:0=day3:0+1; if(day3:0=4ha)day3:0=4h0; dig_blink0=clk_2hz;end3d1:begin day7:4=day7:4+1; if(day7:4=4h3)day7:4=4h0; dig_blink1=clk_2hz;end3d2:begin month3:0=month3:0+1; if(month3:0=4ha)month3
26、:0=4h0; dig_blink2=clk_2hz;end3d3:begin month7:4=month7:4+1; if(month7:4=4h2)month7:4=4h0; dig_blink3=clk_2hz;end3d4:begin year3:0=year3:0+1; if(year3:0=4ha)year3:0=4h0; dig_blink4=clk_2hz;end3d5:begin year7:4=year7:4+1; if(year7:4=4ha)year7:4=4h0; dig_blink5=clk_2hz;end3d6:begin year11:8=year11:8+1
27、; if(year11:8=4ha)year11:8=4h0; dig_blink6=clk_2hz;end3d7:begin year15:9=year15:9+1; if(year15:9=4ha)year15:9=4h0; dig_blink7=clk_2hz;endendcase3.9 键盘扫描模块通过前面的操作发现单独的操作按键进行数码的设置不太方便,若能够将4*4矩阵键盘利用起来,必将方便的多。键盘扫描的原理如下:keyout14:key5key8的管脚keyin14:key1key4的管脚(通过跳线进行复用)矩阵键盘的键值读取是通过逐行扫描判断实现的,如上图所示,矩阵键盘的扫描流
28、程是这样的,刚开始在KEYOUT4:1输出1110(KEYOUT1输出低电平),延时一段时间后读取KEYIN的状态,由于KEYIN接有上拉电阻,平时无按键时值为1111,若读取的值不为1111,则说明S1、S5、S9、S13有按键按下,KEYIN1-KEYIN4的每一位对应一个按键(如KEYIN4:1的值为1110,说明S1按下);扫描完一行之后继续扫描第二行,KEYOUT4:1输出1101(KEYOUT2输出低电平),通读取KEYIN的值可判断S2、S6、S10、S14按键的值。以此类推通过定义6个状态,0状态监测有按键按下,1-4扫描是哪一列按下,若检测到有按下,立即转到5状态,在按下时重
29、复保存下当前的行和列。若均无按下,回到0状态等待按下。主要代码实现:always (posedge clk_500khz or negedge reset)if(!reset) begin col=4b0000;state=3d0;endelse begin case (state)3d0: begincol3:0=4b0000;key_flag=1b0;if(row3:0!=4b1111) begin state=3d1;col3:0=4b1110;end /有键按下,扫描第一列else state=3d0;end 3d1: beginif(row3:0!=4b1111) begin sta
30、te=3d5;end /判断是否是第一列else begin state=3d2;col3:0=4b1101;end /扫描第二列end 3d2:begin if(row3:0!=4b1111) begin state=3d5;end /判断是否是第二列else begin state=3d3;col3:0=4b1011;end /扫描第三列end3d3:begin if(row3:0!=4b1111) begin state=3d5;end /判断是否是第三列else begin state=3d4;col3:0=4b0111;end /扫描第四列end3d4:begin if(row3:0
31、!=4b1111) begin state=3d5;end /判断是否是第一行else state=3d0;end3d5:begin if(row3:0!=4b1111) begincol_reg=col; /保存扫描列值row_reg=row; /保存扫描行值state=3d5;key_flag=1b1; /有键按下endelsebegin state=0;endendendcase end always (clk_500khz or col_reg or row_reg) begin if(key_flag=1b1) begin case (col_reg,row_reg) 8b1110_
32、1110:key_value=8h7; 8b1110_1101:key_value=8h4; 8b1110_1011:key_value=8h1; 8b1110_0111:key_value=8h0; 8b1101_1110:key_value=8h8; 8b1101_1101:key_value=8h5; 8b1101_1011:key_value=8h2; 8b1101_0111:key_value=8ha; 8b1011_1110:key_value=8h9; 8b1011_1101:key_value=8h6; 8b1011_1011:key_value=8h3; 8b1011_011
33、1:key_value=8hb; 8b0111_1110:key_value=8hf; 8b0111_1101:key_value=8he; 8b0111_1011:key_value=8hd; 8b0111_0111:key_value=8hc; endcase end end 4 调试仿真由于之前比赛就有过太多的失败和教训,不过也积累了不少经验,所以总体在软件使用方面不存在障碍。提几点十分重要的地方,当然老师上课也都说过的。1.软件必须完全破解,否则无法使用高级功能,也不能使用cycloneIII系列FPGA芯片。2.所有的文件必须在英文路径下面,否则会有意想不到的各种问题。3.以前我不知
34、道仿真的信号可以自由分组,以方便观察组合值,以前都是默认的总线才有分组的。总而言之,写好的项目需要编译,然后根据提示的错误进行修改就行。仿真时需要新建波形文件,选择感兴趣的端口,设置好输入信号,使能,时钟,功能选择等等。仿真,然后查看输出波形。总的仿真波形如下:5 编程下载分配好管脚,注意把没有用到的管脚定义为三态输入。再次编译。分配好管脚如下:6 结论成功地运用VerilogHDL设计出多功能数字钟,完成所有基本功能,并且添加了秒表,闹钟,万年历功能。7 参考文献EDA实验与实践.周立功主编数字逻辑电路与系统设计.蒋立平主编Verilog_HDL_华为入门教程8 实验感想遇到了很多的问题,基
35、本上都是Verilog的问题,毕竟没有系统的学习过,下面包括几个典型的:1. 只能在一个进程中操作寄存器,不然会有冲突。刚开始很不理解,而且觉得限制了很多的功能。比如想在多种信号条件去操作同一个寄存器。解决方法是将所有触发信号写入敏感表,在进程中用if语句判断到底是哪一个信号触发的,从而做出相应的操作。2. 不能多次赋值给网线类型,其实这个问题与前面一个问题有相似之处。解决方法是先将多个要赋值的信号逻辑运算后再进行赋值,比如或和与运算。(前面一个问题通过if语句进行逻辑运算的)3. 在赋值时不能偷懒,最好指定好数据的位,如4h0,不然会出现意想不到的错误。4. if条件语句(如果包含)必须至少
36、有一个条件指向其中一个敏感事件(边界标识符)5. 设计流程最好采用并行设计,在多个always进程中处理时序逻辑或组合逻辑。这样有利于问题的简化。通过此次电子设计,再次复习学习了一遍Verilog HDL,对其中数据流的操作又有了更多的理解。当然,还是停留在表面,以后还需要更加深入的学习,这样运用起来才会。Verilog HDL很强大,既包括低级的逻辑门,又包括高级的数学运算。其模块化和结构化足以设计大型的数字电路。个人认为硬件描述语言通过语言主要是直接操作寄存器和网线,从而综合时序逻辑电路和组合逻辑电路,理论上可以设计出任何逻辑功能的电路。9 源代码1.module clock(clk,cl
37、k_1hz,clk_2hz,clk_500hz,clk_1k,key_in,dig,seg,beep);input clk,clk_1hz,clk_2hz,clk_500hz,clk_1k;input 7:0 key_in;/key0:en,key1:clear,key2:jiaoshi,key3:jiaofen,key4:,key5,key6,key7:function chooseoutput 7:0dig;output 7:0seg;output beep;wire beep1;reg beep2;reg beep_r;/output 7:0hour,minute,second;assi
38、gn dig=dig_r | dig_blink;assign seg=seg_r;assign beep=beep_r|beep2;/nao zhong,bao shireg 7:0key_r1,key_r2,key_r3;wire 7:0key;reg 7:0seg_r;/segment choosereg 7:0dig_r,dig_blink;/digit choosereg 7:0hour,minute,second;reg 7:0month,day;reg 15:0year;reg 7:0hour1,minute1,second1;/nao zhongreg 7:0min,sec,ms;/miao biaoreg 3:0dis_data;/the data you want display nowreg 2:0count1;reg 32:0display;/all the data series to displayreg f50hz,f