正弦信号发生器Word格式.docx
《正弦信号发生器Word格式.docx》由会员分享,可在线阅读,更多相关《正弦信号发生器Word格式.docx(27页珍藏版)》请在冰点文库上搜索。
ROM存放波形数据,有8位输出数据线,10位输入地址线。
ROM表的两个8位输出口,可以分别与两个高速D/A的8个输入端连接(本设计中采用D/AC0800),输出参考信号和可移相波形信号。
DDS数字电路部分完全集成在Alter公司的cycloneII系列FPGA中,利用FPGA丰富的逻辑资源来实现,通过键盘控制单片机向FPGA输入幅度控制值来调整幅度,显示部分由单片机来实现。
系统引入模块化的思想,采用自底向上的设计思路,将软件开发与硬件开发相结合。
整个系统可以分为四部分:
FPGA内部逻辑单元设计,模拟电路单元设计,编码键盘设计以及单片机显示单元设计。
2.FPGA内部逻辑设计
2.1累加器的设计
累加器是DDS电路工作的最关键部分,累加器的工作速度决定了输出波形的频率精度。
由f0min=fc/
知,累加器的位数决定了频率最小分辨率,设计中fc为FPGA工作频率经过定制的锁相环进行10倍频后的频率:
fc=20MHz*10=200MHz,根据设计需要将累加器位数设为32位,这样最小频率步进制为fmin=0.046566Hz。
2.2波形ROM表的设计
利用QuartusII中的MegaWizardPlug-InManager可以方便的生成大小任意大小和接口的ROM,而关键是如何将波形表初始化到其中去。
本设计采用的查表法所需函数表通过Excel的实现。
首先建立数学函数模型,例如在一个周期内,ωt的取值范围为0~2π,对应y=f(x)形式,则0<
x≤2π,即y=sinx(0<
x≤2π)。
RAM地址范围的大小取决于所要求的数据表精度,地址范围越大数据表越精确,但需要的存储空间越大。
在Excel表格中可以用下拉单元格的方式迅速生成地址,本设计中生成1024个数据的数据表,地址范围0——1024,即波形表中每种波形每周期取1024点。
输入公式“=SIN((A:
A/1024)*2*3.1415926)”,再利用下拉单元格的方式,得到各个地址单元所对应的正弦函数值。
以上得到的正弦函数表往往不能被D/A转换器直接利用,需要将其值映射到D/A转换器所能接受的数据空间内。
设计中所用D/A转换器为8位,其数据空间是0——255,可以利用公式“=(B:
B+1)*127.5”来映射数据,影射后的数据为小数,还须对其取整,输入公式“=INT(C:
C)”。
本设计中只需先建立波形表文件(mif文件),将Excel中的数复制进去即可得波形表。
部分波形数据如下:
在原理图中双击ROM调入波形表文件即将波形表中数据写入ROM中。
ROM的10位地址与累加器的输出的高10位数据相连,作为相位读取地址。
2.3调频模块(fm)的设计
(1)最高频率的设定
根据Nyquist采样定理,每周期最少有两个采样点,便可以还原出数字信号的波形,所以最高输出频率为fc/2(fc为采样频率),利用QuartusII中的MegaWizardPlug-InManager将FPGA的20M频率倍频成200M:
fmin=200000000/
=0.04656Hz频率控制字FSW由下式得出:
FSW=fo*
/200000000,实际中将FSW设为24位。
最小步进制设为1Hz,增加100Hz步进制,每个步进制有正负两个键,并且通过单片机即时显示当前频率值。
两个按键分别为控制相位每次加减一度,另外两个键控制幅度增减。
2.4调幅模块(AM)的设计
(1)调幅精度的设定
由于采用8位DAC0832来产生调幅电压,ΔV=Vref/256,由于实际要求为输出峰值1~5V可调,步进小于0.5V。
设计中幅度参考电压取9V,精度为0.035V,可直接将其作为步进电压值。
幅度控制字的输入同调频模块,采用幅度加减键来设定当前幅度值。
2.5双路移相模块的设计
双路移相输出是本设计的重点之一,采用FPGA设计DDS函数发生器可以方便的输出双路信号,而不必增加硬件成本。
在第一路信号的波形表地址的基础上加上相位增量,作为第二路信号的查表地址,由此实现移相输出。
在硬件实现时由于开发板上无输入数字键,所以仍然采用设定相位步进制的方法来实现移相,移相精度与波形表地址精度有关,本设计中的移相精度为:
Δφ=360°
/1024。
3、D/A输出模块的硬件电路设计设计
本模块采用DAC0832模块作为输出波形的幅度调节,连接至FPGA的调幅输出,将FPGA输出的相关幅度数据转换成相应的电压值作为DAC0800的参考电压。
DAC0800作为波形数据输出的D/A转换,转换后的波形信号电压经运放放大后输出。
具体电路结构如下图所示:
4、单片机及编码键盘系统模块
4.1单片机系统框图如下:
4.2编码键盘模块如下:
附件1单片机程序
#include<
reg52.h>
intrins.h>
#defineucharunsignedchar
#defineuintunsignedint
#defines_datP2//频控/相控
ucharcodedis2[]={'
0'
'
1'
2'
3'
4'
5'
6'
7'
8'
9'
};
//液晶显示数组
ucharzero,one,two,three,four,five,six;
sbitADR1=P3^0;
sbitADR2=P3^1;
sbitADR3=P3^2;
sbitADR4=P3^7;
sbitWR1=P3^3;
sbitRD1=P3^4;
sbitCLK=P3^5;
unsignedlongf1=2147;
//sendoutcontrolword
unsignedlongf2=2147;
unsignedlongp2=0;
sbitLCD_CS=P1^0;
sbitLCD_SID=P1^1;
sbitLCD_CLK=P1^2;
uintf_1=100,f_2=100,p=0;
//displaynum
unsignedlongfsw1=21474836,fsw2=21474836,phase=0;
//10000*controlword
ucharfc_1=1,fc_2=1;
//frequencycomparision
ucharref=128;
//votagereference
/**************************液晶程序*************************************************************/
voiddelayMs(uintm)
{uintz;
for(;
m!
=0;
m--)
for(z=500;
z>
0;
z--);
}
bitlcd_busy()
{
uinti;
bitflag;
//先产生连续5个'
LCD_CS=1;
for(i=0;
i<
5;
i++)
LCD_CLK=0;
LCD_SID=1;
LCD_CLK=1;
}
//再发送一个'
,表示读操作
//再发送一个'
表示写命令操作
LCD_SID=0;
,这是表示第一个字节结束
for(i=50;
i!
i--);
flag=0;
flag=LCD_SID;
LCD_CS=0;
returnflag;
voidwrite_command(unsignedcharcmd)
{
unsignedinti;
while(lcd_busy());
//再发送三个'
,表示写操作
3;
//下面发送具体指令,先发送高4位
4;
if(cmd&
0x80)
else
cmd<
<
=1;
//发送连续4个'
//下面发送指令的低4位
0x80)/////////////////////////////
}
voidwrite_data(uchardat)
unsignedchari;
表示写数据操作
//下面发送具体数据,先发送高4位
if(dat&
dat<
//下面发送数据的低4位
//结束
voidwrite_char(uchar*ch)
ch[i]!
='
\0'
;
write_data(ch[i]);
//////////////////////////////////////
voidlcd_init()
{
write_command(0x30);
//同一指令的动作不能同时改变DL和RE,需先改变DL再改变RE
50;
i++);
//
write_command(0x0c);
//01dcb设置显示状态,d=1整体显示ON,c=1游标与b=1游标位置反白ON01111
write_command(0x1c);
//游标设置,显示向右移动,游标跟着移动
write_command(0x01);
//清显示
delayMs(10);
voiddat_to_char(uinttemp)
one=temp/100000;
two=temp%100000/10000;
three=temp%100000%10000/1000;
four=temp%100000%10000%1000/100;
five=temp%100000%10000%1000%100/10;
six=temp%100000%10000%1000%100%10;
voiddisplay()
dat_to_char(f_1);
write_command(0x81);
write_char("
f1:
"
);
//write_data(dis2[one]);
write_data(dis2[two]);
write_data(dis2[three]);
write_data(dis2[four]);
write_data(dis2[five]);
write_data(dis2[six]);
Hz"
dat_to_char(f_2);
write_command(0x91);
f2:
write_command(0x89);
相差:
dat_to_char(p);
//write_data(dis2[two]);
//write_char("
度"
voidWritedata(unsignedlongdat)
RD1=0;
s_dat=dat;
delayMs
(1);
WR1=1;
CLK=1;
CLK=0;
WR1=0;
voidwrite_word()
ADR1=0;
ADR2=0;
ADR3=0;
ADR4=0;
Writedata(f1);
////writef11
ADR1=1;
Writedata((f1>
>
8));
//writef12
ADR2=1;
16));
//writef13
Writedata(f2);
//writef21
ADR3=1;
Writedata((f2>
////writef22
//writef23
Writedata(p2);
//writep21
Writedata((p2>
//writep22
ADR4=1;
Writedata(ref);
RD1=1;
voidmain()
{
uchartemp1;
lcd_init();
//write_command(0x80);
液晶显示"
while
(1)
{
P0=0XFF;
temp1=P0;
temp1=temp1&
0x0f;
if(temp1!
=0x00)
{
switch(temp1)
case14:
temp1=0;
ref=ref+1;
break;
case13:
ref=ref-1;
case12:
fc_2++;
f1=fc_2*f2;
f_1=fc_2*f_2;
phase=0;
p=0;
case11:
fc_1++;
f2=fc_1*f1;
f_2=fc_1*f_1;
//case11:
p2=p2-1422222;
p=p-50;
write_word();
//50°
//case10:
p2=p2+1422222;
p=p+50;
case10:
if((f_2==f_1)&
&
(p>
0)){phase=phase-28444;
p2=phase/10000;
p--;
}break;
case9:
if(f_2==f_1){phase=phase+28444;
p++;
//1°
case8:
fsw2=fsw2-21474836;
f_2=f_2-100;
f2=fsw2/10000;
//100hz
case7:
fsw2=fsw2+21474836;
f_2=f_2+100;
case6:
fsw2=fsw2-214748;
f_2=f_2-1;
//1Hz
f1=fsw2/10000;
break;
//1hz;
f---display;
temp---fswacc;
case5:
fsw2=fsw2+214748;
f_2=f_2+1;
f2=fsw2/10000;
case4:
fsw1=fsw1-21474836;
f_1=f_1-100;
f1=fsw1/10000;
case3:
fsw1=fsw1+21474836;
f_1=f_1+100;
case2:
fsw1