——基于Basys2开发板电路设计及仿真
1.实验目的
1.了解有关FPGA的基本知识以及在电路设计的应用;
2.了解并学会利用Verilog HDL硬件开发语言设计特定功能的电路,加深对知识的理解; 3.了解Basys2开发板的特点并利用其元件在硬件上实现电路功能; 4.在完成电路设计的过程中积累实际工程开发的经验; 5.培养对于新型实验器材的理解和学习能力;
6.在实验中练习并熟悉有关嵌入式系统开发的过程,为未来的学习打下基础。
2.总体设计方案或技术路线
1.查阅资料,了解Basys2工作相关特点,对于FPGA的开发过程有初步认识;
2.学习Verilog HDL硬件开发语言,阅读相关程序实例加深对于编程语言及模块的理解; 3.确定本次试验电子表的功能,编写程序进行实现; 4.对于编写程序进行调试,修改编写过程中出现的语法错误;
5.再对上一步中调试好的程序进行仿真,编写仿真代码,分析输出并进一步修改程序; 6.对于仿真好的程序建立ucf文件进行引脚约束及综合,生成bit文件; 7.将bit文件烧写到开发板中,在硬件中实现预定功能; 8.对整个实验过程进行总结,分析输出效果并寻找改进方法。
3.实验电路图
由于本实验的电路设计基本全部由Verilog HDL硬件编程语言完成(具体代码附于报告结尾处),因此,没有具体芯片电路图。
而在仿真软件中,提供了实验电路的RTL级原理图和技术原理图。因此我们可以利用ISE Design Suite 14.7电路设计和仿真软件自动生成实验电路的原理图,具体操作过程为,在编写好程序后,双击鼠标左键选择运行Synthesize - XST对电路进行综合,综合成功后,在其子目录下会有View RTL Schematic和View Technology Schematic两个选项,双击这两个选项即可查看该电路的RTL级原理图和技术原理图(如下图)。
由于电路的搭建主要由代码实现,因此软件提供的主要为电路的输入输出原理图,而非具体的电路图,但对于工程的建立与调试已经足够,也就不需要另画详细的电路图了
RTL级原理图:
技术原理图:
4. 仪器设备名称、型号
1.Basys2 FPGA开发板(配有电源及烧写程序线,可与PC计算机相连); 2.Xilinx电路设计及仿真软件ISE Design Suite(版本号14.7); 3.PC计算机,Win7系统;
5.理论分析或仿真分析结果
1.电路理论及功能分析
本实验的目的是设计一个电子表,目前市面上销售的电子表主要有以下功能:时钟计时、
调整时间、秒表和照明及发送信号功能(由于Basys2开发板上没有自带蜂鸣器,因此闹钟功能相对较难实现)。
记时功能,以一秒为单位,由Basys2内部时钟可以使得led显示数码管在每秒可以自动加一,从而实现电子表的计时功能,同时需要一个开关控制继续和暂停,并且在暂停的情况下,通过按键来控制数码管调节时间;
调整时间,在电子表处在计时功能下,操纵按键可以控制相应位数的数码管变化,可以调整时间;
秒表功能,通过开发板上的开关控制数码管一0.01秒的精度进行计时,并且之前的暂停信号在秒表功能下依然有效,此外,还可通过另一个开关对于秒表的清零进行控制;
照明及发送信号功能,通过功能选择开关控制进入照明模式,可以使开发板上的8位led灯按次序进行一定周期的闪烁,完成照明以及必要时发送信号的功能。
各模块流程图如下图所示:
结束 判断结束 判断清零 调整时间 判断暂停 判断暂停 信号输出 计时 计时 照明 秒表模块 计时模块 照明模块 判断使用那个功能模块 开始
电子表效果图
2.实验元器件介绍 (1)可编程逻辑器件FPGA
FPGA(Field-Programmable Gate Array)即现场可编程门阵列,是近年来十分流行的可编程元件,它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点,因此在工程中得到了广泛的应用。
对于FPGA的开发,通常以硬件描述语言(Verilog或VHDL)所完成的电路设计,可以经过简单的综合与布局,快速的烧录至 FPGA 上进行测试,是现代 IC设计验证的技术主流。这些可编辑元件可以被用来实现一些基本的逻辑门电路(比如AND、OR、XOR、NOT)或者更复杂一些的组合功能比如解码器或数学方程式。在大多数的FPGA里面,这些可编辑的元件里也包含记忆元件例如触发器(Flip-flop)或者其他更加完整的记忆块。 (2)Xilinx公司 Basys2开发板
Basys2是围绕着Xilinx公司的Spartan-3E FPGA芯片和一个Atmel AT90USB USB控制器搭建的,它提供了完整、随时可以使用的硬件平台,并且它适合于从基本逻辑器件到复杂控制器件的各种主机电路。可兼容所有版本的ISE电路设计和仿真软件。 3.实验仿真
利用ISE软件对于各个功能进行仿真,仿真时要建立Verilog Test Fixture文件,同时还要加入时钟信号,具体代码如下:
parameter PERIOD = 20; always begin CLK = 1'b0;
#(PERIOD/2) CLK = 1'b1; end
具体各功能仿真如下图: 照明及信号发送功能:
#(PERIOD/2); //开发板自身晶振50MHz
秒表功能:
计时功能:
6.详细实验步骤及实验结果数据记录(包括各仪器、仪表量程及内阻的记录)
1.确定本次试验电子表的功能,具体模块如以上部分介绍,并利用Verilog HDL语言编写程序进行实现(具体源程序文件附在报告后);
2.对于编写程序在ISE Design Suite 14.7软件中选择Check Syntax选项进行编译,修改编写过程中出现的语法错误;
3.再对上一步中调试好的程序进行仿真,编写仿真代码,分析输出并进一步修改程序; 4.对于仿真好的程序建立ucf文件进行引脚约束(ucf文件代码附在报告后);
5.对于程序文件和引脚约束文件在ISE Design Suite 14.7软件中选择Synthesize – XST选项进行程序的综合
6.综合结束后,可以查看RTL级原理图和技术原理图; 7.综合成功后,继续选择Implement Design完成电路的连接;
8.完成后,进一步选择Generate Programming File选项生成可烧写到开发版中的二进制程序文件,即bit文件;
9.选择Manage Configuration Project选项,将bit文件烧写到开发板中,在硬件中实现预定功能,具体界面如下图;
10.对整个实验过程进行总结,分析输出效果并寻找改进方法。
7.实验现象及结论
电路具体效果见下图:
计时功能:
调整时间功能:
照明及信号发送功能:
秒表计时及清零功能:
经过实际观察,电子表电路预定功能全部实现,稳定性也较好,基本达到了预期的计划预实验目的。至此,实验设计的主体部分完成。
8.实验中出现的问题及解决对策
出现的问题:
1. 在实验中,在实现功能选择时,由于Verilog HDL语言无法在同一个或者不同模块中对外设进行两次赋值,因此对于功能选择的实现造成了困难。
2.在开始将程序烧写到开发板上时,开发板一直在执行内部程序,而不响应计算机烧写的程序。
3.实验调试初期,功能显示一直不稳定,功能切换时总出现卡顿,而且经常输出不稳定信号。 解决对策:
1.在编写代码时采用了单模块的结构,并且利用if条件判断语句对于赋值语句进行分割,以避免出现重复赋值的情况;
2.将开发板右上角处的短路块由ROM MODE调节到PC MODE,即可实现计算机程序的执行;
3.多次调试并仔细分析和优化代码,不断尝试修改代码以使得输出达到预期。
9.本次实验的收获和体会、对电路实验室的意见或建议
本实验我有以下几点体会:
1.对于课内没有学过的器材和知识,可以自己去学习和设计,例如试验中Basys2开发板和编程语言;
2.要认识到理论和实际的区别,多进行电路的调试,了解实际情况不可能和仿真波形完全一致,要学会抓住主要特点进行功能的分析和代码的优化;
3.对于好的想法,一定要勇于尝试,深入探究才能更深刻的理解元件特点;
4.充分利用仿真软件与实际硬件电路相结合进行功能测试,这样可以达到事半功倍的效果; 5.最后,强烈建议实验室能够再多提供一些外设(例如蜂鸣器)并多给一些实例程序和历程以供学习和参考。
10.参考文献
[1] 沈涛,李传志,张小平,李斌. Xilinx FPGA/CPLD 设计初级教程[M]. 西安电子科技大学出版社, 2009.
[2] 杜勇. FPGA/VHDL 设计入门与进阶[M]. 机械工业出版社, 2011. [3] 刘颖. 电路实验研究. 哈尔滨:哈尔滨工业大学,2009:8-13.
[4] 周兴华. 手把手教你学 CPLD/FPGA 与单片机联合设计[M]. 北京航空航天大学出版社, 2010.11.
[5] Reece T, Kiddie B T, Robinson W H. Identification of Trojans in an FPGA using Low-Precision Equipment[J].
附录A 电路设计源程序代码
1. 模块定义以及初始化部分:
module ewatch(clk,clr,digit,out1,pause,switch,led,adj);
input clk,clr,pause,adj,switch; output digit,out1,led;
wire pause; //定义暂停控制变量 wire[7:6] switch;
wire[3:0] adj; //定义时间调整变量adj reg[7:0] led;
reg[6:0] out1; //定义数码管段选,即译码后的数据 reg[3:0] digit; //定义数码管位选 reg[31:0] count; //定义计数器 reg[31:0] counter; //定义计数器 reg cn;
//cn为0.01秒向秒的进位位
reg[3:0] sec_l,sec_h,min_l,min_h,display; //定义时钟各位及译码前数据 initial out1<=7'b0000001; initial led<=8'b00000000;
2. 功能选择部分(包括照明和信号输出、时钟计时以及秒表功能): 照明和信号输出:
always@(posedge clk) //功能选择always部分
begin
count=count+1; if(switch[6]==1) begin
//定义分频计数器count和counter
counter=counter+1;
//如果switch6为1进入照明及信号选择功能
//发送SOS信号
//短信号
if(count==10000000) begin end
if(count==20000000) begin end
if(count==30000000) begin end
if(count==40000000) begin
led<=8'b11111111; led<=8'b11111111;
led<=8'b00000000;
led<=8'b00000000;
end
if(count==50000000) begin led<=8'b11111111;
end
if(count==60000000) begin
led<=8'b00000000;
end
if(count==70000000)
begin led<=8'b11111111; end
if(count==90000000) begin led<=8'b00000000; end
if(count==110000000) begin led<=8'b11111111; end
if(count==130000000) begin led<=8'b00000000; end
if(count==150000000) begin led<=8'b11111111; end
if(count==170000000) begin led<=8'b00000000; end
if(count==190000000) begin led<=8'b11111111; end
//长信号
end
if(count==200000000) begin end
if(count==210000000) begin end
if(count==220000000) begin end
if(count==230000000) begin end
if(count==240000000) begin end
if(count==300000000) begin end
count=0;
led<=8'b00000000; led<=8'b11111111; led<=8'b00000000; led<=8'b11111111; led<=8'b00000000;
//短信号
秒表功能部分: else if(switch[7]==1)
begin
if(clr) begin end
else if(!pause&&{min_h,min_l,sec_h,sec_l}!=16'b0101_1001_1001_1001)
if(counter>=30'd499999) begin counter=30'd0; {sec_h,sec_l}=8'h00; {min_h,min_l}=8'h00; cn=1'b0;
//判断清零
//如果switch7为1则进入
end
end
counter=30'd0;
if(sec_l==9) //判断低位是否为9 begin end else begin end if(cn==1) begin end else;
cn=0; if(min_l==9) begin end else
min_l=min_l+1; min_l=0; if(min_h==5); else
min_h=min_h+1; sec_l=sec_l+1; cn=0;
sec_l=0; if(sec_h==9)
begin end
else sec_h=sec_h+1;
sec_h=0; cn=1;
else;
时钟计时部分: else
//awitch6和7均为零时进入时钟计时功能
begin
if((count>=50000000)&&(pause==0)) //计算器以一秒钟为周期,整秒时刻时,begin
如没有外加控制,则秒个位加1,计算器清零
end
sec_l=sec_l+1; count=0;
if(sec_l==10) //秒个位到10,秒十位加1,秒个位置零 begin end
sec_l=0; sec_h=sec_h+1;
if(sec_h==6) //秒十位到6,分个位加1,秒十位置零 begin end
min_l=min_l+1; sec_h=0;
if(min_l==10) //分钟个位到10,分十位加1,分个位置零 begin end
min_h=min_h+1; min_l=0;
if(min_h==6) //分钟十位到6,分十位置零
min_h=0;
else if((count==25000000)&&(pause==1)) //在整秒时,若有外加控制,调整begin
count=0; begin end
if(adj[1]==1) //改变秒十位 begin end
if(adj[2]==1) //改变分个位 begin
min_l=min_l+1; if(min_l==10) min_l=0; sec_h=sec_h+1; if(sec_h==6) sec_h=0; sec_l=sec_l+1; if(sec_l==10) sec_l=0;
//计数器置零
if(adj[0]==1) //改变秒个位
时钟,如不调整就为暂停
end
end
end
end
if(adj[3]==1) //改变分十位 begin end
min_h=min_h+1; if(min_h==6) min_h=0;
3. 数码管选择及显示部分: always@(posedge clk)
begin end
case(count[17:16]) //将需要显示的值付给display
2'b00:begin digit<=4'b1110;display<=sec_l;end 2'b01:begin digit<=4'b1101;display<=sec_h;end 2'b10:begin digit<=4'b1011;display<=min_l;end 2'b11:begin digit<=4'b0111;display<=min_h;end
endcase
4. 数码管译码及输出部分:
always@(posedge clk) //将display译码为七段数码管的二进制数字,赋给out1输出
begin end
case(display) 0:out1<=7'b0000001; 1:out1<=7'b1001111; 2:out1<=7'b0010010; 3:out1<=7'b0000110; 4:out1<=7'b1001100; 5:out1<=7'b0100100; 6:out1<=7'b0100000; 7:out1<=7'b0001111; 8:out1<=7'b0000000; 9:out1<=7'b0000100; endcase
endmodule
附录B UCF源程序代码
NET \"clk\" LOC = \"B8\" ; NET \"clr\" LOC = \"F3\" ; NET \"pause\" LOC = \"P11\" ; NET \"switch<6>\" LOC = \"E2\" ; NET \"switch<7>\" LOC = \"N3\" ; NET \"adj<0>\" LOC = \"G12\" ; NET \"adj<1>\" LOC = \"C11\" ; NET \"adj<2>\" LOC = \"M4\" ; NET \"adj<3>\" LOC = \"A7\" ; NET \"digit<3>\" LOC = \"K14\" ; NET \"digit<2>\" LOC = \"M13\" ; NET \"digit<1>\" LOC = \"J12\" ; NET \"digit<0>\" LOC = \"F12\" ; NET \"out1<6>\" LOC = \"L14\" ; NET \"out1<5>\" LOC = \"H12\" ; NET \"out1<4>\" LOC = \"N14\" ; NET \"out1<3>\" LOC = \"N11\" ; NET \"out1<2>\" LOC = \"P12\" ; NET \"out1<1>\" LOC = \"L13\" ; NET \"out1<0>\" LOC = \"M12\" ; NET \"led<7>\" LOC = \"G1\" ; NET \"led<6>\" LOC = \"P4\" ; NET \"led<5>\" LOC = \"N4\" ; NET \"led<4>\" LOC = \"N5\" ; NET \"led<3>\" LOC = \"P6\" ; NET \"led<2>\" LOC = \"P7\" ; NET \"led<1>\" LOC = \"M11\" ; NET \"led<0>\" LOC = \"M5\" ;
因篇幅问题不能全部显示,请点此查看更多更全内容