EDA实验报告频率计及DDS.docx
- 文档编号:30017398
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:18
- 大小:189.79KB
EDA实验报告频率计及DDS.docx
《EDA实验报告频率计及DDS.docx》由会员分享,可在线阅读,更多相关《EDA实验报告频率计及DDS.docx(18页珍藏版)》请在冰豆网上搜索。
EDA实验报告频率计及DDS
EDA实验II
信号源、频率计的设计
姓名:
叶爽
班级:
08042100
学号:
0804210147
指导教师:
花汉兵蒋立平
摘要
本实验利用ALTERA公司的CYCLONE系列硬件平台和QUARTUSⅡ软件平台,对Cyclone系列的EP1C12Q240C8芯片进行设计,实现了一个简单的正弦波,三角波及调幅波信号源和频率计。
关键字:
FPGAQURATUSⅡ数字钟VHDL
Inthisexperiment,weusethehardwareplatformofcycloneproducedbyALTERAandthesoftwareplatformwhichcalledquartusII.Wedesignasimplesinewaveandtrianglewaveandamplitude-modulationwavegeneratoronthechipofep1c12q240c8ofcycloneseries.
Keyword:
FPGAQURATUSⅡVHDL,SignalGenerator.
实验目的P4
实验要求P4
实验步骤及设计过程P4
编译下载P13
经验总结P13
一.实验目的。
1.熟悉QUARTEUS-Ⅱ软件的使用方法,和实现FPGA电路设计的一般流程。
2.了解VHDL语言编程。
3.了解基本的自顶向下模块化设计思想。
二.实验要求。
1.利用DDS的方案,产生一个正弦波输出,频率可控。
2.利用DDS产生调制信号和载波信号,并根据所学的高频电子线路知识产生标准调幅波。
3.设计一个数字频率计,能够将频率显示在数码管上。
三、实验步骤及设计过程。
1.DDS信号发生模块(半周期数据,正弦波,三角波)(模块名:
)
DDS其实质是以基准频率源(系统时钟)对相位进行等间隔的采样。
由图见,DDS由相位累加器和波形存储器(即,ROM查询表)构成的数控振荡器(NCO_NumericallyControlledOscillators)、数模转换器(DAC)组成。
在每一个时钟周期,N位相位累加器与其反馈值进行累加,其结果的高L位作为查询表的地址,然后从ROM中读出相应的幅度值送到DAC。
再由DAC将其转换成为阶梯模拟波形,最后由具有内插作用的LPF将其平滑为连续的正弦波形作为输出。
因此,通过改变频率控制字K就可以改变输出频率
。
DDS模块中,遇到的第一个问题就是如何产生有符号数的ROM。
在实验指导手册里提供的都是产生无符号数的计算机程序,但是由于后面涉及到调幅波中的相乘运算,使用无符号数的话会非常麻烦,因此第一步必须做出有符号数的ROM出来。
产生有符号数的C++程序如下。
其中加下划线的部分就是有符号数和无符号数的程序区别所在。
#include"iostream.h"
#include"stdio.h"
#include"math.h"
intmain(intargc,char*argv[])
{
inti;
doubles;
for(i=0;i<2048;i++)
{
s=sin(atan
(1)*8*i/4096);
printf("%d:
%x;\n",i,(int)(s*511));
}
return0;
}
相位累加器,寄存器均由VHDL语言编写,比较简单,此处只给出源程序,略去分析。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityphase_adderis
port(
k:
instd_logic_vector(11downto0);
clk:
instd_logic;
en:
instd_logic;
reset:
instd_logic;
out1:
outstd_logic_vector(11downto0)
);
endentityphase_adder;
architectureartofphase_adderis
signaltemp:
std_logic_vector(11downto0);
begin
process(clk,en,reset)
begin
ifreset='1'then
temp<="000000000000";
else
ifclk'eventandclk='1'then
ifen='1'then
temp<=temp+k;
endif;
endif;
endif;
out1<=temp;
endprocess;
endarchitecture;
==================================
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityreg11is
port
(
clk:
instd_logic;
d:
instd_logic_vector(11downto0);
q:
outstd_logic_vector(10downto0)
);
endreg11;
architectureartofreg11is
signaltemp:
std_logic_vector(11downto0);
begin
process(clk)
begin
if(clk'eventandclk='1')then
if(d<"100000000000")then
temp<=d;
elsetemp<=("111111111111"-d);
endif;
endif;
endprocess;
q<=(temp(10)&temp(9)&temp(8)&temp(7)&temp(6)&temp(5)&temp(4)&temp(3)&temp
(2)&temp
(1)&temp(0));
endart;
======================================
在本次实验中,为了节约存储空间,我的ROM里只存储了半周期数据。
但如果按照正弦函数的前半周期来保存的话,后半周期会涉及到符号位的转换,比较麻烦,因此我选择保存了余弦函数的前半周期数据。
对于送进来的频率控制字K,如果在0-PI之间,那么不做变换,直接输出,如果在PI-2PI之间,那么输出2PI-K,即关于PI做了一个对称变换,由正弦波的对称性知,这样不会改变波形。
分析寄存器的代码就可以发现,寄存器是12位地址输入,却只有11位地址输出,就是因为做了一次对称变换,接口宽度缩减了一半。
对于三角波,其核心就是改变ROM的内容,也就是产生MIF文件的计算机程序需要修改一下。
我直接定义了一个周期为2PI,幅度为2的三角波函数TRIANGLE.那么MAIN函数中只要把SIN改为TRIANGLE就可以了。
程序如下。
#include"iostream.h"
#include"stdio.h"
#include"math.h"
doubletriangle(doublex)
{
if(0<=x&&x<=4*atan
(1))
return((2*atan
(1))-x)/(2*atan
(1));
elsereturn(triangle(8*atan
(1)-x));
}
intmain(intargc,char*argv[])
{
inti;
doubles;
for(i=0;i<2048;i++)
{
s=triangle(atan
(1)*8*i/4096);
printf("%d:
%x;\n",i,(int)(s*511));
}
return0;
}
对于反相功能,其实就是在寄存器之前加一个反相模块就可以了。
VHDL如下。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityphase_reverseis
port(
en,clk:
instd_logic;
phase_ctrl:
instd_logic_Vector(11downto0);
dout:
outstd_logic_vector(11downto0)
);
endphase_reverse;
architecturebehofphase_reverseis
signaltemp:
std_logic_vector(11downto0);
begin
process(clk)
begin
ifclk'eventandclk='1'then
ifen='1'thentemp<=phase_ctrl+"100000000000";
elsetemp<=phase_ctrl;
endif;
endif;
endprocess;
dout<=temp;
endarchitecture;
============================================
仔细分析一下,就是当反相开关打开以后,相位控制字统一加上2048,正好是半个周期,因此反相。
完整的DDS模块
完整的DDS(反相)模块
DDS模块封装,KCUSTOM是自定义的频率控制字,CLK为时钟输入,DAIN为输出的正弦波信号。
2.调幅波模块
根据已学过的高频电子线路知识知道调幅波的表达式如下:
考虑到这当中用到大量的运算,如果一个一个单独定制乘法加法模块较为繁琐,因此直接使用VHDL语言编写,简洁明了。
VHDL代码如下。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
useieee.std_logic_arith.all;
entitytestis
generic(ma:
integer:
=7);
port(
clk:
instd_logic;
sig:
insigned(9downto0);
carry:
insigned(9downto0);
amwave:
outsigned(9downto0)
);
endtest;
architecturebehoftestis
signals:
signed(3downto0);
signalt:
signed(23downto0);
begin
s<=conv_signed(ma,4);
process(clk)
begin
ifclk'eventandclk='1'then
t<=(s*sig+3577)*carry;
amwave<=t(22downto13);
endif;
endprocess;
endbeh;
========================================
在这当中最难理解的莫过于3577这个数了。
在十进制中,我们加上的是1。
之前接触的一直是10进制,没有仔细思考这个1的含义。
现在换成2进制,当然不能加上二进制的1,而要换成别的。
十进制当中,这个1是调制度M的最大值与正弦函数的最大值1相乘的结果。
而在二进制中,调制度用四位有符号数表示,最大为7,正弦函数用10位有符号二进制数表示,最大值为511。
因此,相乘后结果就是3577。
用它来替换原来十进制中的1,才能得出正确的结果。
如图所示为AM模块的原理图
3.频率计模块
频率计的原理有两种,一种是计数式测量,一种是周期式测量。
前者对与频率较高的信号测量较为准确,后者对于频率较低的信号测量较为准确。
考虑到我们要测量的信号频率都很高,因此选择前者。
我设计的频率计有4个量程,×1,×10,×100,×1000。
原理很简单,例如×1档来说,只要给一个1HZ脉冲,通过计数器计算出在脉冲时间内信号上升沿的个数就可以了,也就是把信号的符号位接在计数器的CLK端。
TIMER模块为定时电路,控制计数的停止与开始,送到T_CON模块后,由该模块发出使能信号。
CNT4*10模块为计数模块,DISPREG为显示寄存器,使得示数不至于变化的太快。
4.基准频率源模块
由于频率计模块中涉及到需要产生精确的基准频率,因此需要对系统48M频率进行分频。
对48分解质因数可知,需要2,3,5分频。
2,3分频的模块在数字钟里已有。
5分频的原理和3分频非常类似,同样是利用把PQ变量错开半周期,不同的是判断语句不一样,而且在5分频里PQ要变为三位矢量,否则没有足够多的状态数来产生分频效果。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
entityFP5is
port(
clk:
instd_logic;
clkout:
outstd_logic
);
endFP5;
architecturertlofFP5is
signalp,q:
std_logic_vector(2downto0);
begin
process(clk)
begin
if(clk'eventandclk='1')then
ifp="100"thenp<="000";
else
p<=p+1;
endif;
endif;
endprocess;
process(clk)
begin
if(clk'eventandclk='0')
then
ifq="100"thenq<="000";
else
q<=q+1;
endif;
endif;
endprocess;
clkout<='1'when(p
(2)='0'andq
(2)='0'and(p
(1)='0'orp(0)='0'))else'0';
endrtl;
====================================================
5.AD转换(未完成)
我在周二的时候就已经做完了所有的基本功能,然后开始思考如何加上一些附加功能。
我首先考虑的就是,我的频率计能不能测量一个外部的信号的频率。
由于板子内部全部是数字信号,因此外部的模拟信号进来必须要经过AD转换。
将外部的信号接在板子上的SGIN引脚处,对ADC做适当的设定,在ADC的8个输出脚上就会产生相应的数字信号。
于是我在接完线以后尝试使用SIGNALTAP逻辑分析仪来捕捉ADC的输出信号,但是很遗憾,尝试了一个下午,ADC输出口出来的数字信号始终无规律,而按照理论它应该是正弦波。
更换实验台也无果。
这个问题曾经在去年的华为杯比赛时出现过,我们为了这个问题调试了整整一天,直至最后才解决。
不过我已经记不清当时是如何解决的了,当时做的报告上也没有写这方面的内容。
所以,以后写报告的时候一定要有经验总结的内容,把实验中遇到的所有问题都记录下来。
6.相位测量(未完成)
相位测量的原理也是比较简单的。
对于两个用DDS产生的正弦波信号,只需取出他们同一时刻的频率控制字的差值,计算其差值,再换算成相位,送到显示电路显示即可。
但是很遗憾的是,我在接入相位测量电路以后,频率计的示数错误。
在之前的调试过程中曾经出现过这样的状况,我知道是时钟信号太多,互相之间有干扰的原因,但是在我尽全力把所有的多余的高频率时钟去掉以后,问题仍然没有解决。
由于时间已经到快验收的时间了,所以不得已只能使用做相位测量之前的备份版去验收,这个功能没有能够出现在最后的验收作品中。
7.动态显示电路
动态显示电路主要目的就是显示频率计的示数。
与之前数字钟的设计几乎完全一致,只不过此次是4位数码管而已,所以对上次的电路略加修改就可以了。
8.显示切换电路
由于要在正弦调幅波,三角调幅波,反相波三者之间切换,所以我自己写了个简单的数据选择器来实现切换功能。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
ENTITYMUX42IS
PORT(
CLK,SW2,SW3:
INSTD_LOGIC;
SIGIN,AMWAVEIN,SIG_ORI,SIG_REV,TRI_SIG,TRI_MOD:
STD_LOGIC_vECTOR(9DOWNTO0);
DA1IN,DA2IN:
OUTSTD_LOGIC_VECTOR(9DOWNTO0)
);
ENDMUX42;
ARCHITECTUREBEHOFMUX42IS
SIGNALTEMP1,TEMP2:
STD_LOGIC_VECTOR(9DOWNTO0);
BEGIN
PROCESS(CLK)
BEGIN
IFCLK'EVENTANDCLK='1'THEN
IFSW2='1'THEN
TEMP1<=SIG_ORI;
TEMP2<=SIG_REV;
ELSIFSW3='1'THEN
TEMP1<=SIGIN;
TEMP2<=AMWAVEIN;
ELSE
TEMP1<=TRI_SIG;
TEMP2<=TRI_MOD;
ENDIF;
ENDIF;
ENDPROCESS;
DA1IN<=TEMP1;
DA2IN<=TEMP2;
ENDBEH;
===========================================
10.其它
总图内还有很多其它的小模块比如常数模块等,比较简单,用VHDL写也就是几行的工作量,在此略去。
11.总图
三.编译下载
首先进行引脚的设置,先对最终的xianshi电路进行编译,然后点Assignments->Pins,然后按书后附录配置引脚。
配置完再点Assignments->Settings设置其余管脚,然后再编译,点下载按钮,再点HardwareSetup将平台改为ByteBlaster[LPT1],再点START即可。
四.实验总结和感受。
1.我在实验中遇到过的比较大的困难。
1)频率计示数错误。
其实这个问题的解决纯粹是经验了,因为单单去排查频率计和显示电路都没有任何问题。
我只是联想到做电子钟的时候有一次因为多引了一个1000HZ的OUTPUT出来并且没有锁定任何端口,结果直接导致钟走时不稳定。
所以我怀疑是不是还是这方面的问题。
我把所有多余的时钟信号全部删掉以后,问题解决。
所以SIMPLEISBEST是永恒不变的真理,在实现同样的功能的情况下,结构简单意味着高可靠性!
不仅是电路,现在的机械设计都有回归简单的趋势,都是一个道理,简单的东西维护成本低,故障率小。
尤其是我电路里多出来的时钟这样多余的东西,更是不应当保留。
2)调幅波波形不对。
某天下午我一直都在折腾调幅波公式里的1换算成2进制到底是多少。
由于我进度比较快,也没有别人可以求助,于是我从差不多从12位2进制的0一直试到111111111111,几乎见过了所有的错误波形,没有一个是对的。
所有的波形都基本上都是由调幅波做某种变换而来,都很像,但都不对。
晚上回去静下心来翻了一会高频书,终于弄懂了,觉得应该是7×511。
第二天上机一试,果然成功了。
所以我觉得以后做实验千万不能急于求成,看到东西近在眼前却搞不定就急躁,乱来。
我要是下午就翻翻书,也许下午就搞出来了,不用等晚上了。
所以做实验的时候心态要好。
2.我在绘制原理图过程中的经验总结
1.使用VHDL代码写模块时,保存的VHD文件的名字最好和代码里ENTITY后的实体名保持一致,否则在你写了多个相似模块以后,QUARTUS很有可能张冠李戴,在你双击了这个模块以后它却打开了另一个VHD文件,不注意的话很容易出错。
2.连线要简洁。
这个感受是我在做电子钟的时候就体会到的。
对于那些密密麻麻的端口连接,直接用信号名就可以,简洁明了。
3.对于从书上看来的源代码的原理一定要弄懂。
我之前电子钟里面的3分频代码是从书上看来的,当时我对它的原理不是太清楚。
后来偶然的机会我用仿真的方法仔细观察了一下波形,一目了然,弄清了它的原理。
于是本次实验中需要5分频的时候我就能很顺利的在源代码的基础上改一下就产生了5分频。
直接抄代码的话,一旦电路出现任何问题,根本都不知道从哪下手。
4.关于创新设计。
这次实验我的进度比较快,所以我有比较充裕的时间来思考一些附加功能。
从实用的角度出发,我首先想到的就是,我能不能测量一个外部进来的正弦信号的频率,老是测量板子里面产生的频率我觉得有点自己和自己玩的感觉,没什么意思。
后来很遗憾,卡在AD转换那一步了。
然后我设计了一个三角波发生器,这个我觉得还比较实用。
后来周三的晚上我曾经去图书馆查了一下有没有什么比较好的设计,感觉都不大实用,比如LCD图片显示,音乐播放等等,音乐播放也不是什么特别难的代码,但是没什么实用性,我就没加了.另外,半周期数据ROM我觉得是个好设计思路,甚至可以简化成1/4周期,因为这样的设计可以节约存储空间。
现在一个周期只有4096个点,当精度要求提高,或者波形种类大幅增多以后,一半,或者1/4节省出来的存储空间就非常可观了,可以留出空间给那些需要更多ROM空间的模块。
我觉得,简单就是最好的。
所有的创新设计,其目的都应当是强大一个产品的功能,而不是是它看上去更炫。
一个电路设计,完成了它的功能以后,再加上若干工作指示灯,就可以了。
工作指示灯是绝对必须的。
在做成成品板子以后,如果你连电路的工作状态都不知道,出了问题,怎么查错?
就比如实验箱上的AD/DAPACK,上面两个LED是常亮的,一个左上角的电源灯,还有一个右下角的配置成功指示灯(在配置的过程中会熄灭)。
非常的实用。
我也曾经拆过一些成品电子产品的板子,除了那些给用户看的指示灯以外,在板子上还有若干个用于调试的指示灯,很实用。
至于那些花里胡哨的东西,我觉得就不必了吧。
花里胡哨的东西加多了只会让人有山寨的感觉,想当年山寨的名字刚出现的时候,就是因为花哨的东西太多,华而不实。
一切的设计都应当以实用为主。
5.遗憾之处。
这次相位测量没能做进最后的电路里不得不说是一大遗憾。
究其根本原因在于,时钟电路设计不合理!
我一共三个模块需要用到时钟,三角波,正弦波,以及正弦波反相。
这三个模块都是始终接着48M时钟在,一直工作,只不过每次只有两路送到DA芯片罢了。
如此高频的时钟振荡,很难保证他们之前不相互影响。
我还发现,三角波的频率如果和正弦波不一样的话,频率计也不准。
原因还是同时工作会有干扰。
所以,合理的设计应该是,需要工作的模块接时钟,不需要的不接。
我之前一直不把这个问题当回事,直到周四意识到干扰的严重性以后才匆忙写了个时钟切换模块,但是估计是代码写的不好,这个模块压根没工作,时间也来不及了,所以就直接交了备份上去验收了。
所以,对待高频振荡的时钟一定要慎之又慎!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- EDA 实验 报告 频率计 DDS