NJUST
多功能数字钟设计
基于VerilogHDL语言
学院: 电子工程与光电技术学院
学号: ************ 姓名: 指导教师:
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 hours, school minutes,the whole point timekeeping. And extended function of alarm clock, stopwatch, calendar, keyboard input. 关键词:多功能数字钟,可编程逻辑器件,EDA设计,Verilog
Keywords:multi-functional digital clock, FPGA, EDA disign, Verilog
目录
1 设计要求 ....................................................................................................... 2 2 设计方案选择及思路分析 ................................................................................ 2 3 各子模块设计原理和分析 ................................................................................. 3
3.1 分频模块 ............................................................................................... 3 3.2 时分秒模块 ............................................................................................ 5 3.3 时分调整模块 ........................................................................................ 6 3.4 报时模块 ............................................................................................... 7 3.5 扫描显示模块 ........................................................................................ 8 3.6 秒表模块 ............................................................................................... 9 3.7 闹钟模块 ............................................................................................. 10 3.8 万年历模块 .......................................................................................... 12 3.9 键盘扫描模块 ...................................................................................... 13 4 调试仿真 ...................................................................................................... 15 5 编程下载 ...................................................................................................... 16 6 结论 ............................................................................................................. 17 7 参考文献 ...................................................................................................... 17 8 实验感想 ...................................................................................................... 17 9 源代码 ......................................................................................................... 18
1
1 设计要求
基于FPGA可编程逻辑器件,用quatusII软件设计一个多功能数字钟,其基本要求如下:
1.有基础的计时显示功能,即时、分、秒显示在6个七段管上
2.K0,K1,K2,K3分别为系统使能(暂停),时钟清零,校时,校分开关。由于按键是长期处于“1”状态,故在这里采用低电平“0”为有效电平(本人认为原要求中“1”为有效电平不合理)。
3. 使时钟具有整点报时功能(当时钟计到59’53”时开始报时,在59’53”, 59’55”,59’57”时报时频率为500Hz,59’59”时报时频率为1KHz, )。
提高部分要求:
添加按键:K4,K5分别为设置位选择,设置位加一。K6,K7为组合功能选择,当K6K7值:(11)为时钟功能,(10)为秒表功能,(01)为闹钟设置,(00)为万年历功能。
1.闹时功能,按动方式键,使电路工作于预置状态,此时显示器与时钟脱开,而与预置计数器相连,利用前面手动校时,校分方式进行预置,预置后回到正常模式。当计时计至预置的时间时,扬声器发出闹铃信号,时间为半分钟,闹铃信号可以用开关“止闹”,按下此开关后,闹铃声立刻中止,正常情况下应将此开关释放,否则无闹时作用。
2.秒表功能。按start键开始计秒,按stop键停止计秒并保持显示数不变,直到复位信号加入。
3.万年历功能,
4.使用4*4矩阵键盘输入设置信号
2 设计方案选择及思路分析
由于之前参加过华为杯电子设计大赛,当时采用的是VerilogHDL语言,而
且EDA实验一曾经做过用器件搭数字钟的实验,如果再用原理图方法的话没有挑战性,而且VerilogHDL语言更为灵活方便,因此决定采用其完成本次电子设计。 设计的总体部分按照要求可以分为基本模块:分频模块、时钟计时及调整模
2
块、扫描显示。附加模块:万年历、整点报时、闹钟功能和秒表功能。其总体设计框图如下: 秒表 分频 日月年计数 报时 闹钟 扫描显示 嗡鸣器 秒分时计数
3 各子模块设计原理和分析
3.1 分频模块
初步分析后面所需要的信号频率,分频器的功能主要有4个:分别是产生计时用的标准秒脉冲1HZ信号;闹钟及万年历设置时用的2HZ闪烁信号整点报时及显示扫描用的1kHZ高音频信号和500HZ低音频信号。分析系统时钟为48M,经过48K的分频后得到1K信号,再经过2分频可以得到500HZ方波,1K经过5分频得到200HZ信号,最后100分频得到的2HZ信号,再2分频得到1HZ的时钟。原理框图如下图5所示。
200HZ 48M 1K 500HZ 2HZ 1HZ 图5 分频信号框图
Verilog设计分频器很简单,在偶数分频时,在输入脉冲下直接计数到所分频数的一半,然后翻转即可。如:
3
always@(posedge clk) begin
f1k<=(count48k<48000/2)?1'b1:1'b0; if(count48k==48000-1) count48k<=0; else
count48k<=count48k+1; end
但是奇数分频则要复杂得多,若奇数分频不要求占空比为50%,原理同偶数分频,可计数到(N-1)/2翻转,此时占空比接近50%。但如果要求占空比为准确的50%,通过查阅资料得知也可以实现的。原理如下图
always @(posedge f1k) //上升沿计数 if(count5p==4) count5p<=0; else
count5p<=count5p+1;
//posedge wave //上升沿波形 always @(posedge f1k ) begin
if(count5p<2)
f200p <=1; else
f200p <=0; end
//negedge counter
always @(negedge f1k ) //下降沿计数 if(count5n==4) count5n<=0; else
count5n<=count5n+1; //negedge wave
always @(negedge f1k) //下降沿波形 begin
if(count5n<2)
f200n <=1; else
4
f200n <=0; end
assign f200hz=f200n|f200p; //波形相或
仿真波形如下,clk设置频率为4800M,则f1k的周期为10us,仿真结果正确。
3.2 时分秒模块
均用BCD码来保存便于后期显示,时分秒的情况基本相同,现详细分析秒的
进位情况。用4位寄存器来保存秒个位,4位寄存器来保存秒十位。时分秒一共需要24位寄存器。
在1HZ的脉冲下,秒个位计数,当满10时即4’ha时向秒十位进位,秒个位
清零;秒十位满6即4’h6时向分个位进位,秒十位清零……以此类推,特别在时十位处理时有些不同,当小时整体满24即8’h24时,清零,(向天进位,为以后万年历做铺垫)。代码如下,(此处把年月日的计数一起处理) begin
second[3:0]=second[3:0]+1'b1; if(second[3:0]==4'ha) begin
second[3:0]=4'h0;
second[7:4]=second[7:4]+1'b1; if(second[7:4]==4'h6) begin second[7:4]=4'h0; minute[3:0]=minute[3:0]+1'b1; if(minute[3:0]==4'ha) begin minute[3:0]=4'h0; minute[7:4]=minute[7:4]+1'b1; if(minute[7:4]==4'h6) begin minute[7:4]=4'h0; hour[3:0]=hour[3:0]+1'b1; if(hour[3:0]==4'ha) begin hour[3:0]=4'h0; hour[7:4]=hour[7:4]+1'b1;
5
if(hour==8'h24) begin hour[7:4]=4'h0; day[3:0]=day[3:0]+1'b1; if(day[3:0]==4'ha) begin day[3:0]=4'h0; day[7:4]=day[7:4]+1'b1; if(day[7:4]==4'h3) begin day[7:4]=4'h0; month[3:0]=month[3:0]+1'b1; if(month[3:0]==4'ha) begin month[3:0]=4'h0; month[7:4]=month[7:4]+1'b1; if(month[7:0]==8'h12) begin month=8'h0; year=year+1; end end end end end end end end end end end
仿真波形:
仿真结果正确
3.3 时分调整模块
调整模块的功能包括暂停计时,清零,校时,校分。在Verilog中很容易实现, 暂停:在时分秒计数模块前加一个条件,当key[0]不等于0时计时,那么低电平0有效时就不计时,即暂停。
6
清零:
always@(posedge clk_1hz or negedge key[1])//key[1]控制清零 begin
if(key[1]==0)//clear begin
hour=8'b0; minute=8'b0; second=8'b0; end
校时和校分一致,当key[2]=0时,时个位加一,个位满十时,向十位进一位。校时:
else if(key[7:6]==2'b11 && key[2]==0) begin
hour[3:0]=hour[3:0]+1'b1; if(hour[3:0]==4'ha) begin
hour[3:0]=4'h0;
hour[7:4]=hour[7:4]+1; if(hour[7:4]==4'h6) hour[7:4]=4'h0; end end 校分:
else if(key[7:6]==2'b11 && key[3]==0) begin
minute[3:0]=minute[3:0]+1'b1; if(minute[3:0]==4'ha) begin
minute[3:0]=4'h0;
minute[7:4]=minute[7:4]+1; if(minute[7:4]==4'h6) minute[7:4]=4'h0; end end
3.4 报时模块
以分和秒为敏感表,检测当分为59时,秒为53,55,57时,beep_r寄存器放入500hz;秒为59时,beep_r寄存器放入1khz。 always@(minute or second)
if(minute==8'h59) //59分钟时
case(second) //秒为53、55、57低音报时 8'h53, 8'h55,
8'h57:beep_r<=clk_500hz;
7
8'h59:beep_r<=clk_1k; default:beep_r<=1'b0; endcase else
beep_r<=1'b0; 3.5 扫描显示模块
扫描显示模块是一个重点模块,理解其工作原理很重要。先定义一个32位的寄存器装载要显示的内容,方便在功能扩展时直接把想要显示的内容送到该寄存器就行了。采用扫描显示,只要扫描的周期小于10ms,人眼就感觉不到闪烁。通过1k的频率控制扫描,一共扫描8位,则显示的频率为125hz,扫描周期为8ms。这样还可以节省管脚,方便操作。
原理简述,通过快速循环扫描产生8位的位码和段码,循环因子当然也是8.在循环中把8位中对应的当前位的位码置为0,同时把该为对应的数保存到寄存器。 同时把刚才寄存器中的值翻译为对应的七段管码值送到段码中。 always@(posedge clk_1k) begin
//display_function chose case(key[7:6])
2'b11:display={hour,4'ha,minute,4'ha,second};//正常计时 2'b10:display={hour1,4'ha,minute1,4'ha,second1};//设置闹钟 2'b01:display={min,4'ha,sec,4'ha,ms};//秒表 2'b00:display={year,month,day};//万年历 endcase
case(count1)
3'd0:dis_data=display[3:0]; 3'd1:dis_data=display[7:4]; 3'd2:dis_data=display[11:8]; 3'd3:dis_data=display[15:12]; 3'd4:dis_data=display[19:16]; 3'd5:dis_data=display[23:20]; 3'd6:dis_data=display[27:24]; 3'd7:dis_data=display[31:28]; endcase
case(count1)
3'd0:dig_r=8'b11111110; 3'd1:dig_r=8'b11111101; 3'd2:dig_r=8'b11111011; 3'd3:dig_r=8'b11110111; 3'd4:dig_r=8'b11101111; 3'd5:dig_r=8'b11011111; 3'd6:dig_r=8'b10111111;
8
3'd7:dig_r=8'b01111111; endcase
count1<=count1+1;
case(dis_data) 4'h0:seg_r=8'hc0; 4'h1:seg_r=8'hf9; 4'h2:seg_r=8'ha4; 4'h3:seg_r=8'hb0; 4'h4:seg_r=8'h99; 4'h5:seg_r=8'h92; 4'h6:seg_r=8'h82; 4'h7:seg_r=8'hf8; 4'h8:seg_r=8'h80; 4'h9:seg_r=8'h90; 4'ha:seg_r=8'hbf; default:seg_r=8'hff; endcase end
3.6 秒表模块
秒表模块是一个相对的模块,用单独的分、秒、毫秒寄存器计数。通过key[6:7]=10来选择功能,key[4]清零,key[5]暂停。秒表的计数模块与时分秒的大同小异。
//先把1k的信号分频为0.01s的信号
always@(posedge clk_1k) begin
f100hz<=(count10<10/2)?1'b1:1'b0; if(count10==10-1) count10<=0; else
count10<=count10+1; end
always@(posedge f100hz ) begin
if(key[7:4]==4'b0111)//若没有暂停,(key[4]=1) begin
ms[3:0]=ms[3:0]+1'b1; if(ms[3:0]==4'ha) begin ms[3:0]=4'h0; ms[7:4]=ms[7:4]+1'b1; if(ms[7:4]==4'ha) begin
9
ms[7:4]=4'h0; sec[3:0]=sec[3:0]+1'b1; if(sec[3:0]==4'ha) begin sec[3:0]=4'h0; sec[7:4]=sec[7:4]+1'b1; if(sec[7:4]==4'h6) begin sec[7:4]=4'h0; min[3:0]=min[3:0]+1'b1; if(min[3:0]==4'ha) begin min[3:0]=4'h0; min[7:4]=min[7:4]+1'b1; end if(min==8'h60) min=8'h0; end end end end end else
if(key[4]==0)//清零 begin ms=0; sec=0; min=0; end end
3.7 闹钟模块
闹钟模块主要包括存储时分的寄存器,设置闹钟,闹钟音乐,对比是否到达设定时刻几个子模块。其中音乐模块最为复杂,也是本设计的亮点,单独在一个文件中编写。 //设置闹钟
always@(negedge key)
if(key[7:6]==2'b01) //选择闹钟设置 begin
if(!key[2])
hour1=hour+1; else if(!key[3])
minute1=minute1+1; end
10
//对比是否到达设定时刻 always@(minute or second)
if(minute==minute1&&hour==hour1) beep2=beep1; else
beep2=1'b0; //调用音乐模块 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 低4FA 349 1433 #4FA# 370 1350 低5SO 392 1276 #5SO# 415 1205 低6LA 440 1136 #6LA# 466 1072 低7SI 494 1012 #7SI# 524 09
中1DO 523 0956 #1DO# 5 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# 1046 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
11
(——来自百度知道)
卡农简谱:
然后通过计算定义好每个音阶对应的频率。250ms为一个节拍,把每一个节拍的频率送到beep即可播放音乐。代码太长,放到最后。
3.8 万年历模块
万年历的存储计数模块在前面已经和时分秒一起完成,这里只需要调整设置
模块。
这里采用另外一种设置的方式,移位设置。万年历一共有三组数,共8位,若分别用一个键去设置,太浪费资源,而且如果是年的话要从0到2014一个一个累加设置也不现实。故采用移位设置,每一位分别设置,并控制每一位的最大值。这样只需要两个键即可完成功能,一个移位,一个控制累加。
其中,为了突出当前正在设置的位,将该位闪烁。闪烁的方法是用一个低频
信号(2hz)与原来的高频扫描的位码相或。这样低频信号为“1”时会掩盖该位的位码,使其不显示,只要在低频信号为“0”时才正常显示。 //设置万年历
reg [2:0]setpoint;
always@(negedge key[4])
if(key[7:6]==2'b00 && key[4]==0) setpoint=setpoint+1;
always@(negedge key[5])
if(key[7:6]==2'b00 && key[5]==0) case(setpoint)
3'd0:begin day[3:0]=day[3:0]+1;
12
if(day[3:0]==4'ha)day[3:0]=4'h0; dig_blink[0]=clk_2hz; end
3'd1:begin day[7:4]=day[7:4]+1; if(day[7:4]==4'h3)day[7:4]=4'h0; dig_blink[1]=clk_2hz; end
3'd2:begin month[3:0]=month[3:0]+1; if(month[3:0]==4'ha)month[3:0]=4'h0; dig_blink[2]=clk_2hz; end
3'd3:begin month[7:4]=month[7:4]+1; if(month[7:4]==4'h2)month[7:4]=4'h0; dig_blink[3]=clk_2hz; end
3'd4:begin year[3:0]=year[3:0]+1; if(year[3:0]==4'ha)year[3:0]=4'h0; dig_blink[4]=clk_2hz; end
3'd5:begin year[7:4]=year[7:4]+1;
if(year[7:4]==4'ha)year[7:4]=4'h0; dig_blink[5]=clk_2hz;end 3'd6:begin year[11:8]=year[11:8]+1;
if(year[11:8]==4'ha)year[11:8]=4'h0; dig_blink[6]=clk_2hz;end 3'd7:begin year[15:9]=year[15:9]+1;
if(year[15:9]==4'ha)year[15:9]=4'h0; dig_blink[7]=clk_2hz;end endcase
3.9 键盘扫描模块
通过前面的操作发现单独的操作按键进行数码的设置不太方便,若能够将4*4矩阵键盘利用起来,必将方便的多。 键盘扫描的原理如下:
keyout1——4:key5——key8的管脚 keyin1——4:key1——key4的管脚 (通过跳线进行复用)
13
矩阵键盘的键值读取是通过逐行扫描判断实现的,如上图所示,矩阵键盘的扫描流程是这样的,刚开始在KEYOUT[4:1]输出1110(KEYOUT1输出低电平),延时一段时间后读
取KEYIN的状态,由于KEYIN接有上拉电阻,平时无按键时值为1111,若读取的值不为1111,则说明S1、S5、S9、S13有按键按下,KEYIN1-KEYIN4的每一位对应一个按键(如KEYIN[4:1]的值为1110,说明S1按下);扫描完一行之后继续扫描第二行,KEYOUT[4:1]输出1101(KEYOUT2输出低电平),通读取KEYIN的值可判断S2、S6、S10、S14按键的值。以此类推……
通过定义6个状态,0状态监测有按键按下,1-4扫描是哪一列按下,若检测到有按下,立即转到5状态,在按下时重复保存下当前的行和列。若均无按下,回到0状态等待按下。 主要代码实现:
always @(posedge clk_500khz or negedge reset) if(!reset) begin col<=4'b0000;state<=3'd0;end else begin
case (state) 3'd0: begin
col[3:0]<=4'b0000; key_flag<=1'b0;
if(row[3:0]!=4'b1111) begin state<=3'd1;col[3:0]<=4'b1110;end //有键按下,扫描第一列
else state<=3'd0; end 3'd1: begin
if(row[3:0]!=4'b1111) begin state<=3'd5;end //判断是否是第一列 else begin state<=3'd2;col[3:0]<=4'b1101;end //扫描第二列 end 3'd2:
begin
if(row[3:0]!=4'b1111) begin state<=3'd5;end //判断是否是第二列 else begin state<=3'd3;col[3:0]<=4'b1011;end //扫描第三列 end 3'd3:
begin
if(row[3:0]!=4'b1111) begin state<=3'd5;end //判断是否是第三列 else begin state<=3'd4;col[3:0]<=4'b0111;end //扫描第四列 end 3'd4:
begin
if(row[3:0]!=4'b1111) begin state<=3'd5;end //判断是否是第一行 else state<=3'd0; end 3'd5:
14
begin
if(row[3:0]!=4'b1111) begin col_reg<=col; //保存扫描列值 row_reg<=row; //保存扫描行值 state<=3'd5; key_flag<=1'b1; //有键按下 end else begin state<=0; end end
endcase end
always @(clk_500khz or col_reg or row_reg) begin
if(key_flag==1'b1) begin case ({col_reg,row_reg})
8'b1110_1110:key_value<=8'h7; 8'b1110_1101:key_value<=8'h4; 8'b1110_1011:key_value<=8'h1; 8'b1110_0111:key_value<=8'h0;
8'b1101_1110:key_value<=8'h8; 8'b1101_1101:key_value<=8'h5; 8'b1101_1011:key_value<=8'h2; 8'b1101_0111:key_value<=8'ha;
8'b1011_1110:key_value<=8'h9; 8'b1011_1101:key_value<=8'h6; 8'b1011_1011:key_value<=8'h3; 8'b1011_0111:key_value<=8'hb;
8'b0111_1110:key_value<=8'hf; 8'b0111_1101:key_value<=8'he; 8'b0111_1011:key_value<=8'hd;
8'b0111_0111:key_value<=8'hc; endcase end end
4 调试仿真
15
由于之前比赛就有过太多的失败和教训,不过也积累了不少经验,所以总体在软件使用方面不存在障碍。提几点十分重要的地方,当然老师上课也都说过的。
1.软件必须完全破解,否则无法使用高级功能,也不能使用cycloneIII系列FPGA芯片。 2.所有的文件必须在英文路径下面,否则会有意想不到的各种问题。
3.以前我不知道仿真的信号可以自由分组,以方便观察组合值,以前都是默认的总线才有分组的。
总而言之,写好的项目需要编译,然后根据提示的错误进行修改就行。
仿真时需要新建波形文件,选择感兴趣的端口,设置好输入信号,使能,时钟,功能选择等等。仿真,然后查看输出波形。 总的仿真波形如下:
5 编程下载
分配好管脚,注意把没有用到的管脚定义为三态输入。再次编译。 分配好管脚如下:
16
6 结论
成功地运用VerilogHDL设计出多功能数字钟,完成所有基本功能,并且添加了秒表,闹钟,万年历功能。
7 参考文献
《EDA实验与实践》.......................................................................周立功主编 《数字逻辑电路与系统设计》...........................................................蒋立平主编 《Verilog_HDL_华为入门教程》
8 实验感想
遇到了很多的问题,基本上都是Verilog的问题,毕竟没有系统的学习过,下面包括几个典型的:
1. 只能在一个进程中操作寄存器,不然会有冲突。刚开始很不理解,而且觉得了
很多的功能。比如想在多种信号条件去操作同一个寄存器。解决方法是将所有触发
17
信号写入敏感表,在进程中用if语句判断到底是哪一个信号触发的,从而做出相应的操作。
2. 不能多次赋值给网线类型,其实这个问题与前面一个问题有相似之处。解决方法是
先将多个要赋值的信号逻辑运算后再进行赋值,比如或和与运算。(前面一个问题通过if语句进行逻辑运算的)
3. 在赋值时不能偷懒,最好指定好数据的位,如4’h0,不然会出现意想不到的错误。 4. if条件语句(如果包含)必须至少有一个条件指向其中一个敏感事件(边界标识符) 5. 设计流程最好采用并行设计,在多个always@进程中处理时序逻辑或组合逻辑。这
样有利于问题的简化。
通过此次电子设计,再次复习学习了一遍Verilog HDL,对其中数据流的操作又有了更多的理解。当然,还是停留在表面,以后还需要更加深入的学习,这样运用起来才会。 Verilog HDL很强大,既包括低级的逻辑门,又包括高级的数算。其模块化和结构化足以设计大型的数字电路。
个人认为硬件描述语言通过语言主要是直接操作寄存器和网线,从而综合时序逻辑电路和组合逻辑电路,理论上可以设计出任何逻辑功能的电路。
9 源代码
1.
module clock(clk,clk_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;//key[0]:en,key[1]:clear,key[2]:jiaoshi,key[3]:jiaofen,key[4]:,key[5],key[6],key[7]:function choose output [7:0]dig; output [7:0]seg; output beep; wire beep1; reg beep2; reg beep_r;
//output [7:0]hour,minute,second; assign dig=dig_r | dig_blink; assign seg=seg_r;
assign beep=beep_r|beep2;//nao zhong,bao shi reg [7:0]key_r1,key_r2,key_r3; wire [7:0]key;
reg [7:0]seg_r;//segment choose
reg [7:0]dig_r,dig_blink;//digit choose reg [7:0]hour,minute,second;
18
reg [7:0]month,day; reg [15:0]year;
reg [7:0]hour1,minute1,second1;//nao zhong reg [7:0]min,sec,ms;//miao biao
reg [3:0]dis_data;//the data you want display now reg [2:0]count1;
reg [32:0]display;//all the data series to display reg f50hz,f100hz; reg [4:0]count20; reg [3:0]count10;
//////////////////////////////////////////////// //去抖动电路/
assign key=(key_r1 | key_r2 | key_r3); //T=20ms
always@(posedge clk_1k) begin
f50hz<=(count20<20/2)?1'b1:1'b0; if(count20==20-1) count20<=0; else count20<=count20+1; end
always@(posedge f50hz) begin key_r1<=key_in; key_r2<=key_r1; key_r3<=key_r2; end
//second->minute->hour///->day->month->year/////////////////////////// //always@(posedge clk_1hz or negedge key[1] or negedge key[2] or negedge key[3]) always@(posedge clk_1hz or negedge key[1]) begin
if(key[1]==0)//clear begin
hour=8'b0; minute=8'b0; second=8'b0; end
else if(key[7:6]==2'b11 && key[2]==0) begin hour[3:0]=hour[3:0]+1'b1; if(hour[3:0]==4'ha) begin hour[3:0]=4'h0; hour[7:4]=hour[7:4]+1; if(hour[7:4]==4'h6) hour[7:4]=4'h0; end end
else if(key[7:6]==2'b11 && key[3]==0) begin
19
minute[3:0]=minute[3:0]+1'b1; if(minute[3:0]==4'ha) begin minute[3:0]=4'h0; minute[7:4]=minute[7:4]+1; if(minute[7:4]==4'h6) minute[7:4]=4'h0; end end
else if(key[0])//no pause begin second[3:0]=second[3:0]+1'b1; if(second[3:0]==4'ha) begin second[3:0]=4'h0; second[7:4]=second[7:4]+1'b1; if(second[7:4]==4'h6) begin second[7:4]=4'h0; minute[3:0]=minute[3:0]+1'b1; if(minute[3:0]==4'ha) begin minute[3:0]=4'h0; minute[7:4]=minute[7:4]+1'b1; if(minute[7:4]==4'h6) begin minute[7:4]=4'h0; hour[3:0]=hour[3:0]+1'b1; if(hour[3:0]==4'ha) begin hour[3:0]=4'h0; hour[7:4]=hour[7:4]+1'b1; if(hour==8'h24) begin hour[7:4]=4'h0; day[3:0]=day[3:0]+1'b1; if(day[3:0]==4'ha) begin day[3:0]=4'h0; day[7:4]=day[7:4]+1'b1; if(day[7:4]==4'h3) begin day[7:4]=4'h0; month[3:0]=month[3:0]+1'b1; if(month[3:0]==4'ha) begin month[3:0]=4'h0; month[7:4]=month[7:4]+1'b1; if(month[7:0]==8'h12) begin month=8'h0; year=year+1; end end
20
end end end end end end end end end end
/////////////////////////////////////////////////////////////////////// //设置闹钟
always@(negedge key) if(key[7:6]==2'b01) begin
if(!key[2])
hour1=hour+1; else if(!key[3])
minute1=minute1+1; end
/////////////////////////////////////////////////////////////////////// //秒表
always@(posedge clk_1k) begin f100hz<=(count10<10/2)?1'b1:1'b0; if(count10==10-1) count10<=0; else count10<=count10+1; end
always@(posedge f100hz ) begin if(key[7:4]==4'b0111) begin ms[3:0]=ms[3:0]+1'b1; if(ms[3:0]==4'ha) begin ms[3:0]=4'h0; ms[7:4]=ms[7:4]+1'b1; if(ms[7:4]==4'ha) begin ms[7:4]=4'h0; sec[3:0]=sec[3:0]+1'b1; if(sec[3:0]==4'ha) begin sec[3:0]=4'h0; sec[7:4]=sec[7:4]+1'b1; if(sec[7:4]==4'h6) begin sec[7:4]=4'h0; min[3:0]=min[3:0]+1'b1; if(min[3:0]==4'ha) begin
21
min[3:0]=4'h0; min[7:4]=min[7:4]+1'b1; end if(min==8'h60) min=8'h0; end end end end end else if(key[4]==0) begin ms=0; sec=0; min=0; end end
/////////////////////////////////////////////////////////////////////// //设置万年历 reg [2:0]setpoint;
always@(negedge key[4])
if(key[7:6]==2'b00 && key[4]==0) setpoint=setpoint+1;
always@(negedge key[5])
if(key[7:6]==2'b00 && key[5]==0) case(setpoint)
3'd0:begin day[3:0]=day[3:0]+1; if(day[3:0]==4'ha)day[3:0]=4'h0; dig_blink[0]=clk_2hz;end
3'd1:begin day[7:4]=day[7:4]+1; if(day[7:4]==4'h3)day[7:4]=4'h0; dig_blink[1]=clk_2hz;end
3'd2:begin month[3:0]=month[3:0]+1; if(month[3:0]==4'ha)month[3:0]=4'h0; dig_blink[2]=clk_2hz;end
3'd3:begin month[7:4]=month[7:4]+1; if(month[7:4]==4'h2)month[7:4]=4'h0; dig_blink[3]=clk_2hz;end
3'd4:begin year[3:0]=year[3:0]+1; if(year[3:0]==4'ha)year[3:0]=4'h0; dig_blink[4]=clk_2hz;end
3'd5:begin year[7:4]=year[7:4]+1; if(year[7:4]==4'ha)year[7:4]=4'h0; dig_blink[5]=clk_2hz;end
3'd6:begin year[11:8]=year[11:8]+1; if(year[11:8]==4'ha)year[11:8]=4'h0; dig_blink[6]=clk_2hz;end
3'd7:begin year[15:9]=year[15:9]+1; if(year[15:9]==4'ha)year[15:9]=4'h0; dig_blink[7]=clk_2hz;end endcase
///////////////////////////////////////////////////////////////////////////// //scan and display/
always@(posedge clk_1k) begin
//display_function chose case(key[7:6])
2'b11:display={hour,4'ha,minute,4'ha,second};//正常计时 2'b10:display={hour1,4'ha,minute1,4'ha,second1};//设置闹钟
22
2'b01:display={min,4'ha,sec,4'ha,ms};//秒表
2'b00:display={year,month,day};//万年历 endcase case(count1) 3'd0:dis_data=display[3:0]; 3'd1:dis_data=display[7:4]; 3'd2:dis_data=display[11:8]; 3'd3:dis_data=display[15:12]; 3'd4:dis_data=display[19:16]; 3'd5:dis_data=display[23:20]; 3'd6:dis_data=display[27:24]; 3'd7:dis_data=display[31:28]; endcase case(count1) 3'd0:dig_r=8'b11111110; 3'd1:dig_r=8'b11111101; 3'd2:dig_r=8'b11111011; 3'd3:dig_r=8'b11110111; 3'd4:dig_r=8'b11101111; 3'd5:dig_r=8'b11011111; 3'd6:dig_r=8'b10111111; 3'd7:dig_r=8'b01111111; endcase count1<=count1+1;
case(dis_data) 4'h0:seg_r=8'hc0; 4'h1:seg_r=8'hf9; 4'h2:seg_r=8'ha4; 4'h3:seg_r=8'hb0; 4'h4:seg_r=8'h99; 4'h5:seg_r=8'h92; 4'h6:seg_r=8'h82; 4'h7:seg_r=8'hf8; 4'h8:seg_r=8'h80; 4'h9:seg_r=8'h90; 4'ha:seg_r=8'hbf; default:seg_r=8'hff; endcase end
//////////////////////////////////////////////////////////// //报时
always@(minute or second) if(minute==8'h59) //59分钟时 case(second) //秒为53、55、57低音报时 8'h53, 8'h55, 8'h57:beep_r<=clk_500hz; 8'h59:beep_r<=clk_1k; default:beep_r<=1'b0; endcase
else
23
beep_r<=1'b0;
/////////////////////////////////////////////////////////// //闹钟
always@(minute or second)
if(minute==minute1&&hour==hour1) beep2=beep1; else
beep2=1'b0; cannon music( .clk(clk), .beep1(beep1));
Endmodule 2.
module cannon(clk,beep1); input clk;
output wire beep1; reg beep_r; reg[7:0]state;
reg[15:0]count,count_end; reg[23:0]count1; parameter l5=16'd61224, l6=16'd5, l7=16'd48593, m1=16'd45863, m2=16'd408, m3=16'd320, m4=16'd34359, m5=16'd30612, m6=16'd27273, m7=16'd24296, h1=16'd22956, h2=16'd20431, h3=16'd18203, h4=16'd17181, h5=16'd15306, h6=16'd13636, h7=16'd12149; parameter TIME=12000000; assign beep1=beep_r; always@(posedge clk) begin count<=count+1'b1; if(count==count_end) begin count<=16'h0; beep_r<=!beep_r; end end
always@(posedge clk) begin
24
if(count1
Copyright © 2019- huatuo3.com 版权所有 蜀ICP备2023022190号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务