基于FPGA的数字时钟的设计课设(HUAT)

news/2024/11/23 0:29:37/

    • 目录

      前言

      一、数字时钟课设目标

      二、部分代码

      1.clock.v代码的编写

      2.完整代码

      3.仿真代码

      总结



前言

学校黄老师的FPGA的设计课设,最后的课设为数字时钟,实现分时的计数功能,带有整点报时,按键调节的功能,供电子类学生学习和参考。


一、数字时钟课设目标

l 基本要求

1、能进行正常的时、分、秒计时功能,分别由6个数码管显示24小时、60分钟、60秒钟的计数器显示。

2、能利用实验系统上的按键实现“校时”“校分”功能:

⑴按下“SA”键时,计时器迅速递增,并按24小时循环,计满23小时后回“00”

⑵按下“SB”键时,计分器迅速递增,并按59分钟循环,计满59分钟后回“00”,但不向“时”进位;

⑷要求按下“SA”、“SB”或“SC”时均不产生数字跳变(SA”、“SB”、“SC”按键是有抖动的,必须对其消除抖动处理)。

3、能利用扬声器做整点报时:

⑴当计时到达5950秒时开始报时,在5950秒、52秒、54秒、56秒、58秒鸣叫,鸣叫声频率可定为512Hz

⑵到达5960秒时为最后一声整点报时,整点报时频率可定为1024Hz

4、用层次化设计方法设计该电路,用Verilog语言编写各个功能模块。

5、完成电路设计后,用实验系统下载验证。

l 发挥部分

   要求实现闹铃功能,准确到分钟。用功能仿真的方法验证,可通过观察有关波形确认电路设计是否正确。

二、部分代码

1.clock.v代码的编写

     秒计数器
 

