FPGA基于HDL的十进制计数器设计.docx
《FPGA基于HDL的十进制计数器设计.docx》由会员分享,可在线阅读,更多相关《FPGA基于HDL的十进制计数器设计.docx(16页珍藏版)》请在冰豆网上搜索。
FPGA基于HDL的十进制计数器设计
基于HDL的十进制计数器设计
一、实验目的
1、掌握基于语言的ISE设计全流程;
2、熟悉、应用VerilogHDL描述数字电路;
3、掌握基于Verilog的组合和时序逻辑电路的设计方法。
4、掌握chipscope片内逻辑分析仪的使用与调试方法。
5、设计具有异步复位、同步使能的十进制计数器,其计数结果可以通过七段数码管、发光二极管等进行显示。
二、实验原理
1、十进制计数器的设计即是设置一变量,当计数脉冲上升沿到来时,先判断是否为9,若是则置零,否则就进行加一操作。
将变量再进行一个译码操作输出到数码管显示即可。
图1实验原理图
2、数码管分为7段和8段,七段数码管由7段二极管组成。
8段数码管比起7段数码管多了一个显示小数点的LED。
数码管按发光二极管单元衔接方式分为共阳极数码管和共阴极数码管。
本实验使用共阳数码管。
它是指将一切发光二极管的阳极接到一同构成公共阳极(COM)的数码管。
共阳数码管在应用时应将公共极COM接到电源VCC上,当某一字段发光二极管的阴极为低电平相应字段就点亮。
当某一字段的阴极为高电平相应字段就不亮。
共阳端可以作为位选端,实现动态扫描。
动态扫描即是利用了人眼睛的视觉暂留现象,以合适的频率显示每一位数码管,便会产生所有数码管是一起点亮的错觉,数码管原理图如图:
图2共阳数码管示意图
3、数码管显示数字与对应的输入数据的关系如表所示:
0
8'hc0
1
8'hf9
2
8'ha4
3
8'hb0
4
8'h99
5
8'h92
6
8'h82
7
8'hf8
8
8'h80
9
8'h90
表1数码管显示表
4、本次设计一共有11个端口:
输入信号:
clk-------待计数的时钟。
clr---------异步清零信号,当clr=1,输出复位为0,当clr=0,正常计数。
ena---------使能控制信号,当ena=1,电路正常累加计数,否则电路不工作。
输出信号:
q[6:
0]---------驱动数码管,显示计数值的个位。
cout-----------1bit数据,显示计数值向十位的进位图。
三、实验步骤
1、整个系统主要设计的模块是:
十进制计数模块和数码管驱动模块,由于实验板的按键为实现硬件防抖,则需要将按键输入的时钟clk,先通过消抖模块消抖后,再输出至后续使用。
图3系统结构图
2、分别进行各个模块的设计并进行仿真测试。
1)十进制计数器模块设计
输入:
CLK-------待计数的时钟。
CLR---------异步清零信号,当CLR=1,输出复位为0,当CLR=0,正常计数。
ENA---------使能控制信号,当ENA=1,电路正常累加计数,否则电路不工作。
输出:
SUM[3:
0]----------计数值的个位,即在CLK上升沿检测到SUM=9时,SUM将被置0,开始新一轮的计数。
COUT------------计数值的十位进位,即只有在时钟CLK上升沿检测到SUM=9时,COUT将被置1,其余情况下COUT=0。
2)数码管显示驱动模块
输入:
sum[3:
0]-------待显示的数值。
输出:
out[6:
0]----------驱动数码管的七位数值(注意下表中out的对应位
3)消抖模块
(1)按键抖动的产生原因:
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。
因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。
图4按键抖动波形图
(2)本次实验提供的消抖模块简介
图5消抖模块框图
(3)电平检查模块:
检测输入的按键是否被按下或者释放,并分别将H2L_Sig,L2H_Sig拉高,并随后拉低,给出按键的操作信息。
(4)延时模块:
对输入的信号变化进行计时并观察信号的变换情况,对输出端口进行恰当地赋值。
注:
实验资料中将给出消抖模块设计源代码。
对模块的具体设计细节不需理解,消抖模块不要求仿真。
3、根据板子锁定引脚,并生成下载文件。
数码管驱动的七位信号可输出到电路板上相关引脚。
为简化设计,可将消抖模块的复位信号、使能信号与cnt10模块共用。
根据下载板资料,完成引脚锁定,生成相关的用户约束文件(ucf)。
注意:
由于clk没锁在ISE默认的时钟输入引脚上,需要添加代码:
“CLOCK_DEDICATED_ROUTE=FALSE;”
锁引脚代码:
NET"CLK"LOC=P57|CLK_DEDICATED_ROUTE=FALSE;
NET"CLK_50"LOC=P80;
NET"COUT"LOC=P23;
NET"ENA"LOC=P32;
NET"CLR"LOC=P26;
NET"DATA_OUT[6]"LOC=P102;
NET"DATA_OUT[5]"LOC=P99;
NET"DATA_OUT[4]"LOC=P107;
NET"DATA_OUT[3]"LOC=P109;
NET"DATA_OUT[2]"LOC=P112;
NET"DATA_OUT[1]"LOC=P100;
NET"DATA_OUT[0]"LOC=P106;
4、Chipscope在线调试
(1)Chipscope调试开始,新建.cdc文件。
在HDL工程中添加chipscopefile,选择ChipScopeDefinitionandConnectionFile,filename取名seg。
(2)Chipscope-配置.cdc文件
在原有的HDL工程下出现新建seg.cdc文件,可以在chipscope植入ILA和ICONIP核,双击seg.cdc文件,进入配置界面。
(3)Chipscope-设置触发端口、类型等。
进入配置界面,每个触发端口ILA核可支持多路比特数据,最多可有16个端口,触发匹配类型共有6种。
这里配置根据需要调试的数据个数、类型决定。
(4)Chipscope-设置采样深度
设置采样深度,即为一次采样数据所显示的深度、个数。
深度范围512-16384,采样深度越深,耗费资源越多。
然后点击NetConnections标签,设置设置触发时钟与触发信号界面。
(5)Chipscope-设置采样信号
选择ModifyConnections选项,进入采样时钟和触发信号设置,采样时钟用于捕捉触发信号
(6)Chipscope-设置采样时钟
设置触发时钟,一般选择系统频率最高的主时钟。
注:
Netselections中每个channel必须有添加有信号,否则综合要报错。
(7)Chipscope-设置触发数据
同样设置触发信号,将TPO与TP1端口中的每个channel都添加,此处TP0监测clk、clr、ena、cout。
TP1监测的数码管七段信号q[7:
0]、以及COM。
(8)Chipscope-JTAG扫描
设置好以后保存退出,综合与实现,双击图中AnalyzeDesignUsingChipscope。
进入chipscope软件,单击按钮开始JTAG扫描,查找FPGA器件。
(9)Chipscope-装载.bit文件
JTAG扫描以后会发现三个设备,选择XC3S500E,在DEV:
0MyDevice(XC3S500E)右击configure按以下图进行操作,选择下载的bit流文件
(10)Chipscope-装载.cdc文件
(11)开始采样
(12)Chipscope-分析数据
分析数据,在开发板上数码管显示为0,统通过计算得出七段输出q[6:
0]=7’b1000000,加上COM端为8’b11000000。
观察chipscope软件中,如下图所示,采样数据为0xc0,换成二进制刚好是8’b11000000。
得出结论:
硬件测试系统设计正确。
图6Chipscope在线调试仿真图
四、实验结果
1、十进制计数器模块仿真测试
图7计数器波形图
由图可以看出测试波形与理论分析结果相符,当使能ena=1时,clr=0,且时钟上升沿来临时,十进制计数模块开始计数,当计数到9时,产生进位,当clr=1时,计数清零;当ena=0时暂停计数。
2、下载到实验板上面后的结果
数码管开始显示为0,之后每拨动一次拨动开关,数码管的显示值就加1,当加到9的时候产生一个进位即是LED0发光,并且又从0开始计数。
拨动复位键数码管清零。
将使能开关置低,可以看到数码管显示值不在变化,即是计数器不在计数。
实验结果符合设计要求。
3、跑表下载实验效果
八位数码管全部显示为0,之后开始计数,最右边两个数码管一直在加和清零。
右边第三个数码管按照一秒加一的速度在进行变化。
按下复位端,及拨码开关1拨动到低电位,数码管显示值清零。
拨码开关2波动到低电位时,数码管显示值暂停。
实验结果符合设计要求。
4、四位十进制频率计下载效果
开始时数码管全显示为0。
大概过了一秒左右,显示为500,即是事先设定好的计数脉冲的频率。
拨动拨码开关1到低电位的位置,数码管显示值清零,过一秒左右又显示频率值。
五、思考题
1、如何用两个或一个always实现十进制计数模块?
modulecnt10(clk_k,clk,clr,ena,sum,cout);
inputclk,clk_k,clr,ena;
output[3:
0]sum;
outputcout;
reg[3:
0]sum;
regcout;
rega,b;
always@(posedgeclk)
begin
a<=clk_k;
b=a;
end
wirekey_posedge=(~b&a)?
1'b1:
1'b0;
always@(posedgeclk)
begin
if(clr)
begin
cout<=0;
sum<=0;
end
elseif(key_posedge&ena)
begin
if(sum<4'd9)
begin
sum<=sum+1'b1;
cout<=0;
end
else
begin
cout<=1;
sum<=0;
end
end
else
begin
cout<=cout;
sum<=sum;
end
end
endmodule
2、如何用always,或assign实现数码管的驱动设计?
moduletube(clk,sum,seg);
inputclk;
input[3:
0]sum;
output[7:
0]seg;
reg[7:
0]seg;
always@(posedgeclk)
begin
case(sum)
4'd0:
seg<=8'hc0;
4'd1:
seg<=8'hf9;
4'd2:
seg<=8'ha4;
4'd3:
seg<=8'hb0;
4'd4:
seg<=8'h99;
4'd5:
seg<=8'h92;
4'd6:
seg<=8'h82;
4'd7:
seg<=8'hf8;
4'd8:
seg<=8'h80;
4'd9:
seg<=8'h90;
default:
seg<=8'h00;
endcase
end
3、比较实验一与实验二的实验过程,说明原理图输入法与HDL输入法的不同的应用环境。
原理图适用于将模块综合的设计。
HDL输入可以适用基础模块的设计,基础模块写好以后调用起来更方便。
六、代码
1、Cnt10的VerilogHDL代码:
modulecnt10(clk_k,clk,clr,ena,sum,cout);
inputclk,clk_k,clr,ena;
output[3:
0]sum;
outputcout;
reg[3:
0]sum;
regcout;
rega,b;
always@(posedgeclk)
begin
a<=clk_k;
b=a;
end
wirekey_posedge=(~b&a)?
1'b1:
1'b0;
always@(posedgeclk)
begin
if(clr)
begin
cout<=0;
sum<=0;
end
elseif(key_posedge&ena)
begin
if(sum<4'd9)
begin
sum<=sum+1'b1;
cout<=0;
end
else
begin
cout<=1;
sum<=0;
end
end
else
begin
cout<=cout;
sum<=sum;
end
end
endmodule
2、数码管的VerilogHDL代码:
moduletube(clk,sum,seg);
inputclk;
input[3:
0]sum;
output[7:
0]seg;
reg[7:
0]seg;
always@(posedgeclk)
begin
case(sum)
4'd0:
seg<=8'hc0;
4'd1:
seg<=8'hf9;
4'd2:
seg<=8'ha4;
4'd3:
seg<=8'hb0;
4'd4:
seg<=8'h99;
4'd5:
seg<=8'h92;
4'd6:
seg<=8'h82;
4'd7:
seg<=8'hf8;
4'd8:
seg<=8'h80;
4'd9:
seg<=8'h90;
default:
seg<=8'h00;
endcase
end
endmodule
3、激励文件:
moduletest_cnt10;
//Inputs
regclk_k;
regclk;
regclr;
regena;
//Outputs
wire[3:
0]sum;
wirecout;
//InstantiatetheUnitUnderTest(UUT)
cnt10uut(
.clk_k(clk_k),
.clk(clk),
.clr(clr),
.ena(ena),
.sum(sum),
.cout(cout)
);
initialbegin
//InitializeInputs
clk_k=0;
clk=0;
clr=0;
ena=0;
//Wait100nsforglobalresettofinish
forever#10clk=~clk;
//Addstimulushere
end
initialbegin
forever#20clk_k=~clk_k;
end
initialbegin
#30beginclr=1;ena=0;end
#30beginclr=1;ena=1;end
#30beginclr=0;ena=1;end
end
4、引脚锁定:
NETclk_keyLOC=P57;
NET"clk_key"CLOCK_DEDICATED_ROUTE=FALSE;
NETenaLOC=P20;
NETclrLOC=P26;
NETcoutLOC=P22;
#NETsel[0]LOC=P132;
#NETsel[1]LOC=P129;
#NETsel[2]LOC=P128;
#NETsel[3]LOC=P127;
#NETsel[4]LOC=P126;
#NETsel[5]LOC=P123;
#NETsel[6]LOC=P122;
#NETsel[7]LOC=P120;
NETseg[0]LOC=P102;
NETseg[1]LOC=P99;
NETseg[2]LOC=P107;
NETseg[3]LOC=P109;
NETseg[4]LOC=P112;
NETseg[5]LOC=P100;
NETseg[6]LOC=P106;
NETseg[7]LOC=P108;