话不多说先上图
前言
自从学习FPGA以来,唯一做过的完整系统就是基于basys2得多功能数字表。记得当时做的时候也没少头疼,最后用时间磨出来了一个不是很完整的小系统,当时还是产生了满满的成就感。现在回头看来,先不说功能实现的如何,首先代码书写满是不规范,其中犯得最多的一个问题就是把verilog当C来写。所以,我决定趁着寒假自由支配的时间比较多,决定重写多功能数字时钟,算是对我大二第一学期以来对verilog的学习做一个总结。
首先,重写后的工程不仅在功能上做了一些优化,而且占用片内的资源也相对来说少了一些。话不多说先上图。
原来工程的资源占用情况
重写后资源占用情况(少了一点点,呵呵)
一、摘要
多功能数字表,有数字钟、秒表(有暂停清零功能)、闹钟(可设置)、外设蜂鸣器(当闹钟达到设定时间的时候蜂鸣器响应)。第一次写的代码主要是代码书写不规范,可读性和可移植性不强,一个always块里经常给多个寄存器赋值,或者多个if...else语句嵌套,这次重写在占用资源上得到优化,功能更加完善。
二、设计思想
主要有七个模块构成:数字钟计数、秒表计数、按键驱动、数码管显示、蜂鸣器、闹钟设置、中央数据处理中心。下面是rtl原理图。在设计闹钟、时钟、以及秒表共享数码管显示模块的时候,由于每个数码管是单独显示的所以闹钟、时钟、秒表设置模块的一共12个输出我还没有想到更好的办法处理,就专门写了一个cpu模块将各个功能模块对应使用拨码开关什么时候数码管应该显示的信号。感觉这种写法cpu模块的连线有点多。所以以后有机会再回头看看怎么优化一下。
在写时钟计数器时为了使时钟信号的准确,我采用数据流型信号,来作为时间的进位出发标志,代码如下,这种写法,即可以节省寄存器资源占用,也可以在将信号作为边沿检测使用时避免时钟偏移(skew)。
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 parameter TIME = 26'd49999999; 2 //parameter TIME = 26'd49;//仿真专用 3 4 reg [25:0] cnt;//分频一秒时钟信号计数器 5 reg [5:0] cnt_s;//秒计数器 6 wire flag_second;//秒59 7 wire flag_minute_one;//秒59,分个9 8 wire flag_minute_ten;//秒59,分个9,分十5 9 wire flag_hour_one1;//秒59,分个9,分十5,时个9 10 wire flag_hour_one2;//秒59,分个9,分十5,时个3 11 wire flag_hour_ten;//秒59,分个9,分十5,时个3,时十2 12 13 //分频数一秒信号 14 always @(posedge mclk or negedge rst_n) 15 begin 16 if(!rst_n) 17 cnt <= 26'b0; 18 else if(cnt == TIME) 19 cnt <= 26'b0; 20 else 21 cnt <= cnt + 1'b1; 22 end 23 24 //秒计数 25 always @(posedge mclk or negedge rst_n) 26 begin 27 if(!rst_n) 28 cnt_s <= 6'b0; 29 else if(cnt_s == 59 && cnt == TIME) 30 cnt_s <= 6'b0; 31 else if(cnt == TIME) 32 cnt_s <= cnt_s + 1'b1; 33 else 34 cnt_s <= cnt_s; 35 end 36 assign flag_second = (cnt_s == 59 && cnt == TIME)? 1'b1:1'b0; 37 38 //分钟个位计数 39 always @(posedge mclk or negedge rst_n) 40 begin 41 if(!rst_n) 42 minute_one <= 4'b0; 43 else if(minute_one == 9 && flag_second) 44 minute_one <= 4'b0; 45 else if(flag_second || key_en[0] && !clock) 46 minute_one <= minute_one + 1'b1; 47 else 48 minute_one <= minute_one; 49 end 50 assign flag_minute_one = (minute_one == 9 && flag_second)?1'b1:1'b0; 51 52 //分钟十位计数 53 always @(posedge mclk or negedge rst_n) 54 begin 55 if(!rst_n) 56 minute_ten <=