reg  [25:0]  cnt2;
wire     add_cnt2;
wire     end_cnt2;
always@(posedge clk or negedge rst_n)begin //1s计数,可以通过按键更改if(rst_n == 0)
cnt2 <= 0;
else if (add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 +1;end
endassign add_cnt2 = 1;
assign end_cnt2 = add_cnt2 && cnt2 == y-1;//y可以通过按键更改,实现按键调节时钟频率

us计数器
 

reg [8:0]  cnt0;always@(posedge clk or negedge rst_n) //数码管显示if(rst_n == 0)cnt0 <= 0;else if (add_cnt0)beginif(end_cnt0 )cnt0 <= 0;elsecnt0 <= cnt0 +1;endassign add_cnt0 = 1;
assign end_cnt0 = add_cnt0 && cnt0== TIME_1US-1;//通过短时间的数码管显示,实现动态扫描

数码管显示   对4个数码管进行us级的循环点亮,达到视觉上的暂留
 

reg  [2:0]  cnt1;
wire     add_cnt1;
wire     end_cnt1;always@(posedge clk or negedge rst_n)begin //4个数码管if(rst_n == 0)
cnt1 <= 0;
else if (add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 +1;endendassign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1 == 4-1;

数码管动态扫描

always@(posedge clk or negedge rst_n) //动态扫描
beginif(rst_n == 1'b0)seg_sel <= 4'b111_1;else if (cnt1 == 0)seg_sel <= 4'b111_0;else if (cnt1 == 1)seg_sel <= 4'b110_1;else if (cnt1 == 2)seg_sel <= 4'b101_1;else if (cnt1 == 3)seg_sel <= 4'b011_1;elseseg_sel <= 4'b111_1;end 

数码管选择显示
 

reg [3:0] sel_data;always@(posedge clk or negedge rst_n)  // 选择显示
beginif(rst_n == 0)seg_ment <=8'hc0;else if (sel_data==0)seg_ment <= 8'hc0;else if (sel_data==1)seg_ment <= 8'hf9;else if (sel_data==2)seg_ment <= 8'ha4;else if (sel_data==3)seg_ment <= 8'hb0;else if (sel_data==4)seg_ment <= 8'h99;else if (sel_data==5)seg_ment <= 8'h92;else if (sel_data==6)seg_ment <= 8'h82;else if (sel_data==7)seg_ment <= 8'hf8;else if (sel_data==8)seg_ment <= 8'h80;else if (sel_data==9)seg_ment <= 8'h90;elseseg_ment <= 8'hc0;
endalways@(*)
beginif (cnt1==0)sel_data <= m_g;else if (cnt1==1)sel_data <= m_s;else if (cnt1==2)sel_data <= s_g;elsesel_data <= s_s;end

分个位 分十位 时个位 时十位
 

reg  [3:0]  m_g;
wire     add_m_g;
wire     end_m_g;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
m_g <= 0;else if (add_m_g)beginif(end_m_g)m_g <= 0;elsem_g <= m_g +1;end
elsem_g <= m_g;endassign add_m_g = end_cnt2;
assign end_m_g = add_m_g && m_g == 10-1;reg  [2:0]  m_s;
wire     add_m_s;
wire     end_m_s;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
m_s <= 0;
else if (add_m_s)beginif(end_m_s)m_s <= 0;elsem_s <= m_s +1;end
endassign add_m_s = end_m_g;
assign end_m_s = add_m_s && m_s == 6-1;reg  [3:0]  s_g;
wire     add_s_g;
wire     end_s_g;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
s_g <= 0;
else if (add_s_g)
beginif(end_s_g)s_g <= 0;else if (key_in1 == 1'b0)//保证按键按下时位不产生变化s_g <= s_g ;elses_g <= s_g +1;endelses_g <= s_g;
endassign add_s_g = end_m_s;
assign end_s_g = add_s_g && s_g == x-1;reg  [1:0]  s_s;
wire     add_s_s;
wire     end_s_s;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
s_s <= 0;
else if (add_s_s)beginif(end_s_s)s_s <= 0;elses_s <= s_s +1;end
endassign add_s_s = end_s_g;
assign end_s_s = add_s_s && s_s == 3-1;   always@(*)
beginif(s_s==2)
x=4;
else
x=10;end

上述基本可以达到数码管显示计数的效果

//按键更改频率
 

parameter  TIME_1S = 5000_000_0;
parameter  TIME_1MS = 5000_000;
parameter  TIME_1NS = 5000_00;always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)y <= TIME_1S;else if ( key_in1 == 1'b0) //按键1改时钟频率,同时s_g数码管不变beginy=TIME_1MS;endelse if (key_in2 == 1'b0)//按键2 改时钟频率,改的更快y=TIME_1NS;elsebeginy <= TIME_1S;end

beep报时
 

//beep 计数
reg   [24:0]   cnt;
reg   [2:0]    cnt_500ms;
reg   [17:0]   freq_cnt;
reg   [17:0]   freq_data;
reg   [17:0]   freq_data2;
wire   [16:0]   duty_data1;
wire   [16:0]   duty_data2;// beep 0.5s的计数
always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)cnt <= 25'd0;else if (cnt == CNT_MAX)cnt <= 25'd0;elsecnt <= cnt + 25'b1;always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)cnt_500ms <= 3'd0;else if ((cnt_500ms == 3'd6)&&(cnt == CNT_MAX))cnt_500ms <= 3'd0;else if  (cnt == CNT_MAX)cnt_500ms <= cnt_500ms + 3'd1;elsecnt_500ms <= cnt_500ms;//频率计数      
always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)freq_cnt <= 18'd0;else if ((freq_cnt == freq_data)||(cnt == CNT_MAX))freq_cnt <= 18'd0;elsefreq_cnt  <= freq_cnt + 18'd1;always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)freq_data <= DO;else    case(cnt_500ms)3'd0:beginfreq_data <= DO;freq_data2<= XI;enddefault :beginfreq_data <= DO;freq_data2<= XI;endendcaseassign    duty_data1 = freq_data >> 1;assign    duty_data2 = freq_data2 >> 1;//报时always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)beep <= 1'b0;else if ((freq_cnt >= duty_data1)&&(((m_s == 5)&&(m_g== 2))||((m_s == 5)&&(m_g ==0))||((m_s == 5)&&(m_g ==4))||((m_s == 5)&&(m_g ==6))||((m_s == 5)&&(m_g ==8))))// 50 52 54 56 58 报时beep <= 1'b1;else if ((freq_cnt >= duty_data2)&&(((m_s == 0)&&(m_g== 0))))// 正点报时beep <= 1'b1;elsebeep <= 1'b0;  

2.完整代码

module clock_k_b
(input   clk,input   rst_n,input wire key_in1,input wire key_in2,output  reg [3:0] seg_sel,output reg [7:0] seg_ment,output reg   beep);parameter  TIME_1US = 500;
parameter  TIME_1S = 5000_000_0;
parameter  TIME_1MS = 5000_000;
parameter  TIME_1NS = 5000_00;
parameter  CNT_MAX =25'd24_999_999;
parameter  DO = 18'd190839;
parameter  XI = 18'd101213;//
reg [25:0] y;
reg [8:0]  cnt0;
reg [3:0]   x;
wire  add_cnt0;
wire  end_cnt0;//beep 计数
reg   [24:0]   cnt;
reg   [2:0]    cnt_500ms;
reg   [17:0]   freq_cnt;
reg   [17:0]   freq_data;
reg   [17:0]   freq_data2;
wire   [16:0]   duty_data1;
wire   [16:0]   duty_data2;// beep 0.5s的计数
always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)cnt <= 25'd0;else if (cnt == CNT_MAX)cnt <= 25'd0;elsecnt <= cnt + 25'b1;always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)cnt_500ms <= 3'd0;else if ((cnt_500ms == 3'd6)&&(cnt == CNT_MAX))cnt_500ms <= 3'd0;else if  (cnt == CNT_MAX)cnt_500ms <= cnt_500ms + 3'd1;elsecnt_500ms <= cnt_500ms;//频率计数      
always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)freq_cnt <= 18'd0;else if ((freq_cnt == freq_data)||(cnt == CNT_MAX))freq_cnt <= 18'd0;elsefreq_cnt  <= freq_cnt + 18'd1;always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)freq_data <= DO;else    case(cnt_500ms)3'd0:beginfreq_data <= DO;freq_data2<= XI;enddefault :beginfreq_data <= DO;freq_data2<= XI;endendcaseassign    duty_data1 = freq_data >> 1;assign    duty_data2 = freq_data2 >> 1;//报时always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)beep <= 1'b0;else if ((freq_cnt >= duty_data1)&&(((m_s == 5)&&(m_g== 2))||((m_s == 5)&&(m_g ==0))||((m_s == 5)&&(m_g ==4))||((m_s == 5)&&(m_g ==6))||((m_s == 5)&&(m_g ==8))))// 50 52 54 56 58 报时beep <= 1'b1;else if ((freq_cnt >= duty_data2)&&(((m_s == 0)&&(m_g== 0))))// 正点报时beep <= 1'b1;elsebeep <= 1'b0;   
always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)y <= TIME_1S;else if ( key_in1 == 1'b0) //按键1改时钟频率,同时s_g数码管不变beginy=TIME_1MS;endelse if (key_in2 == 1'b0)//按键2 改时钟频率,改的更快y=TIME_1NS;elsebeginy <= TIME_1S;end/*  always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)begin//beep <= 1'b0;led <= 1'b1;endelse if (m_s>= 5)begin//beep <= 1'b1;led <= ~led;endelsebegin     //beep <= 1'b0;led <= led;end */always@(posedge clk or negedge rst_n) //数码管显示if(rst_n == 0)cnt0 <= 0;else if (add_cnt0)beginif(end_cnt0 )cnt0 <= 0;elsecnt0 <= cnt0 +1;endassign add_cnt0 = 1;
assign end_cnt0 = add_cnt0 && cnt0== TIME_1US-1;reg  [2:0]  cnt1;
wire     add_cnt1;
wire     end_cnt1;always@(posedge clk or negedge rst_n)begin //4个数码管if(rst_n == 0)
cnt1 <= 0;
else if (add_cnt1)beginif(end_cnt1)cnt1 <= 0;elsecnt1 <= cnt1 +1;endendassign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1 == 4-1;reg  [25:0]  cnt2;
wire     add_cnt2;
wire     end_cnt2;
always@(posedge clk or negedge rst_n)begin //1s计数,可以通过按键更改if(rst_n == 0)
cnt2 <= 0;
else if (add_cnt2)beginif(end_cnt2)cnt2 <= 0;elsecnt2 <= cnt2 +1;end
endassign add_cnt2 = 1;
assign end_cnt2 = add_cnt2 && cnt2 == y-1;reg [3:0] sel_data;always@(posedge clk or negedge rst_n)  // 选择显示
beginif(rst_n == 0)seg_ment <=8'hc0;else if (sel_data==0)seg_ment <= 8'hc0;else if (sel_data==1)seg_ment <= 8'hf9;else if (sel_data==2)seg_ment <= 8'ha4;else if (sel_data==3)seg_ment <= 8'hb0;else if (sel_data==4)seg_ment <= 8'h99;else if (sel_data==5)seg_ment <= 8'h92;else if (sel_data==6)seg_ment <= 8'h82;else if (sel_data==7)seg_ment <= 8'hf8;else if (sel_data==8)seg_ment <= 8'h80;else if (sel_data==9)seg_ment <= 8'h90;elseseg_ment <= 8'hc0;
endalways@(posedge clk or negedge rst_n) //动态扫描
beginif(rst_n == 1'b0)seg_sel <= 4'b111_1;else if (cnt1 == 0)seg_sel <= 4'b111_0;else if (cnt1 == 1)seg_sel <= 4'b110_1;else if (cnt1 == 2)seg_sel <= 4'b101_1;else if (cnt1 == 3)seg_sel <= 4'b011_1;elseseg_sel <= 4'b111_1;end    reg  [3:0]  m_g;
wire     add_m_g;
wire     end_m_g;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
m_g <= 0;else if (add_m_g)beginif(end_m_g)m_g <= 0;elsem_g <= m_g +1;end
elsem_g <= m_g;endassign add_m_g = end_cnt2;
assign end_m_g = add_m_g && m_g == 10-1;reg  [2:0]  m_s;
wire     add_m_s;
wire     end_m_s;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
m_s <= 0;
else if (add_m_s)beginif(end_m_s)m_s <= 0;elsem_s <= m_s +1;end
endassign add_m_s = end_m_g;
assign end_m_s = add_m_s && m_s == 6-1;reg  [3:0]  s_g;
wire     add_s_g;
wire     end_s_g;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
s_g <= 0;
else if (add_s_g)
beginif(end_s_g)s_g <= 0;else if (key_in1 == 1'b0)s_g <= s_g ;elses_g <= s_g +1;endelses_g <= s_g;
endassign add_s_g = end_m_s;
assign end_s_g = add_s_g && s_g == x-1;reg  [1:0]  s_s;
wire     add_s_s;
wire     end_s_s;
always@(posedge clk or negedge rst_n)beginif(rst_n == 0)
s_s <= 0;
else if (add_s_s)beginif(end_s_s)s_s <= 0;elses_s <= s_s +1;end
endassign add_s_s = end_s_g;
assign end_s_s = add_s_s && s_s == 3-1;   always@(*)
beginif(s_s==2)
x=4;
else
x=10;end/* always@(posedge clk or negedge rst_n)
beginif(rst_n == 1'b0)sel_data <= 0;else if (cnt1==0)sel_data <= m_g;else if (cnt1==1)sel_data <= m_s;else if (cnt1==2)sel_data <= s_g;else if (cnt1==3)sel_data <= s_s;end  */always@(*)
beginif (cnt1==0)sel_data <= m_g;else if (cnt1==1)sel_data <= m_s;else if (cnt1==2)sel_data <= s_g;elsesel_data <= s_s;end  endmodule

3.仿真代码

`timescale 1ns/1ns module tb_clock();parameter  CYCLE = 20;reg clk;
reg rst_n;wire [3:0] seg_sel;
wire [6:0] seg_ment;clock 
#(.TIME_1US (100),.TIME_1S  (10)
)clock_inst
(.clk      (clk),.rst_n    (rst_n),.seg_sel  (seg_sel),.seg_ment (seg_ment)
);initial begin clk = 0;forever#(CYCLE/2)begin  clk=~clk;end endinitial begin#1rst_n = 0;#(10*CYCLE);rst_n = 1;endendmodule

总结

这是暑假自学搞得数字时钟的设计,虽然功能齐全,但是难免有点不完美的地方,也可以通过层次化的设计让代码变得没有这么长,可以通过这一份代码,要是期末课设弄不出来,参考一下也是可以的,免得挂了,功能反正都可以实现。若有更好的点子也可以一起交流学习一下。



http://www.ppmy.cn/news/546575.html

相关文章

Verilog 实现数码管显视驱动【附源码】

目录 1、实验平台2、实验目的2.1、实验内容 3、实验流程3.1、实验原理3.2、系统架构3.3、功能模块划分3.3.1、数据产生模块模块框图信号定义设计文件 3.3.2、数码管驱动模块模块框图信号定义设计文件 3.3.3、顶层文件 3.4、板级验证 4、总结 1、实验平台 软件&#xff1a;PC、…

运行报错:java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_relocate(linker.cpp:975): can

游戏编译的时候不报错&#xff0c;运行的时候报了如下的错误&#xff1a; &#xff08;主要是Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "rand" referenced by "libgameshared.so"...&#xff09; 10-31 12:35:59.667…

八段数码管动态显示(输入数据为BCD编码)

八段数码管动态显示(输入数据为BCD编码) 一、数码管概述 图1 八段共阴数码管内部等效原理图 图2 八段共阳数码管内部等效原理图 上面两图分别是对应八段共阴、共阳的数码管内部等效图&#xff0c;共阴是将八个LED数码管的阴极连接在一起接低&#xff0c;阳极segment信号只需要…

【接口时序】5、QSPI Flash的原理与QSPI时序的Verilog实现(转载)https://www.cnblogs.com/liujinggang/p/9651170.html

一、 软件平台与硬件平台 软件平台&#xff1a; 1、操作系统&#xff1a;Windows-8.1 2、开发套件&#xff1a;ISE14.7 3、仿真工具&#xff1a;ModelSim-10.4-SE 4、Matlab版本&#xff1a;Matlab2014b/Matlab2016a 硬件平台&#xff1a; 1、 FPGA型号&#xff1a;Xilinx公司的…

【边学边记_10】——8 位7段数码管的动态显示

数码管的驱动设计与验证 一、数码管驱动原理 其中 8 段数码管的结构图如下图所示 由上图可以看出数码管有两种结构&#xff1a;共阴极与共阳极。这两者的区别在于&#xff0c;公共端是连接到地还是高电平&#xff0c;对于共阴数码管需要给对应段以高电平才会使其点亮&#x…

tensorflow安装测试教程【一文读懂】

&#x1f947; 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 &#x1f389; 声明: 作为全网 AI 领域 干货最多的博主之一&#xff0c;❤️ 不负光阴不负卿 ❤️ &#x1f34a; 精选专栏&#xff0c;环境搭建&#xff0c;一文读懂&#xff1a; 每篇博文…

FPGA驱动OLED Verilog代码 (四)------ 字符和汉字显示

一、概述&#xff1a; 首先展示一下成果图&#xff0c;使用RAM的读写来完成&#xff0c;下面依次介绍各个模块 二、OLED显示原理&#xff08;部分&#xff09; oled分为7页&#xff0c;每一页有128个字节用来显示 首先先设置页地址&#xff0c;然后设置列的低地址和高地址&…

android功能相同的view,Android自定义View实现扫描效果

本文实例为大家分享了Android自定义View实现扫描效果的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下 演示效果如下&#xff1a; 实现内容&#xff1a; 1、控制动画是竖向或者横向 2、控制动画初始是从底部/左边开始&#xff0c;或者从上边/右边开始 3、控制动画的时…