本人博客园 https://www.cnblogs.com/LonelyKnight/p/13045848.html
修改了一处错误,顶层文件中sel的位宽,由[2:0]
改为[3:0]
FPGA 器件属于专用集成电路中的一种半定制电路,是可编程的逻辑列阵,能够有效的解决原有的器件门电路数较少的问题。FPGA 的基本结构包括可编程输入输出单元,可配置逻辑块,数字时钟管理模块,嵌入式块RAM,布线资源,内嵌专用硬核,底层内嵌功能单元。由于FPGA具有布线资源丰富,可重复编程和集成度高,投资较低的特点,在数字电路设计领域得到了广泛的应用。FPGA的设计流程包括算法设计、代码仿真以及设计、板机调试,设计者以及实际需求建立算法架构,利用EDA建立设计方案或HD编写设计代码,通过代码仿真保证设计方案符合实际要求,最后进行板级调试,利用配置电路将相关文件下载至FPGA芯片中,验证实际运行效果。
可编程逻辑器件是通过EDA技术将电子应用系统的既定功能和技术指标具体实现的硬件载体,FPGA作为实现这一途径的主流器件之一,具有直接面向用户,灵活性和通用性极大,使用方便,硬 件测试和实现快捷等特点。
硬件描述语言(HDL)是一种用来设计数字逻辑系统和描述数字电路的语言,常用的主要有VHDL、Verilog HDL、System Verilog 和 System C。
作为一种全方位的硬件描述语言,超高速集成电路硬件描述语言(VHDL)具有与具体硬件电路无关、与设计平台无关的特性,具有宽范围描述能力、不依赖于特定的器件、可将复杂控制逻辑的设计用严谨简洁的代码进行描述等优点,得到众多EDA公司的支持,在电子设计领域得到了广泛应用。
VHDL是一种用于电路设计的高级语言,与其他硬件描述语言相比,其具有语言简洁、灵活性强、不依赖于器件设计等特点,使其成为EDA技术通用的硬件描述语言,使EDA技术更便于设计者掌握。
Verilog HDL是广泛应用的硬件描述语言,可以用于硬件设计流 程的建模、综合、模拟等多个阶段。
Verilog HDL 优点:类似C语言,上手容易,灵活。大小写敏感。在写激励和建模方面有优势。缺点:很多错误在编译的时候不能被发现。
VHDL 优点:语法严谨,层次结构清晰。缺点:熟悉时间长,不够灵活
ISE是使用XILINX的FPGA的必备的设计工具。目前官方提供下载的最新版本是14.7。它可以完成FPGA开发的全部流程,包括设计输入、仿真、综合、布局布线、生成BIT文件、配置以及在线调试等,功能非常强大。
本次课设我们是使用VerilogHDL语言在IES Design Suite14.7和spartan 3E Basys2开发板来实现的。
本次课程设计的题目是:基于FPGA的竞赛抢答器。
实验要实现的基本功能是 主持人按下开始,三个人抢答,主持人可以给选手加分或者减分,分数用数码管来显示。以下是主要功能和指标:
(1)设计一个可容纳3组参赛的数字式抢答器,每组设一个按钮,供抢答使用。
(2)抢答器具有第一信号鉴别和锁存功能,使除第一抢答者外的按钮不起作用。
(3)设置一个主持人“复位”按钮。
(4)主持人复位后,开始抢答,第一信号鉴别锁存电路得到信号后,有指示灯显示抢答组别,扬声器发出1~2秒的音响。
(5)设置一个计分电路,每组开始预置10分,由主持人记分,答对一次1分,答错一次减1分。
本次设计内容是通过VerilogHDL语言在IES Design Suite14.7和spartan 3E Basys2开发板来实现的。
这次FPGA的课程设计是一次实践的机会,是我们将平时学到的Verilog HDL的理论知识转化为实际操作;强化了我们对Verilog HDL应用能力,加深了对Verilog HDL的理解;了解所学知识的实际应用;熟悉相关EDA工具的使用;熟悉了FPGA数字电路设计流程;熟练掌握基于Vrilog HDL的FPGA设计方法;对自顶向下的系统设计有了更深刻的认识。
本设计采用了FPGA开发板实现逻辑处理的功能,为了实现数据的输入和输出,模块外围包括:选手输入s0,s1,s2输入接口;主持人复位rst加减控制add,sub分数重置c’l’r输入接口;LED选手灯输出接口;蜂鸣器输出接口;数码管的段选位选A~H,sel输出接口;50MHZ时钟clk输入接口。
这次实验打算把他分为下面几个模块:
锁存鉴定模块,记分模块,动态扫描分数显示模块,led灯和蜂鸣器控制模块。
由抢答模块的输出信号来驱动后面几个模块的工作。
抢答器鉴别锁存模块: 抢答器鉴别模块在这个模块中主要实现抢答过程中的抢答功能,并且能实现当有一路抢答按键按下时,该路抢答信号将其余过滤抢答封锁的功能。其中有三个抢答信号 s1,s2,s3;系统复位信号 rst。
我们可以通过这样的逻辑语言来实现对输入信号的锁存
每个语句的输出会对其他语句的输入产生影响来起到锁存的功能。
在此模块中,我们主要实现了在抢答过程中的主持人对选手分数加减。首先,我们重置分数显示,也就是说,所有的分数都是10。根据参赛者的答案,如果参赛者回答正确,按下add按钮,该选手将加分;如果参赛者答错了,按下sub按钮减去该选手分数。按照下面的流程可以实现其功能。
数码管显示模块主要是由两个模块组成分别为动态扫描以及译码这两个模块组成:动态扫描模块主要是将输入的分数进行动态扫描,显示到每一位数码管的,译码模块是将输入的信号转化为数码管的电平信号。
首先我们需要六个数码管(但是实验板只有四个,设置一个设能端口xuan,xuan为1时显示前两个人的分数,为0时显示三号选手的分数),我们设置一个中间变量sec,当复位信号rst为低时,sec为零,我们使sec不停加一使他在000到011(即0到3)之间循环;
然后我们在设计一个always块使用case语句对daout(数据输出)进行赋值。当sec等于000,001,010,011时,daout对应的为a1[7:4],a1[3:0],
a2[7:4],a2[3:0];再用一次case语句对daout(数据输出)进行赋值。当sec等于000,001,010,011时,daout对应的为a3[7:4],a3[3:0],0000,0000;
(注意:在引脚约束时注意顺序排列)
在这个模块中主要实现抢答过程中将BCD码转换成7段现实数码管的功能
因为本次实验只要求显示0~9所以其他不予理会,当输入的BCD码为除了上表以外的部分都输出11000000(最高为是数码管的点)
在这个模块中主要实现抢答过程中的蜂鸣功能,当抢答者按下抢答键时,除了指示灯显示意外,同时蜂鸣器蜂鸣3秒。此模块就是运用分频信号来控制蜂鸣器,已达到蜂鸣3秒的实验效果。
Led灯只需将chose信号赋给led_out即可;
先用一个计数器来产生一个时钟周期为1s的clk1s,再利用clk1s为敏感信号来控制计数器count3,这个计数器由ena(chose三位的或)来控制,再用case语句对fmq_out来进行赋值,当count3=001,010,011时,fmqout输出为高电平,其余为低。
端口 | 位宽 | I/O | 说明 |
---|---|---|---|
rst | 1 | I | 主持人的开始“复位”信号 |
clk | 1 | I | 系统时钟50MHZ |
s0 | 1 | I | 一号选手的输入 |
s1 | 1 | I | 二号选手的输入 |
s2 | 1 | I | 三号选手的输入 |
add | 1 | I | 加分使能 |
sub | 1 | I | 减分使能 |
clr | 1 | I | 分数重置 |
led_out | 3 | O | LED选择信号 |
fmq_out | 1 | O | 蜂鸣器输出 |
sel | 4 | O | 位选信号 |
A~H | 1 | O | 段选信号 |
xuan | 1 | I | 切换数码管显示选手的分数(1时,前两个选手的分数;0时,三号选手的分数) |
如图所示,当裁判的复位键按下之后,三个选手开始抢答,当s0(一号选手)先抢下之后其他选手的抢答对chose的输出没有影响,裁判按下复位chose重新回到000,第二回合二号选手先抢答,抢下之后其他选手的抢答对chose的输出没有影响。
实现了模块的功能
由图可以以看出实现了模块的功能要求。a1,a2a3为三个选手的分数,初始值都为00010000(10分)chose信号为000;之后chose信号变为010,即选中a2选手的分数;当add信号出现高电平时,a2的分数变为00010001(11分);当add信号再次出现高电平时,a2的分数变为00010010(12分);当add信号再次出现高电平时,a2的分数变为00010011(13分),实现了加分的功能;当sub信号出现高电平时,a2的分数变为00010010(12分),即实现了减分的功能;当clr信号出现高电平时三个选手的分数恢复为00010000(10分)
从两幅波形图都可以看出实现了模块功能。
当xuan为1时,显示前两个选手的分数;当xuan为0时,显示三号选手的分数,多余的数码显示为00。
如图:xuan为1时,观察位选信号sel和数据输出daout,当a1=00010000,a2=00010000,对应的sel=0001,daout=0001,代表第一位输出0001;sel=0010,
daout=0000代表第二位显示0000。如图可看出正确的显示了a1a2的分数。当xuan=0时,也正确显示了a3的分数。
这个仿真结果也很容易明白;clk1s时一个周期为一秒的一个脉冲时钟,如图当chose信号有001输入后,fmq_out会输出一个高电平持续时间图中也可以看出来约为2.7us(可以调节计数器的值来变化clk1s的比例);
led_out如图可见于chose保持一致。
如图,三个选手进行抢答,①1号选手先按下抢答按键,蜂鸣器响起约三秒,一号LED灯亮,②作答之后裁判进行加分和减分的操作,下面a1分数变化。③最后裁判按下复位键开始下一轮抢答。④三号选手先抢答,然后加分,a3发生变化,⑤裁判按下clr分数都恢复为10分。⑥裁判按下复位。其中xuan=0可以看到分数显示为三号选手的分数
因为Basys2板子的数码管只有四个,但题目要求六个,所以设置了一个使能端xuan,为1时显示前两位选手的分数,为0时显示第三位选手的分数。
//引脚分配
//输入
NET "clk" LOC = B8;
NET "rst" LOC = P11;
NET "s0" LOC =G12;
NET "s1" LOC = C11;
NET "s2" LOC = M4;
NET "add" LOC = L3;
NET "sub" LOC = K3;
NET "clr" LOC = A7;
NET "xuan" LOC = B4;
//LED和蜂鸣器
NET "led_out[0]" LOC = M5;
NET "led_out[1]" LOC = M11;
NET "led_out[2]" LOC = P7;
NET "fmq_out" LOC = P6;//用一个LED灯代替
//位选
NET "sel[2]" LOC = f12;
NET "sel[2]" LOC = J12;
NET "sel[1]" LOC = M13;
NET "sel[0]" LOC = K14;
//段选
NET "H" LOC = N13;
NET "G" LOC = M12;
NET "F" LOC = L13;
NET "E" LOC = P12;
NET "D" LOC = N11;
NET "C" LOC = N14;
NET "B" LOC = H12;
NET "A" LOC = L14;
收获很大
《Verilog HDL 数字设计与综合(第二版)》 夏宇闻 电子工业出版社
《基于Verilog 的FPGA设计基础》 杜慧敏 西安电子科技大学出版社
《深入浅出玩转FPGA》 吴宇航 北京航空航天大学出版社
《基于FPGA的数字系统设计》 李辉 西安电子科技大学出版社
//////////////////////////////////////*顶层模块*//////////////////////////////////////////////////
module qiangdaqi_top_1(rst, clk, s0, s1, s2,clr, add, sub,xuan,fmq_out,led_out,sel,A,B,C,D,E,F,G,H
);
input rst;
input clk;
input s0;
input s1;
input s2;
input clr;
input add;
input sub;
input xuan;
output [2:0] led_out;
output fmq_out;
output [3:0] sel;
output A,B,C,D,E,F,G,H;
wire [2:0] chose;
wire [7:0] a1;
wire [7:0] a2;
wire [7:0] a3;
wire [3:0] daout;
qd_zz qd_zz_1 (
.rst(rst),
.clk(clk),
.s0(s0),
.s1(s1),
.s2(s2),
.chose(chose));
jf_zz jf_zz_1 (
.clr(clr),
.add(add),
.sub(sub),
.chose(chose),
.a1(a1),
.a2(a2),
.a3(a3)
);
fmq_zz fmq_zz_1 (
.chose(chose),
.rst(rst),
.fmq_out(fmq_out),
.clk(clk),
.led_out(led_out)
);
dtsm_zz dtsm_zz_1 (
.clk(clk),
.rst(rst),
.a1(a1),
.a2(a2),
.a3(a3),
.daout(daout),
.sel(sel),
.xuan(xuan)
);
ym_zz ym_zz_1 (
.daout(daout),
.A(A),
.B(B),
.C(C),
.D(D),
.E(E),
.F(F),
.G(G),
.H(H)
);
endmodule
///////////////////////////////////*抢答鉴别模块*//////////////////////////////////////////////
module qd_zz(rst, clk, s0, s1, s2, chose
);
input rst;
input clk;
input s0;
input s1;
input s2;
output [2:0] chose;
reg [2:0] chose;
always @(negedge rst or posedge clk)
begin
if (!rst)
begin
chose <= 3'b000;
end
else
begin
if ((s0 == 1'b1 | chose[0] == 1'b1) & (~(chose[1] == 1'b1 | chose[2] == 1'b1 )))
begin
chose[0] <= 1'b1;
end
if ((s1 == 1'b1 | chose[1] == 1'b1) & (~(chose[0] == 1'b1 | chose[2] == 1'b1 )))
begin
chose[1] <= 1'b1;
end
if ((s2 == 1'b1 | chose[2] == 1'b1) & (~(chose[1] == 1'b1 | chose[0] == 1'b1 )))
begin
chose[2] <= 1'b1;
end
end
end
endmodule
//////////////////////////////////////*计分模块*////////////////////////////////////////////
module jf_zz(clr, add, sub, chose, a1, a2, a3,led_out
);
input clr;
input add;
input sub;
input [2:0] chose;
output [7:0] a1;
reg [7:0] a1;
output [7:0] a2;
reg [7:0] a2;
output [7:0] a3;
reg [7:0] a3;
output [2:0] led_out;
wire jiajian;
assign jiajian=add^sub;
assign led_out = chose;
always @(posedge clr or posedge jiajian)
if (clr == 1'b1)
begin
a1 <= 8'b00010000;
a2 <= 8'b00010000;
a3 <= 8'b00010000;
end
else
begin
if (add == 1'b1)
case (chose)
3'b001 :
if (a1 == 8'b00100000)
;
else if (a1[3:0] == 4'b1001)
begin
a1[3:0] <= 4'b0000;
a1[7:4] <= a1[7:4] + 1'b1;
end
else
a1[3:0] <= a1[3:0] + 1'b1;
3'b010 :
if (a2 == 8'b00100000)
;
else if (a2[3:0] == 4'b1001)
begin
a2[3:0] <= 4'b0000;
a2[7:4] <= a2[7:4] + 1'b1;
end
else
a2[3:0] <= a2[3:0] + 1'b1;
3'b100 :
if (a3 == 8'b00100000)
;
else if (a3[3:0] == 4'b1001)
begin
a3[3:0] <= 4'b0000;
a3[7:4] <= a3[7:4] + 1'b1;
end
else
a3[3:0] <= a3[3:0] + 1'b1;
default :
;
endcase
else if (sub == 1'b1)
case (chose)
3'b001 :
if (a1 == 8'b00000000)
;
else if (a1[3:0] == 4'b0000)
begin
a1[3:0] <= 4'b1001;
a1[7:4] <= a1[7:4] - 1'b1;
end
else
a1[3:0] <= a1[3:0] - 1'b1;
3'b010 :
if (a2 == 8'b00000000)
;
else if (a2[3:0] == 4'b0000)
begin
a2[3:0] <= 4'b1001;
a2[7:4] <= a2[7:4] - 1'b1;
end
else
a2[3:0] <= a2[3:0] - 1'b1;
3'b100 :
if (a3 == 8'b00000000)
;
else if (a3[3:0] == 4'b0000)
begin
a3[3:0] <= 4'b1001;
a3[7:4] <= a3[7:4] - 1'b1;
end
else
a3[3:0] <= a3[3:0] - 1'b1;
default :
;
endcase
end
endmodule
////////////////////////////////*蜂鸣器和LED显示*/////////////////////////////////////////
module fmq_zz(chose,rst,fmq_out,led_out,clk);
input rst,clk;
input [2:0]chose;
output [2:0]led_out;
output fmq_out;
reg fmq_out,clk1s;
reg [27:0] count1s;
wire ena;
assign led_out=chose;
always@(posedge clk or negedge rst)
begin
if(!rst)
begin
count1s=28'd0; clk1s=1'd0;
end
else
begin
if(count1s>28'd20)
begin
count1s=28'd0;
clk1s=~clk1s;
end
else
count1s=count1s+1'd1;
end
end
assign ena=chose[0]|chose[1]|chose[2];
reg [2:0]count3;
always@(posedge clk1s or negedge rst)
begin
if(!rst)
count3=3'd0;
else
if(ena)
count3=count3+1'd1;
else
count3=0;
end
always@(posedge clk)
begin
case(count3)
3'b000: fmq_out=1'b0;//count3默认是000,所以这样
3'b001: fmq_out=1'b1;//001,010,011时,输出高
3'b010: fmq_out=1'b1;
3'b011: fmq_out=1'b1;
3'b100: fmq_out=1'b0;
3'b101: fmq_out=1'b0;
3'b110: fmq_out=1'b0;
default:fmq_out=1'b0;
endcase
end
endmodule
///////////////////////////////////////*动态扫描*///////////////////////////////////////////
module dtsm_zz(clk,rst, a1,a2,a3, daout, sel,xuan);
input rst;
input clk;
input [7:0] a1;
input [7:0] a2;
input [7:0] a3;
input xuan;
output [3:0] daout;
reg [3:0] daout;
output [3:0] sel;
reg [1:0] sec;
reg [3:0] sell;
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
sec<=2'b00;
end
else
if (sec == 2'b11)
sec <= 2'b00;
else
sec <= sec + 1;
end
always @(sec or xuan or a1 or a2 or a3)
begin
if(xuan)
begin
case (sec)
2'b00 :
begin
daout <= a1[7:4];sell<=4'b0001;end
2'b01 :
begin
daout <= a1[3:0];sell<=4'b0010;end
2'b10 :
begin
daout <= a2[7:4];sell<=4'b0100;end
2'b11 :
begin
daout <= a2[3:0];sell<=4'b1000;end
default :
begin
daout <= 4'b0000;sell<=4'b0000;end
endcase
end
else
begin
case (sec)
2'b00 :
begin
daout <= a3[7:4];sell<=4'b0001;end
2'b01 :
begin
daout <= a3[3:0];sell<=4'b0010;end
2'b10 :
begin
daout <= 4'b0000;sell<=4'b0100;end
2'b11 :
begin
daout <= 4'b0000;sell<=4'b1000;end
default :
begin
daout <= 4'b0000;sell<=4'b0000;end
endcase
end
end
assign sel=sell;
endmodule
////////////////////////////////////*译码模块*//////////////////////////////////////////////
module ym_zz(daout, A, B, C, D, E, F, G, H
);
input [3:0] daout;
output A;
output B;
output C;
output D;
output E;
output F;
output G;
output H;
wire [3:0] DATA;
reg [7:0] DOUT;
assign DATA = daout;
always @(DATA)
case (DATA)
4'b0000 :
DOUT <= 8'b11000000;
4'b0001 :
DOUT <= 8'b11111001;
4'b0010 :
DOUT <= 8'b10100110;
4'b0011 :
DOUT <= 8'b10110000;
4'b0100 :
DOUT <= 8'b10011001;
4'b0101 :
DOUT <= 8'b10010010;
4'b0110 :
DOUT <= 8'b10000010;
4'b0111 :
DOUT <= 8'b11111000;
4'b1000 :
DOUT <= 8'b10000000;
4'b1001 :
DOUT <= 8'b10010000;
default :
DOUT <= 8'b11000000;
endcase
assign H = DOUT[7];
assign G = DOUT[6];
assign F = DOUT[5];
assign E = DOUT[4];
assign D = DOUT[3];
assign C = DOUT[2];
assign B = DOUT[1];
assign A = DOUT[0];
endmodule
你竟然看完了!!!!
代码都是我调试过的,测试文件没有上传
作者水平有限,如有错误欢迎指正