verilog四位秒表实现.docx
《verilog四位秒表实现.docx》由会员分享,可在线阅读,更多相关《verilog四位秒表实现.docx(19页珍藏版)》请在冰豆网上搜索。
verilog四位秒表实现
西北工业大学
《FPGA技术实验》
实验报告四
(四位秒表的设计与实现)
学院:
软件与微电子学院
学 号:
姓 名:
专业:
微电子学
实验时间:
2011.11.16
实验地点:
毅字楼335
指导教师:
王少熙
西北工业大学
2011年11月
一、实验目的及要求
实验目的:
学会复杂编程的思想,综合运用verilog语言,进行复杂电路设计及根据模拟综合仿真结果对设计进行优化。
实验要求:
设计时长度为1小时,计时精度为1秒;初始值为:
00:
00计时最大值:
59:
59。
按照三个模块进行,顶层模块不做逻辑设计,只对底层模块例化,底层模块分为计时模块和译码模块。
二、实验设备(环境)及要求
本次实验使用的主要工具为:
SynplifyPro9.6.2和ModelSimSE6.2b。
三、实验内容与步骤
1.实验总体设计思路
按照题目要求本次实验的总体分为三块,即:
顶层模块、计时模块和译码模块。
先设计底层模块,然后在顶层模块进行例化。
计时模块:
通过在例化时对分频系数的改变,得到1秒,10秒,1分,10分的输出,再对每位计数值的最大值进行例化。
在译码模块:
对输出要显示的时间数字进行译码。
系统框图如图1所示:
图1数字秒表总体框图
下面具体说说每一个模块的实现原理:
计数模块:
我们要实现“分分:
秒秒”显示的电子秒表,需要设计计数频率为1Hz的计数器。
因为“分分:
秒秒”的结构对应有4个十进制数字(个位的秒,十位的秒,个位的分,十位的分),考虑到需要用硬件实现,在此,我们将每个显示的值分别进行计数,即分别针对个位的秒、十位的秒、个位的分、十位的分设计对应的计数器,其中个位的秒计数频率为1Hz,即在现实生活中的1秒个位的秒变化一次,其从0到9计数,当从9回到0时,同时向十位秒前进一位,使得十位的秒进行计数加1。
十位的秒从0到5计数,当从5回到0时,向前进一位,使得个位的分进行计数加1。
个位的分从0到9计数,当从9回到0时,向前进一位,使得十位的分进行计数加1。
十位的分则从0到5计数,计数到5时,又回到0。
当四位都达到最大值后,下一秒从0开始。
有分频计数,但我们在此所利用的是系统的1KHz(即本代码中的sysclk_1KHz)的时钟,这样更符合代码规范和要求。
译码模块:
发光二极管七段显示器(也叫七段数码管)的每一个字段是一个发光二极管。
图2为七个显示字段的示意图,图3为七段数码管可以显示的16种字符,当某些发光二极管因为有驱动电流而发光时,因为发光的字段不同,可以组成不同的数字,当输入代码小于9时,译码器的输出应该使七段显示器显示0~9十种数字;当输入代码大于9时,译码器的输出应该使七段显示器显示一定的图形,这些图形应该与有效的数字有较大的区别,不至于引起混淆。
当输入代码为15时,七段数码管所有的LED都不亮,这时为灭零状态。
为了使用方便,通常将各发光二极管的阳极或阴极连接在一起,这样七段LED显示器就有两种连接方式,如果将各发光二极管的阳极连接在一起成为公共电极,则称为共阳极接法,如图4;如果将各发光二极管的阴极连接在一起成为公共电极,则称为共阴极接法,如图5。
我们在本次试验中用共阴极接法。
图2七段数码管显示字段的示意图
图3七段数码管可以显示的16种字符
图4共阳极7段LED图5共阴极7段LED
LED的静态显示虽然有编程容易、管理简单等优点,但是静态显示所要占的资源很多,所以在显示的LED点较多的情况下,一般都采用动态显示方式。
七段LED数码显示器结构利用人的视觉延迟的特点,采用扫描的方式驱动多位七段LED数码管,节省驱动电路,降低功耗。
保证一定的扫描循环频率,得到较好的显示质量。
各位七段LED数码管公用一个段驱动器、一个段码锁存器,为段驱动器提供逻辑输入。
每位七段LED数码管的公共端连接一个位驱动器,控制各位数码管的点燃。
位驱动器由一个位码锁存器提供输入逻辑电平。
显示器在系统中占用两个端口号:
段码口与位码口。
在本模块中,以扫描显示的频率进行2比特宽的模4计数,然后由其值从4个数码管的待显示值输入(本模块的输入为计时模块的输出,即各个位上的的数字data_0、data_1、data_2、data_3)中选择对应的一个经译码后连接到公共的段控制输入端,同时将计数值经2到4译码后输出到对应数码管位的公共端,点亮对应的数码管。
输出很简单:
led_data(控制七段显示译码加上冒点)led_sel(控制当前时刻显示的位(个秒还是十秒还是个分还是十分))。
冒点的处理:
数码管中间的时间分隔冒号点(对应为左边第2个数码管位的DP点)每秒钟闪烁一次,其频率为1Hz,只需要输出1Hz,占空比为50%的周期信号即可。
其他数码管位的点号不需要显示,对应的DP点输出低电平无效信号即可。
这4个信号所示的显示切换计数值进行4选1选择后接到数码管上公共的DP控制端。
在这里我们还是利用一个计数器,当计数达到500的时候就归零,并且控制DP的时钟就翻转一次,就可以完美得到频率为1Hz的信号,在显示的时候我们利用语句(dp)&&(led_sel_num==2'h2),即可控制。
顶层模块:
在前两个底层模块实现的基础上,实现此模块并不难,首先是对个秒位进行例化,主要是控制最大计数个数(个秒为500)以及输出端口。
其余三位也是同样的方法只不过十分位最大计数5000,个秒为30000,十秒为300000。
然后是对译码模块例化,要把计时模块的输出对应到此模块的输入以及对扫描频率最大值进行控制。
2.系统结构和模块划分,关键子模块之间的接口实现定义。
本次实验划分为三个模块:
顶层模块、计时模块和译码模块,顶层模块只做例化,不做逻辑设计,底层模块进行具体功能实现。
由于两个底层模块所用的时钟(sysclk_1KHz)和控制信号(rst_n)都是全局的,接口的实现比较容易,关键是计时模块的输出与译码模块输入的衔接,在顶层模块设了四个wire变量data_0、data_1、data_2、data_3,然后在对计时模块例化(四个输出端口分别与之对应),再在译码模块例化(四个输出端口也分别与之对应),这样就可以完美把两个底层模块衔接起来。
3.子模块设计以及接口定义
计时模块:
此模块主要是进行计数分频,通过不同分频系数得到我们需要的,通过在例化时对分频系数的改变,得到1秒,10秒,1分,10分的输出,再对每位计数值的最大值进行例化。
接口分别为系统时钟sysclk_1KHz,系统控制端rst_n,子分频系数sub_counter_max,以及分频系数counter_max和输出data_out。
译码模块:
利用扫描技术,对输出要显示的时间数字进行译码。
接口分别为系统时钟sysclk_1KHz,系统控制端rst_n,扫描频率scan_freq,个分位的输入data_0,十分位的输入data_1,个秒位的输入data_2,十秒位输入data_3,七段控制控制led_data,以及当前显示位led_sel。
4.测试平台设计
本次实验的实验平台很简单,从顶层模块来看只有两个输入,两个输出,即:
系统时钟sysclk_1KHz,系统控制端rst_n,七段控制控制led_data,以及当前显示位led_sel。
我们只要对时钟和控制端进行简单例化即可实现。
具体实现代码如下:
`timescale1ms/100us//按照1KHz要求实现
modulestopwatchtb;
regclk;
regrst;
wire[7:
0]led_data;
wire[3:
0]led_sel;
initial
begin
rst=0;
#1rst=1;//对控制信号赋值
#1000000$finish;
end
always
begin
#0.5clk=1;//时钟周期11ms
#0.5clk=0;
end
//实例化
stopwatchs1(clk,rst,led_data,led_sel);
endmodule
四、实验结果与数据处理
1.Modelsim仿真结果,波形图,代码覆盖率图等。
由于波形图太长,我们只能选取几个有代表行的点来进行说明与分析。
首先来看图6:
左边为系统的输入输出以及中间一些端口,从上到下依次为系统时钟(clk),控制端(rst),七段译码控制端(led_data),显示位控制端(led_sel)以及计数模块的输出(个分位的输出data_0,十分位的输出data_1,个秒位的输出data_2,十秒位输出data_3)(虽然这几个端口并没有在顶层模块输入输出端口,但是这几个端口是确定我们设计对否的关键,于是在此列出),我们可以看到竖线是显示器上00:
59到01:
00的分界,七段译码控制端(led_data)显示的是10001000,其中最高位是冒点DP控制端,后七位是七段译码(低电平有效),对照显示结构,可知此时显示的是1,显示位控制端(led_sel)(低电平有效)是0111,即此时点亮的是个秒位,下面四个从上到下依次对应个秒,十秒,个分,十分位,即竖线左边的是00:
59而右边的是01:
00。
图6modelsim仿真结果关键展示
(1)
再来看看图7:
经过上面的分析我们可以很容易的看到,此图展示09:
59到10:
00转换的过程,七段译码控制端(led_data)为0(0001000),显示位控制端(led_sel)为十分位(1110)。
图7modelsim仿真结果关键展示
(2)
最后再来看看图8:
次图展示的是从59:
59到00:
00跳转的过程,此时(竖线左边)七段译码控制端(led_data)为5(0010100),显示位控制端(led_sel)为十秒位(1011)。
图8modelsim仿真结果关键展示(3)
通过以上几幅仿真图的展示,可以认为程序是正确的,能够实现我们想要到达的目的。
再用modelsim进行代码覆盖率测试如图9所示,
图9modelsim代码覆盖率测图
可见覆盖率已经很好了,到达了100%。
设计程序的代码如下:
//顶层模块,只做例化,不做设计
modulestopwatch(
sysclk_1KHz,//系统时钟1kHz
rst_n,//全局控制端,低电平有效
led_data,//七段译码控制
led_sel//显示位控制
);
inputsysclk_1KHz;
inputrst_n;
output[7:
0]led_data;//最高位控制冒点,低七位七段译码
output[3:
0]led_sel;
parameterCOUNTER_MAX_1S=19'h1F4;//个秒分频系数500
parameterCOUNTER_MAX_10S=19'h1388;//十秒分频系数5000
parameterCOUNTER_MAX_1M=19'h7530;//个分分频系数30000
parameterCOUNTER_MAX_10M=19'h493E0;//十分分频系数300000
wire[3:
0]data_0;//用于计数模块和分频模块衔接
wire[3:
0]data_1;
wire[3:
0]data_2;
wire[3:
0]data_3;
//调用计时模块,对个秒位例化
countU_counter_1s(
.sysclk_1KHz(sysclk_1KHz),
.rst_n(rst_n),
.sub_counter_max(4'h9),//周期为10
.counter_max(COUNTER_MAX_1S),
.data_out(data_0)
);
//调用计时模块,对十秒位例化
countU_counter_10s(
.sysclk_1KHz(sysclk_1KHz),
.rst_n(rst_n),
.sub_counter_max(4'h5),//周期为6
.counter_max(COUNTER_MAX_10S),
.data_out(data_1)
);
//调用计时模块,对个分位例化
countU_counter_1m(
.sysclk_1KHz(sysclk_1KHz),
.rst_n(rst_n),
.sub_counter_max(4'h9),//周期为10
.counter_max(COUNTER_MAX_1M),
.data_out(data_2)
);
//调用计时模块,对十分位例化
countU_counter_10m(
.sysclk_1KHz(sysclk_1KHz),
.rst_n(rst_n),
.sub_counter_max(4'h5),//周期为6
.counter_max(COUNTER_MAX_10M),
.data_out(data_3)
);
//调用译码模块
led_decoderU_decoder(
.sysclk_1KHz(sysclk_1KHz),
.rst_n(rst_n),
.scan_freq(8'hFA),//扫描频率500Hz
.data_0(data_0),
.data_1(data_1),
.data_2(data_2),
.data_3(data_3),
.led_data(led_data),
.led_sel(led_sel)
);
endmodule
//计数模块
modulecount(
sysclk_1KHz,
rst_n,
sub_counter_max,//各个显示位周期
counter_max,//计系统时钟最大值
data_out
);
parameterM=19;
inputsysclk_1KHz;
inputrst_n;
input[M-1:
0]counter_max;//最大值300000,18位
input[3:
0]sub_counter_max;//最大值9,4位
output[3:
0]data_out;
reg[M-1:
0]counter;//计数器,计系统时钟
regsub_clk;//分频产生的时钟
reg[3:
0]sub_counter;//计数器,计counter
always@(posedgesysclk_1KHzornegedgerst_n)
begin//用于产生counter,为下面服务
if(!
rst_n)
counter<=0;
else
if(counter==counter_max-1)
counter<=0;
else
counter<=counter+1;
end
always@(posedgesysclk_1KHzornegedgerst_n)
begin
if(!
rst_n)
sub_clk<=0;
else
if(counter==counter_max-1)
sub_clk<=~sub_clk;//当counter达到最大时翻转
else
sub_clk<=sub_clk;
end
always@(posedgesysclk_1KHzornegedgerst_n)
begin
if(!
rst_n)
sub_counter<=0;
else
if((sub_counter==sub_counter_max)&&(counter==counter_max-1))
sub_counter=0;//如果两个都到最大值,清零
else
if(counter==counter_max-1)//sub_counter计数条件
sub_counter<=sub_counter+1;
else
sub_counter<=sub_counter;
end
assigndata_out=sub_counter;//sub_counter就是我们要的结果
endmodule
//译码模块
moduleled_decoder(
sysclk_1KHz,
rst_n,
scan_freq,//扫描频率,500Hz
data_0,//各个位输入
data_1,
data_2,
data_3,
led_data,//七段译码控制
led_sel//显示位控制
);
inputsysclk_1KHz;//系统时钟1KHz.
inputrst_n;//全局控制端
input[7:
0]scan_freq;
input[3:
0]data_0;//个秒输入
input[3:
0]data_1;//十秒输入
input[3:
0]data_2;//个分输入
input[3:
0]data_3;//十分输入
output[7:
0]led_data;
output[3:
0]led_sel;
reg[7:
0]led_data;
reg[3:
0]led_sel;
reg[3:
0]led_data_hex;//传输此时输入的数据
reg[7:
0]scan_counter;//扫描计数器
reg[1:
0]led_sel_num;//led选择管子
reg[8:
0]cnt_time;//计数器,用于控制冒点dp
regdp;//冒点
always@(posedgesysclk_1KHzornegedgerst_n)
begin
if(!
rst_n)
scan_counter<=0;//产生扫描频率,用于选择led
else
scan_counter<=scan_counter+1;
end
always@(posedgesysclk_1KHzornegedgerst_n)
begin
if(!
rst_n)
led_sel_num<=2'b0;
else//四个led依次点亮
if(scan_counter==scan_freq)
led_sel_num<=led_sel_num+1;
else
led_sel_num<=led_sel_num;
end
always@(led_sel_num)
begin
case(led_sel_num)//具体到电平控制
2'b00:
led_sel=4'b0111;
2'b01:
led_sel=4'b1011;
2'b10:
led_sel=4'b1101;
2'b11:
led_sel=4'b1110;
default:
led_sel=4'b0000;
endcase
end
always@(led_sel_numordata_0ordata_1ordata_2ordata_3)
begin
case(led_sel_num)//不同时刻传送不同位
2'b00:
led_data_hex=data_0[3:
0];
2'b01:
led_data_hex=data_1[3:
0];
2'b10:
led_data_hex=data_2[3:
0];
2'b11:
led_data_hex=data_3[3:
0];
default:
led_data_hex=4'h0;
endcase
end
always@(posedgesysclk_1KHzornegedgerst_n)
begin//此计数用于控制dp
if(!
rst_n)
cnt_time<=9'h0;
else
if(cnt_time==9'h1F4)
cnt_time=9'h0;
else
cnt_time<=cnt_time+9'h1;
end
always@(posedgesysclk_1KHzornegedgerst_n)
begin
if(!
rst_n)
dp<=1'b1;
else
if(cnt_time==9'h1F4)
dp=~dp;
else
dp=dp;
end
always@(dporled_sel_num)//冒点的显示,1s一次
begin
if((dp)&&(led_sel_num==2'h2))
led_data[7]=1'h0;
else
led_data[7]=1'h1;
end
always@(led_data_hex)//七段译码
begin
case(led_data_hex)
4'h0:
led_data[6:
0]=7'b0001000;
4'h1:
led_data[6:
0]=7'b1101101;
4'h2:
led_data[6:
0]=7'b0100010;
4'h3:
led_data[6:
0]=7'b0100100;
4'h4:
led_data[6:
0]=7'b1000101;
4'h5:
led_data[6:
0]=7'b0010100;
4'h6:
led_data[6:
0]=7'b0010000;
4'h7:
led_data[6:
0]=7'b0101101;
4'h8:
led_data[6:
0]=7'b0000000;
4'h9:
led_data[6:
0]=7'b0000100;
default:
led_data[6:
0]=7'b1111111;
endcase
end
endmodule
2.综合结果布局布线结果,关键路径,资源利用率
对整个模块进行综合结果的RTLVIEW结果如10所示。
图10:
整个模块进行综合结果
对计数分频模块进行综合的RTLVIEW结果如图11:
图11计数分频模块综合图
译码模块综合的RTLVIEW结果如图12:
图1