目录
开发环境:
FPGA: cyclone iii
软件:quartus ii13.1+modelsim,matlab2016b
语言:Verilog HDL
一、2FSK介绍
FSK是信息传输中使用得较早的一种调制方式,它的主要优点是:实现起来较容易,抗噪声与抗衰减的性能较好。国际电信联盟(ITU)建议在传输速率低于1200b/s时采用2FSK体制,其在中低速数据传输中得到了广泛的应用。所谓FSK就是用数字信号去调制载波的频率。
调制方法:2FSK可看作是两个不同载波频率的ASK已调信号之和。
解调方法:相干法和非相干法。
1、相干解调:
2、非相干解调
二、FPGA生成2FSK方法
如图所示,2FSK产生的方案,利用基带信号控制DA的ROM表,从而实现FSK调试。
1、正弦ROM表产生
下面详细讲解下如何生成ROM表。
正弦ROM表应该有这样的功能:输入时钟信号,输出幅度值(数字)。然后输出的幅度送给DA让其输出实际对应的模拟电压信号。
想要有这样的功能,首先正弦rom表中要存储正弦数值,以mif的形式导入到创建的rom IP核中;然后创建计数器使其根据时钟信号生成地址,对应为rom表中数据的存储位置。
要想生成正弦rom表,首先要明确正弦的表达为:,其三要素为幅度A,频率w和相位。幅度A在二进制中和位宽n有关 ,频率和一个周期的点数有关,相位这里先不考虑。
正弦ROM表里面存储的点数,是根据DA输出一点需要的频率和要输出的正弦频率来确定。
图中一个点的频率为f1,正弦波的频率为f2,正弦波一共有16个点,那么三个数之间的关系为f2=f1/16。这里f1也叫做采样率,也就是采样率/(一个周期的点数)=这个周期对应的频率。
这里我的DA输出频率为2M,我想输出的正弦波频率为4k和12.5k,那么需要rom表的点数为2000/4=300,和2000/12.5=160。
(1)生成mif文件
利用matlab生成mif文件,DA的位数为16位,单极性器件,因此这里的mif文件里面正弦波的数据位宽要为16位,无符号型。
这里需要注意的是信号的位宽为16位无符号数,那么可以表示的信号范围为0~2^16-1=65535,在设置信号的幅度A和直流分量的时候要保证不能溢出,比如当A=2^15,ADC=2^15的时候最大值为2^16会溢出。
F1=1; %信号的频率
P1=0;%信号初始相位
Fs=300;%采样频率
N=300;%采样点数为N
t=[0:1/Fs:(N-1)/Fs];%采样时刻
ADC=2^15-1 ;%直流分量
A=2^15-1;%信号幅度
s=A*sin(2*pi*F1*t + pi*P1/180)+ADC;%生成信号
plot(s);%绘制图形
fild = fopen('d:/DA_4k.mif','wt');%创建mif文件
%写入mif文件文件头
fprintf(fild, '%s\n','WIDTH=16;');%位宽
fprintf(fild, '%s\n\n','DEPTH=300;');%深度
fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;');%地址格式
fprintf(fild, '%s\n\n','DATA_RADIX=UNS;');%数据格式
fprintf(fild, '%s\t','CONTENT');%地址
fprintf(fild, '%s\n','BEGIN');%
for i = 1:N
s2(i) = round(s(i)); %对小数四舍五入以取整
if s2(i)<0 %强制将负1置0,
s2(i) = 0;
end
fprintf(fild, '\t%g\t',i-1);%地址,从0开始编码
fprintf(fild, '%s\t',':');
fprintf(fild, '%d',s2(i));
fprintf(fild, '%s\n',';');
end
fprintf(fild, '%s\n','END;');%地址
(2)生成rom IP核并导入mif文件
打开工具栏的IP核生成助手
创建一个新的自定义的宏文件
选择memory里面的ROM,然后文件输出位置要在project文件下,直接在后面命名就可以。
宽度wide指的是mif中的位宽,这里用的是16位,数量我们用的是300个,不能少于这个数量,因此这里选择用512个。
保持默认Next
选择 mif文件,要注意mif文件也要拷贝放到工程目录下,不然会造成在后面modelsim仿真的时候出现没有波形的奇怪错误(这个bug,调了半天)。
保持默认Next
勾选inst初始化调用模板。最后点击finish。
在project下打开inst文件,复制到工程中就可以调用rom IP核。
sin_rom sin_rom_inst (
.address ( address_sig ),
.clock ( clock_sig ),
.q ( q_sig )
);
(3)生成计数器
计数器应该有这样的功能:
1、向上计数和向下计数(updown);
2、计数开始数据(基数)输入(data);
3、计数结果输出(q);
4、进位输入(carry in);
5、进位输出(carry out);
6、载入基数(load);
7、时钟输入(clk);
我们想实现300个地址的寻址计数,那需要设置:计数开始值为300,向下计数,当300个初始值计完,产生进位cout这个信号给laod,让其再次载入初始值300,进入下一轮的计数。
下面是具体的操作过程:
选择数学运算中的参量化模拟库(Library of parameterized modules)LPM_COUNTER,然后命名
数据位宽选择9位的,因为是300个数,至少需要9位(2^9-1=511)来表示。选择向下计数模式。
选择进入输出。和load配合保证下一轮的计数。
选择同步load
保持默认,Next下一步。
选中conter_inst。
(4)计数器和rom整合
module DAROM_4k(
clk,
sinromout_A,
);
input clk;
output sinromout_A;
wire [15:0] sinromout_A;
wire cout_sig;
wire [8:0]addr_A;
conter conter_inst (
.clock ( clk ),
.data ( 9'd499),
.sload ( cout_sig ),
.cout (cout_sig),
.q ( addr_A)
);
sin_rom sin_rom_inst
(
.clock(clk),
.address(addr_A),
.q(sinromout_A)
);
endmodule
2、数字基带控制正弦ROM表
基带信号作为判断的依据来控制正弦rom1和rom2的输出,这里使用assign语句来实现。
assign DA_SINROM=(baseband_data==1)?DAROM_12k5:DAROM_4k;
3、Modelsim仿真验证
点击processing-start-start Test Bench Template Writer自动创建test Bench文件
生成的文件为project/simulation/modelsim下的.vt文件,打开文件把该文件名修改成和顶层文件相同的名字。
根据硬件实际情况,添加需要的时钟和基带信号。
点击Assignments-Settings,进入仿真设置界面,配置modelsim相关文件。
进入simulation界面,更改配置入图中所示,然后点击Test Benches。
选择新建,然后点击图中file name,在project/simulation/modelsim下选择生成的vt文件。
然后把文件名字复制一下,粘贴到Test bench name,再点击Add。
点击OK
点击OK
点击RTL仿真。
生成了仿真波形图,波形会频率会随着基带信号发生变化,实现调相功能。--成功
想生成上图的正弦波形,右击波形的左侧,选择Format-Analog(custom),根据自己的数据大小修改下最大值和最小值。
来源:oschina
链接:https://my.oschina.net/u/4323830/blog/4732164