基于FPGAad数据采集存储处理报告含Verilog源代码.docx
- 文档编号:9810223
- 上传时间:2023-05-21
- 格式:DOCX
- 页数:38
- 大小:2.18MB
基于FPGAad数据采集存储处理报告含Verilog源代码.docx
《基于FPGAad数据采集存储处理报告含Verilog源代码.docx》由会员分享,可在线阅读,更多相关《基于FPGAad数据采集存储处理报告含Verilog源代码.docx(38页珍藏版)》请在冰点文库上搜索。
基于FPGAad数据采集存储处理报告含Verilog源代码
基于FPGAAD数据采集存储处理项目报告
(XILINXALTEARA都可用)
组员:
华、文、杰
1、实验目的
本次实验利用Basys2开发板完成一个开发小项目,即开发AD数据采集存储处理系统,旨在掌握FPGA开发基本方法以及锻炼解决开发过程中出现问题的能力。
2、关键词
Basys2、FPGA、AD转换、RAM、串口通信、MATLAB处理
3、方案设计
要实现本次项目,首先确定器件,其次根据器件时序写出模块的使用程序,最后综合成一个工程,然后进行仿真,上板实验。
本次实验的器件:
32M8位模数转换器、Basys2开发板、串口转RS232cp2102模块、基于三极管的电平转换电路。
选择好器件后,根据器件的时序完成模块的代码书写。
写好AD模块、串口通信模块后,现在就需要处理采样速率与串口通讯速率不匹配的问题了。
根据香农采样定理,采样频率得高于信号频率的两倍才能完成信号复现,我们这里使用25M的高速采样频率,而串口dps9600传送一个位104us明显比采样慢许多。
所以这里需要解决速率不匹配的问题。
我们想到可以利用FPGA的RAM先存储采样来的数据,然后再提取数据经过串口通信送至PC经由MATLAB处理。
本次小项目最为关键的是控制好采样与串口通信的时序问题。
关于时序的控制,留到模块介绍里面说明。
方案小结:
本次实验基于片RAM存储AD采样过来的数据,然后待采样完成后提取数据串口通信至PC,最后经由matlab处理。
4、模块介绍
1.Verilog开发程序介绍
如下给出基于QuartusII绘制出的BlockDiagram图,涵盖了所有的模块以及模块之间的连线。
图4.1综合模块图
如下给出程序目录(txt格式):
现在分别介绍各个模块的端口以及功能。
AD外设:
电路图、实物图、接口
这个外设提供最大32M采样速率,包括一个模拟信号输入和一个采样时钟输入以及八个数字信号输出。
在每个采样时钟的上升沿输出相应的采样数字信号。
Basys2开发板:
串口通讯模块外设:
这个模块旨在把Basys2输出的LVTTL转换成RS232的负逻辑高电平,实现串口与PC的通信。
它有五个引脚:
GND、3.3V、5V、TXD、RXD。
在使用中,只使用RXD和GND。
需要注意的是,倘若GND不与FPGA串口的GND连接,那么串口输出的电平,此模块无法识别,这就是数字地需要共地的重要性。
这里的RXD接Basys的串口输出C6(这是分配的tx输出管脚)。
接线当然用杜邦线的公母线连接。
TOP模块:
TOP模块命名为TEST是当时自己写的非最终版程序用来测试正确性,最后测试正确后也没修改过来,但是对仿真没影响。
clk是系统时钟输入,用来作为全局时钟并且为调用后面四个子模块提供时钟基础,设置为50M。
rst_n是系统复位设置,复位到初始状态,这里大家都熟悉,不用多说。
input[7:
0]datain是AD外设的8位数字信号输入,这个数字信号随着AD采样时钟(clk_25M)变化,在后面CLK模块里面会说明。
outputclk_25M为调用CLK模块后输出的AD采样时钟,这个输出用来接AD外设的时钟输入,提供采样时钟。
outputtx为调用uart模块后,与PC通信的“桥梁”,即携带数据的信号吧。
CLK模块:
这里模块名字设置为AD_2CLK,旨在表明输出两个CLK,用来AD采样和串口通信。
inputclk为系统时钟50Mhz。
Inputreset_n为系统复位,低电平有效。
Outputregclk_25M为AD采样时钟,之前做过说明。
Outputregdps9600为输出给uart模块的时钟。
ENCON模块:
这个模块是整个程序的控制核心,下面介绍端口说明。
Inputwr_clk为写时钟输入,这里我们接的当然就是AD写入的时钟CLK_25M,这里的写速率要和采样速率匹配才可以保证采样再存储的正确性。
Inputrd_clk为读时钟输入,这里接dps9600,符合串口协议。
Inputrst_n为系统复位,低电平有效。
Outputregwren为写使能输出,当wren为高时,写有效,即表明AD的八位数字信号写进RAM。
Outputreg[8:
0]wraddress为写地址,写地址在写时钟下降沿完成加一,保证每次写完后都是新的地址存储数据保证了ram能够存储512个正确数据。
Outputregrden为读使能输出,当rden为高时,读有效,即表明RAM里面对应地址的信号读出。
Outputreg[8:
0]rdaddress为读地址,在每个读信号的下降沿完成加一,保证每次读完一个数据后地址指向新的容,保证读出的512个数据的正确性。
Outputregwrsig为发送给串口的发送信号,上升沿有效。
每一上升沿使串口开始发送送到串口的数据给PC。
RAM模块:
Inputwr_clk为RAM的写时钟,上升沿有效在相应地址写入数据。
Inputwren为RAM写使能信号,高电平有效,有效时配合wraddress和wrclk进行写操作。
Input[8:
0]wraddress为写地址,在每个wr时钟下降沿完成加一操作,确保每次写入的地址正确性。
Inputrd_clk为RAM的读时钟,上升沿有效,在相应的地址读出数据。
Input[8:
0]rdaddress为读地址,同写地址功能。
Inputrden,同wren。
Outputdataout是读出的数据,送至UART模块通信给PC。
UART模块:
Inputclk为CLK模块的clk_dps9600,用于配合这个模块打成波特率为9600的串口输出。
Inputrst_n为复位,低电平有效。
Input[7:
0]datain接RAM模块的数据输出。
Inputwrsig上升沿有效,开启串口发送,接ENCON模块wrsig。
Outputregidle为串口工作状态说明,为高表明正在发送数据。
Outputtx为发送的串口信号,接至上面的串口通讯外设模块RXD。
介绍完所有模块后,现在给出仿真波形以及testbench的设置。
TOP程序以及子程序调用:
Testbench:
对应的仿真波形:
可见,CLK25M输出正确。
可见,tx的输出也满足设计的10101010B
然后验证每个位的时间,大概为104us,满足通信要求仿真通过。
2.Matlab处理程序介绍:
程序:
串口调试小助手软件以及工作界面:
这个程序提取串口通信至PC的数据(经由串口调试小助手输出),然后将十六进制转换成十进制最后绘图输出。
5、关键问题分析处理
我们小组在代码编写编译过程、仿真过程以及上板过程中出了不少错误,但最终都及时纠正了。
在这个发现问题与解决问题的两周里,我们小组对出现的部分问题做了分析与记录有些还自行设计了实验验证。
如下列出了一些关键问题的分析处理。
Ⅰ:
模块的购置问题与电平是否兼容的处理
我们的小项目设计到两个外设,一个是AD转换模块一个是串口转RS232通信模块。
在购置模块时需要考虑引脚电平是否与FPGA电平(我们这里使用的是LVTTL3.3V引脚电平)兼容,所需要的引脚空间Basys2是否有足够的提供,还需要考虑成本以及模块的时序问题。
本实验过程中,我们购置了兼容LVTTL八位AD转换模块和兼容TTL的串口通信模块。
成本很低,串口模块加上AD模块在几十块以。
网购的模块到了之后,我们开始测试各模块的电平值。
经测试,AD输出高3.34V低0V,符合LVTTL3.3V电平逻辑
经测试,串口模块txd输出高5v,低0V。
基于这里,我们通过串口txd接自己的rxd实现了串口模块是否损坏的测试,测试通过,串口是好的。
由于在测量电平时,我们没有完成上板工作,所以我们只好假设串口模块rxd需要接TTL5V逻辑才可正常工作,因此我们组利用两个三极管搭建了一个电平转换电路,实现了电平转换。
其实到后面的上板工作之后,发现3.3V的输出接到RXD,也能正常工作。
Ⅱ:
源代码的借鉴与部分时序代码设计问题
我们程序需要Verilog串口通信模块,为了节省时间,我们在网上寻找了若干串口通信例程,在掌握了例程的原理后,我们自行又编写了自己的串口模块和分时模块还有存储模块以及时序控制模块。
其中,最为困难的是采集速率和通信速率不匹配怎么解决的问题。
我们采取利用ram存储并且提取数据以及设计了合理的存储提取时序控制模块解决这个问题。
然而其中困难重重,由于网上资源有限,对ISEramip核理解不够,我们花了很多时间思考怎么实现这个速率匹配。
最终利用[]ram[]语句构成的模块实现了ram存取功能。
之后时序控制也顺利设计出来。
Ⅲ:
分模块调试
在完成了各个模块的基本书写后,分模块调试是必须的,不然当各个模块整合到主程序之后除了问题,都不好分析。
这里的调试当然还是基于testbench的仿真调试。
Ⅳ:
子程序直接的衔接
在主程序里调用子程序的过程中,我们出现了变量格式不匹配的问题,即上个子程序的输出需要用wire型去构成下个子程序的输入。
而最开始,缺少经验的我们用的是reg型变量来衔接子程序。
仔细想想两个变量类型就知道,子程序就当作是一个黑盒子,只有输入输出,输出的变量类型就是wire型。
在这个变量类型的选择上,我们组在这里跌了大坑,不过最终还是成功解决。
顺利完成编译工作。
Ⅴ:
主程序里子程序的分块调试
完成编译工作之后,并不代表仿真就可以通过。
我们组就遇到了这样的问题。
我们在testbench里设计了[7:
0]datain的激励输入,结果得到的tx输出既有高阻态也有红线不确定值输出。
简而言之,仿真出错。
所以我们开始在主程序里面执行程序的分块调试。
考虑到我们程序的时序逻辑。
我们由输入一个个分块仿真一直到最后输出。
即先在主程序仿真CLK模块,注释掉其他模块并做做适当修改(比如在主module里面添加时钟输出),验证好CLK模块之后,再在主程序里面仿真CLK+ENCON模块,然后再方向很CLK+ENCON+RAM模块,最后在全部仿真。
经过上述主程序里的分块调试,我们成功完成了软件仿真工作。
Ⅵ:
串口调试软件的熟悉
我们的项目需要利用到一个软件,串口调试小助手。
这个软件我们不是很熟悉,我们自己单独设计了一个串口通信工程,并且利用我们购置的串口通信模块完成这个熟悉过程。
主要是通过修改数据长度、校验选择、停止位长度,来熟悉他们之间的通信协议。
最终大家都对这个软件的应用有了深入了解。
Ⅶ:
上板调试
我们组花了两个下午和三个晚上在南一楼完成调试工作,期间出了诸多问题。
但是我们冷静的分析问题,并且根据问题的现象给出做出假设,并给出试探性的解决方案。
这样一步一步,大概处理了七八个问题之后,我们上板终于通过了。
Ⅷ:
最重要的数字地共地问题
这是本次上板实验过程中,出现的最大的问题!
为什么要共地?
因为我们需要一个标准去衡量数字电路中的高电平到底有多高。
我们实验有三个地:
BASYS2FPGAPMODio地、串口模块地、AD模块地(也就是给AD模块供电的电源地,这里使用的是实验室的电源)。
第一个晚上的调试过程中,PMOD地和串口模块地没接,仅仅有一个AD地,结果导致PC上串口调试小助手只能一次接受到512个00数据(这里我们设计的一次采集512个数据),表明我们的软件模块并没出错,出错的是硬件连线。
我们冷静分析,在第二个晚上的实验中,把PMOD地与AD地共在一起,发现不能接受到512个数据了,只能随机的不可控的接到诸如FFFE这样的错误数据,而且只能接收到一两个数据。
出了这样的问题,大家都手足无措。
第三天晚上也就是项目提交的前一天晚上,我们把三个地全部接在一起。
兴奋的发现,通过!
可见,共地在数字电路中是多么重要。
6、结果与分析
如下是在实验室验收时的一图:
写在前面:
本实验采样时钟25M,AD是八位而且输出幅度可调,每次采样512个数据。
故每次采样的总时长:
512*40ns20000ns=20us,f=50khz
也就是说信号为50khz能够采集一个周期,信号为100KHZ能够采集两个周期……
测量结果:
sin50KHZ:
squ50KHZ:
Tri50KHZ:
Sin150KHZ:
Squ150KHZ:
Tri150KHZ:
sin500KHZ:
Sin1MHZ:
Sin5MHZ:
结果分析:
信号源VPP都是2.9V,基于上面的AD转换的算法介绍,我们简单计算一下每个波形最高点对应的十进制数:
(2.9/5+1)/2*255=201
而我们采样出来的一般在180左右。
为什么?
因为我们说过,这个AD采样器有控制采样输出幅度的功能。
如果要实现准确电压复现,可以再通过一个转换算法即可。
根据上述三种波形以及不同频率的波形展示,可以看出,我们基本上完成了项目功能。
但是在5M赫兹时,输出波形躁动很大,研究发现,是因为信号发生器的稳定性原因导致。
(实验室信号发生器在5Mhz时稳定性很低)
7、总结
经过本次小项目,我们大家经历了很多。
从立项到方案设计、模块购置、代码书写调试、仿真调试上板测试等等,大家一起在宿舍与南一实验室直接奔波多次,才完成这个项目,其中的辛苦不易溢于言表。
这个项目,网上基本上找不到完整源代码,所以我们自行设计了除了串口之外的全部代码,这很好的锻炼了我们的应用知识的能力。
在项目工作中,我们知道了发现问题的重要性,清楚的认识到如何设计实验如何设计方案却解决问题更为重要。
我们团结协作大家一起烧脑思考的奋斗经历更是难忘的。
附录:
源代码
//////////////////////////////
//////////////////////////////
moduleTEST(
inputclk,//50M
inputrst_n,//复位
input[7:
0]datain,//AD输入
outputclk_25M,
outputtx//串口
);
wireclk_dps9600;
ad_2clku1(
.clk(clk),//系统时钟50Mhz
.reset_n(rst_n),//复位,低电平有效,复位时时钟都低
.clk_25M(clk_25M),//用于AD采样的频率
.clk_dps9600(clk_dps9600)//用于串口通信的频率
);
wirewren;
wire[8:
0]wraddress;
wire[8:
0]rdaddress;
wirerden;
wirewrsig;
ad_enconu2(
.wr_clk(clk_25M),//写时钟输入
.rd_clk(clk_dps9600),//读时钟输入
.rst_n(rst_n),//复位信号,低电平有效
.wren(wren),//写使能输出
.wraddress(wraddress),//写地址输出
.rden(rden),//读使能输出
.rdaddress(rdaddress),//读地址输出
.wrsig(wrsig)//串口发送信号输出
);
wire[7:
0]dataout;
ramu3(
.wr_clk(clk_25M),//采集时钟
.rd_clk(clk_dps9600),//串口通讯时钟
.wren(wren),//写使能
.rden(rden),//读使能
.datain(datain),//采集数据入
.wraddress(wraddress),//写地址
.rdaddress(rdaddress),//读地址
.dataout(dataout)
);
ad_uartu4(
.clk(clk_dps9600),//UART时钟,采用clk_dps9600,调用AD_2CLK模块
.rst_n(rst_n),//复位信号
.datain(dataout),//AD送过来的数字信号
.wrsig(wrsig),//发送命令,上升沿有效
.idle(),//线路状态指示,高忙,低闲
.tx(tx)//发送数据信号
);
endmodule
//////////////////////////////
//////////////////////////////
modulead_2clk(
inputclk,//系统时钟50Mhz
inputreset_n,//复位,低电平有效,复位时时钟都低
outputregclk_25M,//用于AD采样的频率
outputregclk_dps9600//用于串口通信的频率
);
reg[1:
0]t_1;
reg[15:
0]t_2;
//2分频
always(posedgeclkornegedgereset_n)
begin
if(!
reset_n)begincnt_1<=2'b0;clk_25M<=1'b0;end
elsebegin
if(cnt_1==2'd0)beginclk_25M<=1'b1;t_1<=t_1+2'd1;end//1-21
elseif(cnt_1==2'd1)beginclk_25M<=1'd0;cnt_1<=2'b0;end//03-0
elsecnt_1<=t_1+1'b1;
end
end
always(posedgeclkornegedgereset_n)
begin
if(!
reset_n)begincnt_2<=2'b0;clk_dps9600<=1'b0;end
elsebegin
if(cnt_2==16'd162)beginclk_dps9600<=1'b1;t_2<=t_2+16'd1;end
elseif(cnt_2==16'd325)beginclk_dps9600<=1'b0;cnt_2<=16'd0;end
elsecnt_2<=t_2+16'd1;
end
end
endmodule
//////////////////////////////
//////////////////////////////
modulead_encon(
inputwr_clk,//写时钟输入
inputrd_clk,//读时钟输入
inputrst_n,//复位信号,低电平有效
outputregwren,//写使能输出
outputreg[8:
0]wraddress,//写地址输出
outputregrden,//读使能输出
outputreg[8:
0]rdaddress,//读地址输出
outputregwrsig//串口发送信号输出
);
//计数器
reg[10:
0]t;//大计数器
reg[10:
0]wr_cnt;//分-读计数器
reg[10:
0]rd_cnt;//分-写计数器
//计数器——写部分
always(posedgewr_clkornegedgerst_n)//这部分先按自然时间累增
begin
if(!
rst_n)
wr_cnt<=11'd0;
elseif(wr_cnt<11'd1024)
wr_cnt<=wr_cnt+11'd1;
else
wr_cnt<=wr_cnt;
end
//计数器——读部分使写计数器在读计数器533后,完成自加
//完成wrsig需要再来个计数器
reg[7:
0]wrsig_cnt;
regflag;
always(posedgerd_clkornegedgerst_n)
begin
if(!
rst_n)begin
rd_cnt<=11'd533;
wrsig_cnt<=8'd0;
end
elseif(rd_cnt==11'd1045)
rd_cnt<=rd_cnt;
elseif(wrsig_cnt==8'd255)begin//等待读出操作完成后,继续下一次读,255是一个比较合理的数
rd_cnt<=rd_cnt+11'd1;
wrsig_cnt<=8'd0;
flag<=1'd1;
end
elsebegin
flag<=1'd0;
wrsig_cnt<=wrsig_cnt+8'd1;
end
end
//计数器分配
always(*)
begin
if(!
rst_n)
cnt<=11'd0;
elseif(wr_cnt<=11'd533)
cnt<=wr_cnt;
else
cnt<=rd_cnt;
end
//写使能
always(posedgewr_clkornegedgerst_n)
begin
if(!
rst_n)
wren<=1'd0;
elseif(cnt<11'd11)//0-10=0
wren<=1'b0;
elseif(cnt>11'd10&&t<11'd523)//11-522=1
wren<=1'b1;
elseif(cnt>11'd522)//523-=0
wren<=1'b0;
end
//读使能
always(posedgerd_clkornegedgerst_n)
begin
if(!
rst_n)
rden<=1'd0;
elseif(cnt<=11'd533)//0-533=0
rden<=1'b0;
elseif(cnt<11'd1045)//534-1045=1
rden<=1'b1;
else//1046-=0
rden<=1'b0;
end
//写地址,在写信号激发时,每个时钟下降沿加一,初始定位0,复位后也为0;
always(negedgewr_clkornegedgerst_n)
begin
if(!
rst_n)
wraddress<=9'd0;
elseif(wren)
wraddress<=wraddress+9'd1;
else
wraddress<=wraddress;
end
//读地址和串口发送信号,在读信号激发时,而且falg信号出现时,地址加一,信号为1初始定位0,复位后也为0;
always(negedgerd_clkornegedgerst_n)
begin
if(!
rst_n)
rdaddress<=9'd0;
elseif(rden&&flag)begin
rdaddress<=rdaddress+
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 FPGAad 数据 采集 存储 处理 报告 Verilog 源代码