数电自主设计实验报告——Verilog秒表
时间:2020-11-02 12:42:49 来源:勤学考试网 本文已影响 人
姓名 班级 学号
实验日期 节次 教师签字 成绩
基于BASYS2开发板的
记忆秒表设计
实验目的
熟悉基于Verilog HDL语言输入方式的数字电路的设计方法。
掌握基于FPGA的设计流程。
熟悉BASYS2开发板的使用方法。
熟悉Xilinx ISE软件的使用方法。
培养自己独立自主设计并完成实验的能力。
总体设计方案或技术路线
本实验利用BASYS2开发板的已有资源来进行设计实验,并用Xilinx ISE软件来编写和综合Verilog代码。总体设计方案是设计一个带有记忆功能的秒表。具体而言,该秒表通过BASYS2开发板的50M的时钟进行分频计时,最大计时时间为99.99s,用4位数码管动态显示计时时间,除了有基本的运行、暂停及复位清空功能,还有存储当前时间和查看存储时间的功能。
实验电路图
BASYS2开发板原理图--数码管
板上数码管为4位共阳极数码管,每段为低电平点亮,位选接了三极管增大驱动电流,同时为非逻辑,所以位选信号为低电平有效。
BASYS2开发板原理图--按键
本实验用到了两个按键BTN0和BTN1,BTN0为复位按键,对应程序的clear信号,BTN1为存储按键,对应程序的btn[1]信号,按一次该按键数据存储一次,下一次按下时这一次存的数据将被替换掉。
BASYS2开发板原理图--开关
本实验用到了两个开关SW7和SW1,SW7为运行、暂停开关,对应程序的sw[0]信号,开关打到上方为运行,下方为暂停,SW1为显示切换开关,对应程序的sw[1]信号,在计时暂停的前提下,将开关打到上方显示出存储的时间数据。
仪器设备名称、型号和技术指标
硬件:BASYS2开发板
软件:Xilinx ISE(编程)、Digilent Adept(下载)
程序流程图
程序源代码
/////////////////////////////////////////////////////////程序文件
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 15:45:01 11/26/2014
// Design Name:
// Module Name: miaobiao
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
///////////////////////////////////////////////////////////秒表的顶层模块
module miaobiao(
input wire clk,///////////////////////////////开发板系统时钟50MHz
input wire[1:0] btn,////////////////////////两个按键:[0]复位和[1]存时间
input wire[1:0] sw,/////////////////////////两个开关:[0]运行/暂停和[1]显示存储时间
output wire[7:0] smg,/////////////////////数码管的8个段选信号
output wire[3:0] smg_an/////////////////数码管的4个位选信号
);
wire clear;
assign clear=btn[0];////////////////////////////////////将复位按键信号传给clear变量
wire clk_1k;
clkdiv #(50000) m0(clk,clear,clk_1k);//将50MHz进行5万分频输出1kHz时钟信号
wire[15:0]number;
timer m1(sw[0]&clk_1k,clear,number);///////////计时器模块,输出当前时间数据
wire[15:0]num_save;
save m2(clk,clear,btn[1],number,num_save);//////按键按下存储当前时间
wire[15:0]num_display;
/////////////////////////////////////////////////////////////////////////////根据开关状态选择显示内容
choose_4num m3(sw,number,num_save,num_display);
display m4(clk_1k,clear,num_display,smg,smg_an);///////将数字送给数码管显示
endmodule
///////////////////////////////////////////////////////////////////////////////4选1数据选择器模块
module choose_4num(
input wire[1:0]sw,
input wire[15:0]number,
input wire[15:0]num_save,
output reg[15:0]num_display
);
always@(*)
case(sw)
0:num_display<=number;/////////////显示内容为当前时间
1:num_display<=number;/////////////。。。。。。。。。当前时间
2:num_display<=num_save;/////////显示内容为存储时间
3:num_display<=number;/////////////。。。。。。。。。当前时间
default:num_display<=number;
endcase
endmodule
//////////////////////////////////////////////////////////////////////////////////存储时间模块
module save(
input wire clk_save,
input wire clear,
input wire button,
input wire[15:0]number,
output reg[15:0]num_save
);
always@(posedge clk_save)
begin
if(1==clear)
num_save<=0;
else if(1==button)
num_save<=number;
else
num_save<=num_save;
end
endmodule
//////////////////////////////////////////////////////////////////////////////////////计时器模块
module timer(
input wire clk_timer,
input wire clear,
output reg[15:0] number
);
reg[3:0] reg_1ms;
always@(posedge clk_timer,posedge clear)
begin
if(1==clear)
begin
number<=0;
reg_1ms<=0;
end
else
begin
reg_1ms<=reg_1ms+1;
if(reg_1ms>=9)///////////////1ms的计数变量到10清零,同时10ms变量加一
begin
reg_1ms<=0;
number[3:0]<=number[3:0]+1;
if(number[3:0]>=9)////10ms变量到10清零,100ms加一
begin
number[3:0]<=0;
number[7:4]<=number[7:4]+1;
if(number[7:4]>=9)////100ms变量到10清零,1s加一
begin
number[7:4]<=0;
number[11:8]<=number[11:8]+1;
if(number[11:8]>=9)/////1s到10清零,10s加一
begin
number[11:8]<=0;
number[15:12]<=number[15:12]+1;
if(number[15:12]>=9)////10s变量到10清零
number[15:12]<=0;///综上,计时到99.99s后清零
end
end
end
end
end
end
endmodule
/////////////////////////////////////////////////////////////////////////////////////动态扫描显示数字模块
module display(
input wire clk_dis,
input wire clear,
input wire[15:0] number,
output wire[7:0] smg,
output wire[3:0] smg_an
);
reg[1:0] counter;
reg[3:0] reg_num;
wire dp;
always@(posedge clk_dis,posedge clear)
begin
if(1==clear)
begin
counter<=0;
end
else
counter<=counter+1;
end
always@(*)
begin
case(counter)
0:reg_num<=number[3:0];////////将10ms 变量送到数码管第0位显示
1:reg_num<=number[7:4];////////将100ms 变量送到数码管第1位显示
2:reg_num<=number[11:8];//////将1s 变量送到数码管第2位显示
3:reg_num<=number[15:12];////将10s 变量送到数码管第3位显示
default:reg_num<=0;
endcase
end
assign dp=(2==counter);//////////////////第2位数码管的小数点点亮,其余小数点熄灭
num2smg m0(counter,reg_num,dp,smg_an,smg);
endmodule
//////////////////////////////////////////////////////////////////////////////////////时钟分频模块
module clkdiv
#(parameter div=50000)///////默认5万分频
(input wire clk,
input wire clear,
output reg new_clk
);
reg[31:0] counter;
always@(posedge clk,posedge clear)
begin
if(1==clear)
begin
counter<=0;
new_clk<=0;
end
else if(counter>=div/2-1)
begin
counter<=0;
new_clk<=~new_clk;//二分频
end
else
counter<=counter+1;
end
endmodule
///////////////////////////////////////////////////////////////////////////数字转换成数码管段、位码模块
module num2smg(
// input wire clk_smg,
input wire[1:0] which,
input wire[3:0] num,
input wire dp,//dp=1时,点亮小数点
output reg[3:0] smg_an,
output wire[7:0] smg
);
always@(*)
case(which)/////////////////////////////////////////数码管位选子模块
3:smg_an<=4'b0111;
2:smg_an<=4'b1011;
1:smg_an<=4'b1101;
0:smg_an<=4'b1110;
default:smg_an<=4'b1111;
endcase
reg[7:0] r_smg;
always@(*)//////////////////////////////////////////////数码管段选子模块
begin
case(num)
0:r_smg<=8'hc0;
1:r_smg<=8'hf9;
2:r_smg<=8'ha4;
3:r_smg<=8'hb0;
4:r_smg<=8'h99;
5:r_smg<=8'h92;
6:r_smg<=8'h82;
7:r_smg<=8'hf8;
8:r_smg<=8'h80;
9:r_smg<=8'h90;
10:r_smg<=8'h88;
11:r_smg<=8'h83;
12:r_smg<=8'hc6;
13:r_smg<=8'ha1;
14:r_smg<=8'h86;
15:r_smg<=8'h8e;
default:r_smg<=8'hff;
endcase
end
assign smg=r_smg-128*dp;////////////////////////////////////判断是否显示小数点
endmodule
////////////////////////////////////////////////////////////////////////////程序结束END
//////////////////////////////////引脚约束文件
////////////////////////////////////////////////////时钟约束
NET"clk"TNM_NET=clk;
TIMESPEC TS_CLK=PERIOD"clk"20ns high 50%;
NET"clk"LOC="B8";
//////////////////////////////////////////////////////////数码管
NET"smg<7>"LOC="N13";
NET"smg<6>"LOC="M12";
NET"smg<5>"LOC="L13";
NET"smg<4>"LOC="P12";
NET"smg<3>"LOC="N11";
NET"smg<2>"LOC="N14";
NET"smg<1>"LOC="H12";
NET"smg<0>"LOC="L14";
NET"smg_an<3>"LOC="K14";
NET"smg_an<2>"LOC="M13";
NET"smg_an<1>"LOC="J12";
NET"smg_an<0>"LOC="F12";
//////////////////////////////////////////////////////按键
//NET"btn<3>"LOC="A7";
//NET"btn<2>"LOC="M4";
NET"btn<1>"LOC="C11";
NET"btn<0>"LOC="G12";
////////////////////////////////////////////////////开关
NET"sw<1>"LOC="L3";
NET"sw<0>"LOC="N3";
实验结果
最后,成功地编写出程序,调试通过,完成所有功能,整个设计达到预期目标:最大计时时间为99.99s,用4位数码管动态显示计时时间,除了有基本的运行、暂停及复位清空功能,还有存储当前时间和查看存储时间的功能。
实验中出现的问题及解决对策
问题一:数码管按照板子上给的位选引脚编号进行引脚约束后,发现4个数码管显示的内容恰好反过来。
解决对策:用万用表检查电路后,再通过每一位数码管单独静态显示的测试后,证明确实是板子上给的引脚编号有误,在引脚约束文件中对4位数码管的引脚约束进行了修改之后,最后成功地改变了显示顺序,达到了预期的效果。
问题二:每次综合的时候都出现了很多很多的错误和警告。
解决对策:首先,通过软件给出的提示进行修改,解决了一部分错误和警告;然后,将错误和警告代码复制粘贴到网上进行搜索,寻找解决方案,又解决了一部分错误和警告;最后,给老师和学长发邮件请教,或者当面请教寻求帮助,解决了所有错误和又一部分警告,剩下几个警告直接无视,下载到开发板后证明对秒表的功能没有任何影响,说明这些警告可以忽视。
本次实验的收获和体会、对电路实验室的意见或建议
收获和体会:
本次实验,我从一开始的完全不懂FPGA到最后学会FPGA并且成功完成整个实验内容,我最大的收获就是一种自信和成就感,这增加了我在以后的学习生活中面对困难时的勇气和决心。在老师教授FPGA之前,我自己尝试去提前自学FPGA,边看文档边学习,通过对例程的编写和思考完成了基础知识的构建,然后自己编程锻炼和提高编程水平。在FPGA的编程控制过程中,我建立了模块化编程的思想,明白了FPGA触发式的运行方式,初步学会了FPGA编程,并且对FPGA产生了浓厚的兴趣。
但是,从另一方面我也明白了自己掌握的知识只是冰山一角,要想能力更强,还需要付出更多努力。
意见和建议:
希望实验室可以根据课程进度安排实验内容。
希望实验室能举办更多的FPGA的培训。
希望仿真实验室能在所有电脑上都安装Xilinx ISE软件。
希望实验室能定期检查领取了BASYS2开发板的同学的学习进度,或者安排定期必须完成的小任务,督促大家认真学习BASYS2开发板。
参考文献
[1] 廉玉欣. 电子技术基础实验教程. 北京:机械工业出版社,2013.2.
[2] 孟涛. 电工电子EDA实践教程. 北京:机械工业出版社,2010.2.
[3] 王伟. Verilog HDL程序设计与应用. 北京:人民邮电出版社,2005.3.
[4] 云创工作室. Verilog HDL程序设计与实践. 北京:人民邮电出版社,2009.2.