FPGA基于Verilog实现的多功能时钟
时钟实现的功能:
1.数码管显示时间
2.有计时功能
3.可实现定点报时
多功能时钟共两种工作状态:
1.正常的时钟显示时间
2.计时状态
由于部分原因,本例中调节时间的功能并没有添加,程序大体功能完整,可能出现少许BUG,可以做个参考,望知。
实现资源:
- FPGA开发板一块,包括: 六位八段数码管(用于显示时间)、蜂鸣器(用于定点报时)、 四位按键输入
- 开发板采用50Mhz晶振产生时钟
变量定义
一共有5个输入,包括四个按键及一个时钟输入
3个输出,包括位、段数码管及蜂鸣器
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29module multfun_clock(clk,key1,key2,key3,key0,beep,dxuan, wxuan,count,divclk,wei_cnt,disp_state ); input clk; input key1; input key2; input key3; input key0; output reg [7:0] dxuan; output reg [5:0] wxuan; output reg beep; reg [25:0] count; reg divclk; //分频产生1次/秒的脉冲用于时钟计数 reg [4:0] cnth,cnthh; reg [5:0] cntd,cntdd; reg [5:0] cnts,cntss; reg [1:0] kstate; //******************数码管数值定义*********************************// parameter disp0=8'b1100_0000; parameter disp1=8'b1111_1001; parameter disp2=8'b1010_0100; parameter disp3=8'b1011_0000; parameter disp4=8'b1001_1001; parameter disp5=8'b1001_0010; parameter disp6=8'b1000_0010; parameter disp7=8'b1111_1000; parameter disp8=8'b1000_0000; parameter disp9=8'b1001_0000;
按键的消抖
利用脉冲的递送产生的上升沿来控制时钟状态转换
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25reg low_g; reg low_g_r; reg d1; reg [19:0] cnt; always @ (posedge clk ) if (cnt == 20'hfffff) low_g <= key3; else cnt <= cnt + 1'b1; always @ (posedge clk ) low_g_r <= low_g; wire led_ctr = low_g_r & (~low_g); always@(posedge clk) begin if(led_ctr==0) //按键3用来切换时钟、计数器与调节时钟状态 begin if(kstate>2'b10) kstate<=2'b00; else kstate<=kstate+2'b01; end else kstate<=kstate; end
分频
该always语句用于产生时钟所用脉冲,将50Mhz脉冲分频,计数2500_0000次即为1秒钟时间。50Mhz脉冲每个脉冲为20ns,1秒钟需要5000_0000个脉冲,那么产生的分频信号应该计数至2500_0000就翻转一次
复制代码
1
2
3
4
5
6
7
8
9
10always@(posedge clk) //时钟分频 begin if(count<=26'd2500_0000) count<=count+26'd1; else begin divclk=~divclk; count<=26'd0; end end
时钟模块
无论当前多功能时钟计数状态为什么,时钟模块永远处于工作状态,按秒、分、时依次进位
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20always@(posedge divclk) begin if(cnts<=6'd58) cnts=cnts+6'd1; else begin //计时60秒,秒计数清零,分计数加1 cnts<=6'd0; if(cntd<=6'd58) cntd<=cntd+6'd1; else begin //计数60分,分计数清零,时计数加1 cntd<=6'd0; if(cnth<=5'd22) cnth<=cnth+5'd1; else cnth<=5'd0; //计数24时,时计数清零 end end end
计时模块
本例中计时最大限度设为2小时,可清零
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27always@(posedge divclk) if(kstate==2'b01) begin//切换到计时 if(key0==1'b0) //开关0清零 begin cntss<=0; cntdd<=0; cnthh<=0; end else if(key1==1'b0) begin //复位端无效 if(cntss<=6'd59) cntss=cntss+6'd1; else begin //计时60秒,秒计数清零,分计数加1 cntss<=6'd0; if(cntdd<=6'd59) cntdd<=cntdd+6'd1; else begin //计数60分,分计数清零,时计数加1 cntdd<=0; if(cnthh<=5'd31) cnthh<=cnthh+5'd1; else cnthh<=5'd0; end //计数2小时,时计数清零 end end else begin cntss<=cntss; cntdd<=cntdd; cnthh<=cnthh; end end
时间显示模块
cnt_symin用于选择八段数码管的输入显示
复制代码
1
2case(cnt_symin)
显示分为时钟显示和计时显示,根据状态不同进行切换
复制代码
1
2
3if(kstate==2'b01) begin …… else begin ……
下面为该模块所有代码:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60reg [15:0] wei_cnt; reg [ 2:0] disp_state; reg [ 7:0] cnt_symin; reg [ 7:0] cnt_symout; always@(posedge clk) //位数码管切换 begin if(wei_cnt<=16'd5_0000) begin disp_state<=disp_state; wei_cnt<=wei_cnt+12'd1; end else begin wei_cnt<=16'd0; if(disp_state==3'd5) disp_state<=3'd0; else disp_state<=disp_state+3'd1; end end always@(posedge clk) //段数码管切换 begin case(cnt_symin) 1:dxuan<=disp1; 2:dxuan<=disp2; 3:dxuan<=disp3; 4:dxuan<=disp4; 5:dxuan<=disp5; 6:dxuan<=disp6; 7:dxuan<=disp7; 8:dxuan<=disp8; 9:dxuan<=disp9; 0:dxuan<=disp0; default:dxuan<=disp0; endcase end always@(posedge clk) begin if(kstate==2'b01) begin case(disp_state) 0:begin wxuan<=6'b011_111;cnt_symin<=cnthh/10; end 1:begin wxuan<=6'b101_111;cnt_symin<=cnthh%10; end 2:begin wxuan<=6'b110_111;cnt_symin<=cntdd/10; end 3:begin wxuan<=6'b111_011;cnt_symin<=cntdd%10; end 4:begin wxuan<=6'b111_101;cnt_symin<=cntss/10; end 5:begin wxuan<=6'b111_110;cnt_symin<=cntss%10; end default:wxuan<=6'b111_111; endcase end else begin case(disp_state) 0:begin wxuan<=6'b011_111;cnt_symin<=cnth/10; end 1:begin wxuan<=6'b101_111;cnt_symin<=cnth%10; end 2:begin wxuan<=6'b110_111;cnt_symin<=cntd/10; end 3:begin wxuan<=6'b111_011;cnt_symin<=cntd%10; end 4:begin wxuan<=6'b111_101;cnt_symin<=cnts/10; end 5:begin wxuan<=6'b111_110;cnt_symin<=cnts%10; end default:wxuan<=6'b111_111; endcase end end
定点提醒
这个模块因为某些原因并没有实现功能,可做参考
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15reg [15:0] beep_cnt; always@(posedge clk) begin if(cnts==6'd58) begin //59秒时开始提醒 if(beep_cnt==16'd1000) begin //如果计时等于0.01秒,则停止蜂鸣 beep<=0; beep_cnt<=0; end else begin beep<=~beep; //否则一直蜂鸣直到计时结束 beep_cnt<=beep_cnt+16'd1; end end else beep=0; end
【注】:个人学习记录,如有错误,望不吝赐教
邮箱:2267395007@qq.com
最后
以上就是时尚小懒虫最近收集整理的关于FPGA学习——基于Verilog实现的多功能时钟的全部内容,更多相关FPGA学习——基于Verilog实现内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复